2005-02-05 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-string-util.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-string-util.c Would be in dbus-string.c, but not used in libdbus
3  * 
4  * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-string.h"
26 #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1
27 #include "dbus-string-private.h"
28
29 /**
30  * @addtogroup DBusString
31  * @{
32  */
33
34 /**
35  * Copies the contents of a DBusString into a different
36  * buffer. The resulting buffer will be nul-terminated.
37  * 
38  * @param str a string
39  * @param buffer a C buffer to copy data to
40  * @param avail_len maximum length of C buffer
41  */
42 void
43 _dbus_string_copy_to_buffer (const DBusString  *str,
44                              char              *buffer,
45                              int                avail_len)
46 {
47   int copy_len;
48   DBUS_CONST_STRING_PREAMBLE (str);
49
50   _dbus_assert (avail_len >= 0);
51
52   copy_len = MIN (avail_len, real->len+1);
53   memcpy (buffer, real->str, copy_len);
54   if (avail_len > 0 && avail_len == copy_len)
55     buffer[avail_len-1] = '\0';
56 }
57
58 /**
59  * Returns whether a string ends with the given suffix
60  *
61  * @todo memcmp might make this faster.
62  * 
63  * @param a the string
64  * @param c_str the C-style string
65  * @returns #TRUE if the string ends with the suffix
66  */
67 dbus_bool_t
68 _dbus_string_ends_with_c_str (const DBusString *a,
69                               const char       *c_str)
70 {
71   const unsigned char *ap;
72   const unsigned char *bp;
73   const unsigned char *a_end;
74   unsigned long c_str_len;
75   const DBusRealString *real_a = (const DBusRealString*) a;
76   DBUS_GENERIC_STRING_PREAMBLE (real_a);
77   _dbus_assert (c_str != NULL);
78   
79   c_str_len = strlen (c_str);
80   if (((unsigned long)real_a->len) < c_str_len)
81     return FALSE;
82   
83   ap = real_a->str + (real_a->len - c_str_len);
84   bp = (const unsigned char*) c_str;
85   a_end = real_a->str + real_a->len;
86   while (ap != a_end)
87     {
88       if (*ap != *bp)
89         return FALSE;
90       
91       ++ap;
92       ++bp;
93     }
94
95   _dbus_assert (*ap == '\0');
96   _dbus_assert (*bp == '\0');
97   
98   return TRUE;
99 }
100
101 /**
102  * Find the given byte scanning backward from the given start.
103  * Sets *found to -1 if the byte is not found.
104  *
105  * @param str the string
106  * @param start the place to start scanning (will not find the byte at this point)
107  * @param byte the byte to find
108  * @param found return location for where it was found
109  * @returns #TRUE if found
110  */
111 dbus_bool_t
112 _dbus_string_find_byte_backward (const DBusString  *str,
113                                  int                start,
114                                  unsigned char      byte,
115                                  int               *found)
116 {
117   int i;
118   DBUS_CONST_STRING_PREAMBLE (str);
119   _dbus_assert (start <= real->len);
120   _dbus_assert (start >= 0);
121   _dbus_assert (found != NULL);
122
123   i = start - 1;
124   while (i >= 0)
125     {
126       if (real->str[i] == byte)
127         break;
128       
129       --i;
130     }
131
132   if (found)
133     *found = i;
134
135   return i >= 0;
136 }
137
138 /**
139  * Skips whitespace from start, storing the first non-whitespace in *end.
140  * (whitespace is space, tab, newline, CR).
141  *
142  * @param str the string
143  * @param start where to start
144  * @param end where to store the first non-whitespace byte index
145  */
146 void
147 _dbus_string_skip_white (const DBusString *str,
148                          int               start,
149                          int              *end)
150 {
151   int i;
152   DBUS_CONST_STRING_PREAMBLE (str);
153   _dbus_assert (start <= real->len);
154   _dbus_assert (start >= 0);
155   
156   i = start;
157   while (i < real->len)
158     {
159       if (!(real->str[i] == ' ' ||
160             real->str[i] == '\n' ||
161             real->str[i] == '\r' ||
162             real->str[i] == '\t'))
163         break;
164       
165       ++i;
166     }
167
168   _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
169                                     real->str[i] == '\t'));
170   
171   if (end)
172     *end = i;
173 }
174
175 /** @} */
176
177 #ifdef DBUS_BUILD_TESTS
178 #include "dbus-test.h"
179 #include <stdio.h>
180
181 static void
182 test_max_len (DBusString *str,
183               int         max_len)
184 {
185   if (max_len > 0)
186     {
187       if (!_dbus_string_set_length (str, max_len - 1))
188         _dbus_assert_not_reached ("setting len to one less than max should have worked");
189     }
190
191   if (!_dbus_string_set_length (str, max_len))
192     _dbus_assert_not_reached ("setting len to max len should have worked");
193
194   if (_dbus_string_set_length (str, max_len + 1))
195     _dbus_assert_not_reached ("setting len to one more than max len should not have worked");
196
197   if (!_dbus_string_set_length (str, 0))
198     _dbus_assert_not_reached ("setting len to zero should have worked");
199 }
200
201 static void
202 test_hex_roundtrip (const unsigned char *data,
203                     int                  len)
204 {
205   DBusString orig;
206   DBusString encoded;
207   DBusString decoded;
208   int end;
209
210   if (len < 0)
211     len = strlen (data);
212   
213   if (!_dbus_string_init (&orig))
214     _dbus_assert_not_reached ("could not init string");
215
216   if (!_dbus_string_init (&encoded))
217     _dbus_assert_not_reached ("could not init string");
218   
219   if (!_dbus_string_init (&decoded))
220     _dbus_assert_not_reached ("could not init string");
221
222   if (!_dbus_string_append_len (&orig, data, len))
223     _dbus_assert_not_reached ("couldn't append orig data");
224
225   if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0))
226     _dbus_assert_not_reached ("could not encode");
227
228   if (!_dbus_string_hex_decode (&encoded, 0, &end, &decoded, 0))
229     _dbus_assert_not_reached ("could not decode");
230     
231   _dbus_assert (_dbus_string_get_length (&encoded) == end);
232
233   if (!_dbus_string_equal (&orig, &decoded))
234     {
235       const char *s;
236       
237       printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n",
238               _dbus_string_get_length (&orig),
239               _dbus_string_get_length (&encoded),
240               _dbus_string_get_length (&decoded));
241       printf ("Original: %s\n", data);
242       s = _dbus_string_get_const_data (&decoded);
243       printf ("Decoded: %s\n", s);
244       _dbus_assert_not_reached ("original string not the same as string decoded from hex");
245     }
246   
247   _dbus_string_free (&orig);
248   _dbus_string_free (&encoded);
249   _dbus_string_free (&decoded);  
250 }
251
252 typedef void (* TestRoundtripFunc) (const unsigned char *data,
253                                     int                  len);
254 static void
255 test_roundtrips (TestRoundtripFunc func)
256 {
257   (* func) ("Hello this is a string\n", -1);
258   (* func) ("Hello this is a string\n1", -1);
259   (* func) ("Hello this is a string\n12", -1);
260   (* func) ("Hello this is a string\n123", -1);
261   (* func) ("Hello this is a string\n1234", -1);
262   (* func) ("Hello this is a string\n12345", -1);
263   (* func) ("", 0);
264   (* func) ("1", 1);
265   (* func) ("12", 2);
266   (* func) ("123", 3);
267   (* func) ("1234", 4);
268   (* func) ("12345", 5);
269   (* func) ("", 1);
270   (* func) ("1", 2);
271   (* func) ("12", 3);
272   (* func) ("123", 4);
273   (* func) ("1234", 5);
274   (* func) ("12345", 6);
275   {
276     unsigned char buf[512];
277     int i;
278     
279     i = 0;
280     while (i < _DBUS_N_ELEMENTS (buf))
281       {
282         buf[i] = i;
283         ++i;
284       }
285     i = 0;
286     while (i < _DBUS_N_ELEMENTS (buf))
287       {
288         (* func) (buf, i);
289         ++i;
290       }
291   }
292 }
293
294 #ifdef DBUS_BUILD_TESTS
295 /* The max length thing is sort of a historical artifact
296  * from a feature that turned out to be dumb; perhaps
297  * we should purge it entirely. The problem with
298  * the feature is that it looks like memory allocation
299  * failure, but is not a transient or resolvable failure.
300  */
301 static void
302 set_max_length (DBusString *str,
303                 int         max_length)
304 {
305   DBusRealString *real;
306   
307   real = (DBusRealString*) str;
308
309   real->max_length = max_length;
310 }
311 #endif /* DBUS_BUILD_TESTS */
312
313 /**
314  * @ingroup DBusStringInternals
315  * Unit test for DBusString.
316  *
317  * @todo Need to write tests for _dbus_string_copy() and
318  * _dbus_string_move() moving to/from each of start/middle/end of a
319  * string. Also need tests for _dbus_string_move_len ()
320  * 
321  * @returns #TRUE on success.
322  */
323 dbus_bool_t
324 _dbus_string_test (void)
325 {
326   DBusString str;
327   DBusString other;
328   int i, end;
329   long v;
330   double d;
331   int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 };
332   char *s;
333   dbus_unichar_t ch;
334   
335   i = 0;
336   while (i < _DBUS_N_ELEMENTS (lens))
337     {
338       if (!_dbus_string_init (&str))
339         _dbus_assert_not_reached ("failed to init string");
340
341       set_max_length (&str, lens[i]);
342       
343       test_max_len (&str, lens[i]);
344       _dbus_string_free (&str);
345
346       ++i;
347     }
348
349   /* Test shortening and setting length */
350   i = 0;
351   while (i < _DBUS_N_ELEMENTS (lens))
352     {
353       int j;
354       
355       if (!_dbus_string_init (&str))
356         _dbus_assert_not_reached ("failed to init string");
357
358       set_max_length (&str, lens[i]);
359       
360       if (!_dbus_string_set_length (&str, lens[i]))
361         _dbus_assert_not_reached ("failed to set string length");
362
363       j = lens[i];
364       while (j > 0)
365         {
366           _dbus_assert (_dbus_string_get_length (&str) == j);
367           if (j > 0)
368             {
369               _dbus_string_shorten (&str, 1);
370               _dbus_assert (_dbus_string_get_length (&str) == (j - 1));
371             }
372           --j;
373         }
374       
375       _dbus_string_free (&str);
376
377       ++i;
378     }
379
380   /* Test equality */
381   if (!_dbus_string_init (&str))
382     _dbus_assert_not_reached ("oom");
383
384   if (!_dbus_string_append (&str, "Hello World"))
385     _dbus_assert_not_reached ("oom");
386
387   _dbus_string_init_const (&other, "H");
388   _dbus_assert (_dbus_string_equal_substring (&str, 0, 1, &other, 0));
389   _dbus_assert (_dbus_string_equal_substring (&str, 1, 0, &other, 1));
390   _dbus_string_init_const (&other, "Hello");
391   _dbus_assert (_dbus_string_equal_substring (&str, 0, 5, &other, 0));
392   _dbus_assert (_dbus_string_equal_substring (&str, 1, 4, &other, 1));
393   _dbus_assert (_dbus_string_equal_substring (&str, 2, 3, &other, 2));
394   _dbus_assert (_dbus_string_equal_substring (&str, 3, 2, &other, 3));
395   _dbus_assert (_dbus_string_equal_substring (&str, 4, 1, &other, 4));
396   _dbus_assert (_dbus_string_equal_substring (&str, 5, 0, &other, 5));
397
398   _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 0));
399   _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 1));
400   _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 2));
401   _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 3));
402   _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 4));
403   _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 5));
404
405   
406   _dbus_string_init_const (&other, "World");
407   _dbus_assert (_dbus_string_equal_substring (&str, 6,  5, &other, 0));
408   _dbus_assert (_dbus_string_equal_substring (&str, 7,  4, &other, 1));
409   _dbus_assert (_dbus_string_equal_substring (&str, 8,  3, &other, 2));
410   _dbus_assert (_dbus_string_equal_substring (&str, 9,  2, &other, 3));
411   _dbus_assert (_dbus_string_equal_substring (&str, 10, 1, &other, 4));
412   _dbus_assert (_dbus_string_equal_substring (&str, 11, 0, &other, 5));
413
414   _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 6));
415   _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 7));
416   _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 8));
417   _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 9));
418   _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 10));
419   _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 11));
420   
421   _dbus_string_free (&str);
422   
423   /* Test appending data */
424   if (!_dbus_string_init (&str))
425     _dbus_assert_not_reached ("failed to init string");
426
427   i = 0;
428   while (i < 10)
429     {
430       if (!_dbus_string_append (&str, "a"))
431         _dbus_assert_not_reached ("failed to append string to string\n");
432
433       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1);
434
435       if (!_dbus_string_append_byte (&str, 'b'))
436         _dbus_assert_not_reached ("failed to append byte to string\n");
437
438       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2);
439                     
440       ++i;
441     }
442
443   _dbus_string_free (&str);
444
445   /* Check steal_data */
446   
447   if (!_dbus_string_init (&str))
448     _dbus_assert_not_reached ("failed to init string");
449
450   if (!_dbus_string_append (&str, "Hello World"))
451     _dbus_assert_not_reached ("could not append to string");
452
453   i = _dbus_string_get_length (&str);
454   
455   if (!_dbus_string_steal_data (&str, &s))
456     _dbus_assert_not_reached ("failed to steal data");
457
458   _dbus_assert (_dbus_string_get_length (&str) == 0);
459   _dbus_assert (((int)strlen (s)) == i);
460
461   dbus_free (s);
462
463   /* Check move */
464   
465   if (!_dbus_string_append (&str, "Hello World"))
466     _dbus_assert_not_reached ("could not append to string");
467
468   i = _dbus_string_get_length (&str);
469
470   if (!_dbus_string_init (&other))
471     _dbus_assert_not_reached ("could not init string");
472   
473   if (!_dbus_string_move (&str, 0, &other, 0))
474     _dbus_assert_not_reached ("could not move");
475
476   _dbus_assert (_dbus_string_get_length (&str) == 0);
477   _dbus_assert (_dbus_string_get_length (&other) == i);
478
479   if (!_dbus_string_append (&str, "Hello World"))
480     _dbus_assert_not_reached ("could not append to string");
481   
482   if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other)))
483     _dbus_assert_not_reached ("could not move");
484
485   _dbus_assert (_dbus_string_get_length (&str) == 0);
486   _dbus_assert (_dbus_string_get_length (&other) == i * 2);
487
488     if (!_dbus_string_append (&str, "Hello World"))
489     _dbus_assert_not_reached ("could not append to string");
490   
491   if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2))
492     _dbus_assert_not_reached ("could not move");
493
494   _dbus_assert (_dbus_string_get_length (&str) == 0);
495   _dbus_assert (_dbus_string_get_length (&other) == i * 3);
496   
497   _dbus_string_free (&other);
498
499   /* Check copy */
500   
501   if (!_dbus_string_append (&str, "Hello World"))
502     _dbus_assert_not_reached ("could not append to string");
503
504   i = _dbus_string_get_length (&str);
505   
506   if (!_dbus_string_init (&other))
507     _dbus_assert_not_reached ("could not init string");
508   
509   if (!_dbus_string_copy (&str, 0, &other, 0))
510     _dbus_assert_not_reached ("could not copy");
511
512   _dbus_assert (_dbus_string_get_length (&str) == i);
513   _dbus_assert (_dbus_string_get_length (&other) == i);
514
515   if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other)))
516     _dbus_assert_not_reached ("could not copy");
517
518   _dbus_assert (_dbus_string_get_length (&str) == i);
519   _dbus_assert (_dbus_string_get_length (&other) == i * 2);
520   _dbus_assert (_dbus_string_equal_c_str (&other,
521                                           "Hello WorldHello World"));
522
523   if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2))
524     _dbus_assert_not_reached ("could not copy");
525
526   _dbus_assert (_dbus_string_get_length (&str) == i);
527   _dbus_assert (_dbus_string_get_length (&other) == i * 3);
528   _dbus_assert (_dbus_string_equal_c_str (&other,
529                                           "Hello WorldHello WorldHello World"));
530   
531   _dbus_string_free (&str);
532   _dbus_string_free (&other);
533
534   /* Check replace */
535
536   if (!_dbus_string_init (&str))
537     _dbus_assert_not_reached ("failed to init string");
538   
539   if (!_dbus_string_append (&str, "Hello World"))
540     _dbus_assert_not_reached ("could not append to string");
541
542   i = _dbus_string_get_length (&str);
543   
544   if (!_dbus_string_init (&other))
545     _dbus_assert_not_reached ("could not init string");
546   
547   if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
548                                  &other, 0, _dbus_string_get_length (&other)))
549     _dbus_assert_not_reached ("could not replace");
550
551   _dbus_assert (_dbus_string_get_length (&str) == i);
552   _dbus_assert (_dbus_string_get_length (&other) == i);
553   _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World"));
554   
555   if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
556                                  &other, 5, 1))
557     _dbus_assert_not_reached ("could not replace center space");
558
559   _dbus_assert (_dbus_string_get_length (&str) == i);
560   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
561   _dbus_assert (_dbus_string_equal_c_str (&other,
562                                           "HelloHello WorldWorld"));
563
564   
565   if (!_dbus_string_replace_len (&str, 1, 1,
566                                  &other,
567                                  _dbus_string_get_length (&other) - 1,
568                                  1))
569     _dbus_assert_not_reached ("could not replace end character");
570   
571   _dbus_assert (_dbus_string_get_length (&str) == i);
572   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
573   _dbus_assert (_dbus_string_equal_c_str (&other,
574                                           "HelloHello WorldWorle"));
575   
576   _dbus_string_free (&str);
577   _dbus_string_free (&other);
578   
579   /* Check append/get unichar */
580   
581   if (!_dbus_string_init (&str))
582     _dbus_assert_not_reached ("failed to init string");
583
584   ch = 0;
585   if (!_dbus_string_append_unichar (&str, 0xfffc))
586     _dbus_assert_not_reached ("failed to append unichar");
587
588   _dbus_string_get_unichar (&str, 0, &ch, &i);
589
590   _dbus_assert (ch == 0xfffc);
591   _dbus_assert (i == _dbus_string_get_length (&str));
592
593   _dbus_string_free (&str);
594
595   /* Check insert/set/get byte */
596   
597   if (!_dbus_string_init (&str))
598     _dbus_assert_not_reached ("failed to init string");
599
600   if (!_dbus_string_append (&str, "Hello"))
601     _dbus_assert_not_reached ("failed to append Hello");
602
603   _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H');
604   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e');
605   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l');
606   _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l');
607   _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o');
608
609   _dbus_string_set_byte (&str, 1, 'q');
610   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q');
611
612   if (!_dbus_string_insert_bytes (&str, 0, 1, 255))
613     _dbus_assert_not_reached ("can't insert byte");
614
615   if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z'))
616     _dbus_assert_not_reached ("can't insert byte");
617
618   if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W'))
619     _dbus_assert_not_reached ("can't insert byte");
620   
621   _dbus_assert (_dbus_string_get_byte (&str, 0) == 255);
622   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H');
623   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z');
624   _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z');
625   _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z');
626   _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z');
627   _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q');
628   _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l');
629   _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l');
630   _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o');
631   _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W');
632
633   _dbus_string_free (&str);
634   
635   /* Check append/parse int/double */
636   
637   if (!_dbus_string_init (&str))
638     _dbus_assert_not_reached ("failed to init string");
639
640   if (!_dbus_string_append_int (&str, 27))
641     _dbus_assert_not_reached ("failed to append int");
642
643   i = _dbus_string_get_length (&str);
644
645   if (!_dbus_string_parse_int (&str, 0, &v, &end))
646     _dbus_assert_not_reached ("failed to parse int");
647
648   _dbus_assert (v == 27);
649   _dbus_assert (end == i);
650
651   _dbus_string_free (&str);
652   
653   if (!_dbus_string_init (&str))
654     _dbus_assert_not_reached ("failed to init string");
655   
656   if (!_dbus_string_append_double (&str, 50.3))
657     _dbus_assert_not_reached ("failed to append float");
658
659   i = _dbus_string_get_length (&str);
660
661   if (!_dbus_string_parse_double (&str, 0, &d, &end))
662     _dbus_assert_not_reached ("failed to parse float");
663
664   _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6));
665   _dbus_assert (end == i);
666
667   _dbus_string_free (&str);
668
669   /* Test find */
670   if (!_dbus_string_init (&str))
671     _dbus_assert_not_reached ("failed to init string");
672
673   if (!_dbus_string_append (&str, "Hello"))
674     _dbus_assert_not_reached ("couldn't append to string");
675   
676   if (!_dbus_string_find (&str, 0, "He", &i))
677     _dbus_assert_not_reached ("didn't find 'He'");
678   _dbus_assert (i == 0);
679
680   if (!_dbus_string_find (&str, 0, "Hello", &i))
681     _dbus_assert_not_reached ("didn't find 'Hello'");
682   _dbus_assert (i == 0);
683   
684   if (!_dbus_string_find (&str, 0, "ello", &i))
685     _dbus_assert_not_reached ("didn't find 'ello'");
686   _dbus_assert (i == 1);
687
688   if (!_dbus_string_find (&str, 0, "lo", &i))
689     _dbus_assert_not_reached ("didn't find 'lo'");
690   _dbus_assert (i == 3);
691
692   if (!_dbus_string_find (&str, 2, "lo", &i))
693     _dbus_assert_not_reached ("didn't find 'lo'");
694   _dbus_assert (i == 3);
695
696   if (_dbus_string_find (&str, 4, "lo", &i))
697     _dbus_assert_not_reached ("did find 'lo'");
698   
699   if (!_dbus_string_find (&str, 0, "l", &i))
700     _dbus_assert_not_reached ("didn't find 'l'");
701   _dbus_assert (i == 2);
702
703   if (!_dbus_string_find (&str, 0, "H", &i))
704     _dbus_assert_not_reached ("didn't find 'H'");
705   _dbus_assert (i == 0);
706
707   if (!_dbus_string_find (&str, 0, "", &i))
708     _dbus_assert_not_reached ("didn't find ''");
709   _dbus_assert (i == 0);
710   
711   if (_dbus_string_find (&str, 0, "Hello!", NULL))
712     _dbus_assert_not_reached ("Did find 'Hello!'");
713
714   if (_dbus_string_find (&str, 0, "Oh, Hello", NULL))
715     _dbus_assert_not_reached ("Did find 'Oh, Hello'");
716   
717   if (_dbus_string_find (&str, 0, "ill", NULL))
718     _dbus_assert_not_reached ("Did find 'ill'");
719
720   if (_dbus_string_find (&str, 0, "q", NULL))
721     _dbus_assert_not_reached ("Did find 'q'");
722
723   if (!_dbus_string_find_to (&str, 0, 2, "He", NULL))
724     _dbus_assert_not_reached ("Didn't find 'He'");
725
726   if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL))
727     _dbus_assert_not_reached ("Did find 'Hello'");
728
729   if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'H', &i))
730     _dbus_assert_not_reached ("Did not find 'H'");
731   _dbus_assert (i == 0);
732
733   if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'o', &i))
734     _dbus_assert_not_reached ("Did not find 'o'");
735   _dbus_assert (i == _dbus_string_get_length (&str) - 1);
736
737   if (_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str) - 1, 'o', &i))
738     _dbus_assert_not_reached ("Did find 'o'");
739   _dbus_assert (i == -1);
740
741   if (_dbus_string_find_byte_backward (&str, 1, 'e', &i))
742     _dbus_assert_not_reached ("Did find 'e'");
743   _dbus_assert (i == -1);
744
745   if (!_dbus_string_find_byte_backward (&str, 2, 'e', &i))
746     _dbus_assert_not_reached ("Didn't find 'e'");
747   _dbus_assert (i == 1);
748   
749   _dbus_string_free (&str);
750
751   /* Hex encoding */
752   _dbus_string_init_const (&str, "cafebabe, this is a bogus hex string");
753   if (!_dbus_string_init (&other))
754     _dbus_assert_not_reached ("could not init string");
755
756   if (!_dbus_string_hex_decode (&str, 0, &end, &other, 0))
757     _dbus_assert_not_reached ("deccoded bogus hex string with no error");
758
759   _dbus_assert (end == 8);
760
761   _dbus_string_free (&other);
762
763   test_roundtrips (test_hex_roundtrip);
764   
765   _dbus_string_free (&str);
766   
767   return TRUE;
768 }
769
770 #endif /* DBUS_BUILD_TESTS */