2003-10-20 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-string.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-string.c String utility class (internal to D-BUS implementation)
3  * 
4  * Copyright (C) 2002, 2003 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
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 /* we allow a system header here, for speed/convenience */
27 #include <string.h>
28 /* for vsnprintf */
29 #include <stdio.h>
30 #include "dbus-marshal.h"
31 #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1
32 #include "dbus-string-private.h"
33 #include "dbus-protocol.h"
34
35 /**
36  * @defgroup DBusString string class
37  * @ingroup  DBusInternals
38  * @brief DBusString data structure
39  *
40  * Types and functions related to DBusString. DBusString is intended
41  * to be a string class that makes it hard to mess up security issues
42  * (and just in general harder to write buggy code).  It should be
43  * used (or extended and then used) rather than the libc stuff in
44  * string.h.  The string class is a bit inconvenient at spots because
45  * it handles out-of-memory failures and tries to be extra-robust.
46  * 
47  * A DBusString has a maximum length set at initialization time; this
48  * can be used to ensure that a buffer doesn't get too big.  The
49  * _dbus_string_lengthen() method checks for overflow, and for max
50  * length being exceeded.
51  * 
52  * Try to avoid conversion to a plain C string, i.e. add methods on
53  * the string object instead, only convert to C string when passing
54  * things out to the public API. In particular, no sprintf, strcpy,
55  * strcat, any of that should be used. The GString feature of
56  * accepting negative numbers for "length of string" is also absent,
57  * because it could keep us from detecting bogus huge lengths. i.e. if
58  * we passed in some bogus huge length it would be taken to mean
59  * "current length of string" instead of "broken crack"
60  */
61
62 /**
63  * @defgroup DBusStringInternals DBusString implementation details
64  * @ingroup  DBusInternals
65  * @brief DBusString implementation details
66  *
67  * The guts of DBusString.
68  *
69  * @{
70  */
71
72 /**
73  * We allocate 1 byte for nul termination, plus 7 bytes for possible
74  * align_offset, so we always need 8 bytes on top of the string's
75  * length to be in the allocated block.
76  */
77 #define ALLOCATION_PADDING 8
78
79 /**
80  * This is the maximum max length (and thus also the maximum length)
81  * of a DBusString
82  */
83 #define MAX_MAX_LENGTH (_DBUS_INT_MAX - ALLOCATION_PADDING)
84
85 /**
86  * Checks a bunch of assertions about a string object
87  *
88  * @param real the DBusRealString
89  */
90 #define DBUS_GENERIC_STRING_PREAMBLE(real) _dbus_assert ((real) != NULL); _dbus_assert (!(real)->invalid); _dbus_assert ((real)->len >= 0); _dbus_assert ((real)->allocated >= 0); _dbus_assert ((real)->max_length >= 0); _dbus_assert ((real)->len <= ((real)->allocated - ALLOCATION_PADDING)); _dbus_assert ((real)->len <= (real)->max_length)
91
92 /**
93  * Checks assertions about a string object that needs to be
94  * modifiable - may not be locked or const. Also declares
95  * the "real" variable pointing to DBusRealString. 
96  * @param str the string
97  */
98 #define DBUS_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \
99   DBUS_GENERIC_STRING_PREAMBLE (real);                                          \
100   _dbus_assert (!(real)->constant);                                             \
101   _dbus_assert (!(real)->locked)
102
103 /**
104  * Checks assertions about a string object that may be locked but
105  * can't be const. i.e. a string object that we can free.  Also
106  * declares the "real" variable pointing to DBusRealString.
107  *
108  * @param str the string
109  */
110 #define DBUS_LOCKED_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \
111   DBUS_GENERIC_STRING_PREAMBLE (real);                                                 \
112   _dbus_assert (!(real)->constant)
113
114 /**
115  * Checks assertions about a string that may be const or locked.  Also
116  * declares the "real" variable pointing to DBusRealString.
117  * @param str the string.
118  */
119 #define DBUS_CONST_STRING_PREAMBLE(str) const DBusRealString *real = (DBusRealString*) str; \
120   DBUS_GENERIC_STRING_PREAMBLE (real)
121
122 /** @} */
123
124 /**
125  * @addtogroup DBusString
126  * @{
127  */
128
129 static void
130 fixup_alignment (DBusRealString *real)
131 {
132   char *aligned;
133   char *real_block;
134   unsigned int old_align_offset;
135
136   /* we have to have extra space in real->allocated for the align offset and nul byte */
137   _dbus_assert (real->len <= real->allocated - ALLOCATION_PADDING);
138   
139   old_align_offset = real->align_offset;
140   real_block = real->str - old_align_offset;
141   
142   aligned = _DBUS_ALIGN_ADDRESS (real_block, 8);
143
144   real->align_offset = aligned - real_block;
145   real->str = aligned;
146   
147   if (old_align_offset != real->align_offset)
148     {
149       /* Here comes the suck */
150       memmove (real_block + real->align_offset,
151                real_block + old_align_offset,
152                real->len + 1);
153     }
154
155   _dbus_assert (real->align_offset < 8);
156   _dbus_assert (_DBUS_ALIGN_ADDRESS (real->str, 8) == real->str);
157 }
158
159 static void
160 undo_alignment (DBusRealString *real)
161 {
162   if (real->align_offset != 0)
163     {
164       memmove (real->str - real->align_offset,
165                real->str,
166                real->len + 1);
167
168       real->str = real->str - real->align_offset;
169       real->align_offset = 0;
170     }
171 }
172
173 /**
174  * Initializes a string that can be up to the given allocation size
175  * before it has to realloc. The string starts life with zero length.
176  * The string must eventually be freed with _dbus_string_free().
177  * 
178  * @param str memory to hold the string
179  * @param allocate_size amount to preallocate
180  * @returns #TRUE on success, #FALSE if no memory
181  */
182 dbus_bool_t
183 _dbus_string_init_preallocated (DBusString *str,
184                                 int         allocate_size)
185 {
186   DBusRealString *real;
187   
188   _dbus_assert (str != NULL);
189
190   _dbus_assert (sizeof (DBusString) == sizeof (DBusRealString));
191   
192   real = (DBusRealString*) str;
193
194   /* It's very important not to touch anything
195    * other than real->str if we're going to fail,
196    * since we also use this function to reset
197    * an existing string, e.g. in _dbus_string_steal_data()
198    */
199   
200   real->str = dbus_malloc (ALLOCATION_PADDING + allocate_size);
201   if (real->str == NULL)
202     return FALSE;  
203   
204   real->allocated = ALLOCATION_PADDING + allocate_size;
205   real->len = 0;
206   real->str[real->len] = '\0';
207   
208   real->max_length = MAX_MAX_LENGTH;
209   real->constant = FALSE;
210   real->locked = FALSE;
211   real->invalid = FALSE;
212   real->align_offset = 0;
213   
214   fixup_alignment (real);
215   
216   return TRUE;
217 }
218
219 /**
220  * Initializes a string. The string starts life with zero length.  The
221  * string must eventually be freed with _dbus_string_free().
222  * 
223  * @param str memory to hold the string
224  * @returns #TRUE on success, #FALSE if no memory
225  */
226 dbus_bool_t
227 _dbus_string_init (DBusString *str)
228 {
229   return _dbus_string_init_preallocated (str, 0);
230 }
231
232 /* The max length thing is sort of a historical artifact
233  * from a feature that turned out to be dumb; perhaps
234  * we should purge it entirely. The problem with
235  * the feature is that it looks like memory allocation
236  * failure, but is not a transient or resolvable failure.
237  */
238 static void
239 set_max_length (DBusString *str,
240                 int         max_length)
241 {
242   DBusRealString *real;
243   
244   real = (DBusRealString*) str;
245
246   real->max_length = max_length;
247 }
248
249 /**
250  * Initializes a constant string. The value parameter is not copied
251  * (should be static), and the string may never be modified.
252  * It is safe but not necessary to call _dbus_string_free()
253  * on a const string. The string has a length limit of MAXINT - 8.
254  * 
255  * @param str memory to use for the string
256  * @param value a string to be stored in str (not copied!!!)
257  */
258 void
259 _dbus_string_init_const (DBusString *str,
260                          const char *value)
261 {
262   _dbus_assert (value != NULL);
263   
264   _dbus_string_init_const_len (str, value,
265                                strlen (value));
266 }
267
268 /**
269  * Initializes a constant string with a length. The value parameter is
270  * not copied (should be static), and the string may never be
271  * modified.  It is safe but not necessary to call _dbus_string_free()
272  * on a const string.
273  * 
274  * @param str memory to use for the string
275  * @param value a string to be stored in str (not copied!!!)
276  * @param len the length to use
277  */
278 void
279 _dbus_string_init_const_len (DBusString *str,
280                              const char *value,
281                              int         len)
282 {
283   DBusRealString *real;
284   
285   _dbus_assert (str != NULL);
286   _dbus_assert (value != NULL);
287   _dbus_assert (len <= MAX_MAX_LENGTH);
288   _dbus_assert (len >= 0);
289   
290   real = (DBusRealString*) str;
291   
292   real->str = (char*) value;
293   real->len = len;
294   real->allocated = real->len + ALLOCATION_PADDING; /* a lie, just to avoid special-case assertions... */
295   real->max_length = real->len + 1;
296   real->constant = TRUE;
297   real->invalid = FALSE;
298
299   /* We don't require const strings to be 8-byte aligned as the
300    * memory is coming from elsewhere.
301    */
302 }
303
304 /**
305  * Frees a string created by _dbus_string_init().
306  *
307  * @param str memory where the string is stored.
308  */
309 void
310 _dbus_string_free (DBusString *str)
311 {
312   DBusRealString *real = (DBusRealString*) str;
313   DBUS_GENERIC_STRING_PREAMBLE (real);
314   
315   if (real->constant)
316     return;
317   dbus_free (real->str - real->align_offset);
318
319   real->invalid = TRUE;
320 }
321
322 #ifdef DBUS_BUILD_TESTS
323 /* Not using this feature at the moment,
324  * so marked DBUS_BUILD_TESTS-only
325  */
326 /**
327  * Locks a string such that any attempts to change the string will
328  * result in aborting the program. Also, if the string is wasting a
329  * lot of memory (allocation is sufficiently larger than what the
330  * string is really using), _dbus_string_lock() will realloc the
331  * string's data to "compact" it.
332  *
333  * @param str the string to lock.
334  */
335 void
336 _dbus_string_lock (DBusString *str)
337 {  
338   DBUS_LOCKED_STRING_PREAMBLE (str); /* can lock multiple times */
339
340   real->locked = TRUE;
341
342   /* Try to realloc to avoid excess memory usage, since
343    * we know we won't change the string further
344    */
345 #define MAX_WASTE 48
346   if (real->allocated - MAX_WASTE > real->len)
347     {
348       char *new_str;
349       int new_allocated;
350
351       new_allocated = real->len + ALLOCATION_PADDING;
352
353       new_str = dbus_realloc (real->str - real->align_offset,
354                               new_allocated);
355       if (new_str != NULL)
356         {
357           real->str = new_str + real->align_offset;
358           real->allocated = new_allocated;
359           fixup_alignment (real);
360         }
361     }
362 }
363 #endif /* DBUS_BUILD_TESTS */
364
365 static dbus_bool_t
366 reallocate_for_length (DBusRealString *real,
367                        int             new_length)
368 {
369   int new_allocated;
370   char *new_str;
371
372   /* at least double our old allocation to avoid O(n), avoiding
373    * overflow
374    */
375   if (real->allocated > (MAX_MAX_LENGTH + ALLOCATION_PADDING) / 2)
376     new_allocated = MAX_MAX_LENGTH + ALLOCATION_PADDING;
377   else
378     new_allocated = real->allocated * 2;
379
380   /* if you change the code just above here, run the tests without
381    * the following before you commit
382    */
383 #ifdef DBUS_BUILD_TESTS
384   new_allocated = 0; /* ensure a realloc every time so that we go
385                       * through all malloc failure codepaths
386                       */
387 #endif
388       
389   /* But be sure we always alloc at least space for the new length */
390   new_allocated = MAX (new_allocated, new_length + ALLOCATION_PADDING);
391
392   _dbus_assert (new_allocated >= real->allocated); /* code relies on this */
393   new_str = dbus_realloc (real->str - real->align_offset, new_allocated);
394   if (new_str == NULL)
395     return FALSE;
396
397   real->str = new_str + real->align_offset;
398   real->allocated = new_allocated;
399   fixup_alignment (real);
400
401   return TRUE;
402 }
403
404 static dbus_bool_t
405 set_length (DBusRealString *real,
406             int             new_length)
407 {
408   /* Note, we are setting the length not including nul termination */
409
410   /* exceeding max length is the same as failure to allocate memory */
411   if (new_length > real->max_length)
412     return FALSE;
413   else if (new_length > (real->allocated - ALLOCATION_PADDING) &&
414            !reallocate_for_length (real, new_length))
415     return FALSE;
416   else
417     {
418       real->len = new_length;
419       real->str[real->len] = '\0';
420       return TRUE;
421     }
422 }
423
424 static dbus_bool_t
425 open_gap (int             len,
426           DBusRealString *dest,
427           int             insert_at)
428 {
429   if (len == 0)
430     return TRUE;
431
432   if (len > dest->max_length - dest->len)
433     return FALSE; /* detected overflow of dest->len + len below */
434   
435   if (!set_length (dest, dest->len + len))
436     return FALSE;
437
438   memmove (dest->str + insert_at + len, 
439            dest->str + insert_at,
440            dest->len - len - insert_at);
441
442   return TRUE;
443 }
444
445 /**
446  * Gets the raw character buffer from the string.  The returned buffer
447  * will be nul-terminated, but note that strings may contain binary
448  * data so there may be extra nul characters prior to the termination.
449  * This function should be little-used, extend DBusString or add
450  * stuff to dbus-sysdeps.c instead. It's an error to use this
451  * function on a const string.
452  *
453  * @param str the string
454  * @returns the data
455  */
456 char*
457 _dbus_string_get_data (DBusString *str)
458 {
459   DBUS_STRING_PREAMBLE (str);
460   
461   return real->str;
462 }
463
464 /**
465  * Gets the raw character buffer from a const string.
466  *
467  * @param str the string
468  * @returns the string data
469  */
470 const char*
471 _dbus_string_get_const_data (const DBusString  *str)
472 {
473   DBUS_CONST_STRING_PREAMBLE (str);
474   
475   return real->str;
476 }
477
478 /**
479  * Gets a sub-portion of the raw character buffer from the
480  * string. The "len" field is required simply for error
481  * checking, to be sure you don't try to use more
482  * string than exists. The nul termination of the
483  * returned buffer remains at the end of the entire
484  * string, not at start + len.
485  *
486  * @param str the string
487  * @param start byte offset to return
488  * @param len length of segment to return
489  * @returns the string data
490  */
491 char*
492 _dbus_string_get_data_len (DBusString *str,
493                            int         start,
494                            int         len)
495 {
496   DBUS_STRING_PREAMBLE (str);
497   _dbus_assert (start >= 0);
498   _dbus_assert (len >= 0);
499   _dbus_assert (start <= real->len);
500   _dbus_assert (len <= real->len - start);
501   
502   return real->str + start;
503 }
504
505 /**
506  * const version of _dbus_string_get_data_len().
507  *
508  * @param str the string
509  * @param start byte offset to return
510  * @param len length of segment to return
511  * @returns the string data
512  */
513 const char*
514 _dbus_string_get_const_data_len (const DBusString  *str,
515                                  int                start,
516                                  int                len)
517 {
518   DBUS_CONST_STRING_PREAMBLE (str);
519   _dbus_assert (start >= 0);
520   _dbus_assert (len >= 0);
521   _dbus_assert (start <= real->len);
522   _dbus_assert (len <= real->len - start);
523   
524   return real->str + start;
525 }
526
527 /**
528  * Sets the value of the byte at the given position.
529  *
530  * @param str the string
531  * @param i the position
532  * @param byte the new value
533  */
534 void
535 _dbus_string_set_byte (DBusString    *str,
536                        int            i,
537                        unsigned char  byte)
538 {
539   DBUS_STRING_PREAMBLE (str);
540   _dbus_assert (i < real->len);
541   _dbus_assert (i >= 0);
542   
543   real->str[i] = byte;
544 }
545
546 /**
547  * Gets the byte at the given position. It is
548  * allowed to ask for the nul byte at the end of
549  * the string.
550  *
551  * @param str the string
552  * @param start the position
553  * @returns the byte at that position
554  */
555 unsigned char
556 _dbus_string_get_byte (const DBusString  *str,
557                        int                start)
558 {
559   DBUS_CONST_STRING_PREAMBLE (str);
560   _dbus_assert (start <= real->len);
561   _dbus_assert (start >= 0);
562   
563   return real->str[start];
564 }
565
566 /**
567  * Inserts a number of bytes of a given value at the
568  * given position.
569  *
570  * @param str the string
571  * @param i the position
572  * @param n_bytes number of bytes
573  * @param byte the value to insert
574  * @returns #TRUE on success
575  */
576 dbus_bool_t
577 _dbus_string_insert_bytes (DBusString   *str,
578                            int           i,
579                            int           n_bytes,
580                            unsigned char byte)
581 {
582   DBUS_STRING_PREAMBLE (str);
583   _dbus_assert (i <= real->len);
584   _dbus_assert (i >= 0);
585   _dbus_assert (n_bytes > 0);
586   
587   if (!open_gap (n_bytes, real, i))
588     return FALSE;
589   
590   memset (real->str + i, byte, n_bytes);
591
592   return TRUE;
593 }
594
595 /**
596  * Like _dbus_string_get_data(), but removes the
597  * gotten data from the original string. The caller
598  * must free the data returned. This function may
599  * fail due to lack of memory, and return #FALSE.
600  *
601  * @param str the string
602  * @param data_return location to return the buffer
603  * @returns #TRUE on success
604  */
605 dbus_bool_t
606 _dbus_string_steal_data (DBusString        *str,
607                          char             **data_return)
608 {
609   int old_max_length;
610   DBUS_STRING_PREAMBLE (str);
611   _dbus_assert (data_return != NULL);
612
613   undo_alignment (real);
614   
615   *data_return = real->str;
616
617   old_max_length = real->max_length;
618   
619   /* reset the string */
620   if (!_dbus_string_init (str))
621     {
622       /* hrm, put it back then */
623       real->str = *data_return;
624       *data_return = NULL;
625       fixup_alignment (real);
626       return FALSE;
627     }
628
629   real->max_length = old_max_length;
630
631   return TRUE;
632 }
633
634 /**
635  * Like _dbus_string_get_data_len(), but removes the gotten data from
636  * the original string. The caller must free the data returned. This
637  * function may fail due to lack of memory, and return #FALSE.
638  * The returned string is nul-terminated and has length len.
639  *
640  * @todo this function is broken because on failure it
641  * may corrupt the source string.
642  * 
643  * @param str the string
644  * @param data_return location to return the buffer
645  * @param start the start of segment to steal
646  * @param len the length of segment to steal
647  * @returns #TRUE on success
648  */
649 dbus_bool_t
650 _dbus_string_steal_data_len (DBusString        *str,
651                              char             **data_return,
652                              int                start,
653                              int                len)
654 {
655   DBusString dest;
656   DBUS_STRING_PREAMBLE (str);
657   _dbus_assert (data_return != NULL);
658   _dbus_assert (start >= 0);
659   _dbus_assert (len >= 0);
660   _dbus_assert (start <= real->len);
661   _dbus_assert (len <= real->len - start);
662
663   if (!_dbus_string_init (&dest))
664     return FALSE;
665
666   set_max_length (&dest, real->max_length);
667   
668   if (!_dbus_string_move_len (str, start, len, &dest, 0))
669     {
670       _dbus_string_free (&dest);
671       return FALSE;
672     }
673
674   _dbus_warn ("Broken code in _dbus_string_steal_data_len(), see @todo, FIXME\n");
675   if (!_dbus_string_steal_data (&dest, data_return))
676     {
677       _dbus_string_free (&dest);
678       return FALSE;
679     }
680
681   _dbus_string_free (&dest);
682   return TRUE;
683 }
684
685
686 /**
687  * Copies the data from the string into a char*
688  *
689  * @param str the string
690  * @param data_return place to return the data
691  * @returns #TRUE on success, #FALSE on no memory
692  */
693 dbus_bool_t
694 _dbus_string_copy_data (const DBusString  *str,
695                         char             **data_return)
696 {
697   DBUS_CONST_STRING_PREAMBLE (str);
698   _dbus_assert (data_return != NULL);
699   
700   *data_return = dbus_malloc (real->len + 1);
701   if (*data_return == NULL)
702     return FALSE;
703
704   memcpy (*data_return, real->str, real->len + 1);
705
706   return TRUE;
707 }
708
709 /**
710  * Copies a segment of the string into a char*
711  *
712  * @param str the string
713  * @param data_return place to return the data
714  * @param start start index
715  * @param len length to copy
716  * @returns #FALSE if no memory
717  */
718 dbus_bool_t
719 _dbus_string_copy_data_len (const DBusString  *str,
720                             char             **data_return,
721                             int                start,
722                             int                len)
723 {
724   DBusString dest;
725
726   DBUS_CONST_STRING_PREAMBLE (str);
727   _dbus_assert (data_return != NULL);
728   _dbus_assert (start >= 0);
729   _dbus_assert (len >= 0);
730   _dbus_assert (start <= real->len);
731   _dbus_assert (len <= real->len - start);
732
733   if (!_dbus_string_init (&dest))
734     return FALSE;
735
736   set_max_length (&dest, real->max_length);
737
738   if (!_dbus_string_copy_len (str, start, len, &dest, 0))
739     {
740       _dbus_string_free (&dest);
741       return FALSE;
742     }
743
744   if (!_dbus_string_steal_data (&dest, data_return))
745     {
746       _dbus_string_free (&dest);
747       return FALSE;
748     }
749
750   _dbus_string_free (&dest);
751   return TRUE;
752 }
753
754 /**
755  * Gets the length of a string (not including nul termination).
756  *
757  * @returns the length.
758  */
759 int
760 _dbus_string_get_length (const DBusString  *str)
761 {
762   DBUS_CONST_STRING_PREAMBLE (str);
763   
764   return real->len;
765 }
766
767 /**
768  * Makes a string longer by the given number of bytes.  Checks whether
769  * adding additional_length to the current length would overflow an
770  * integer, and checks for exceeding a string's max length.
771  * The new bytes are not initialized, other than nul-terminating
772  * the end of the string. The uninitialized bytes may contain
773  * nul bytes or other junk.
774  *
775  * @param str a string
776  * @param additional_length length to add to the string.
777  * @returns #TRUE on success.
778  */
779 dbus_bool_t
780 _dbus_string_lengthen (DBusString *str,
781                        int         additional_length)
782 {
783   DBUS_STRING_PREAMBLE (str);  
784   _dbus_assert (additional_length >= 0);
785
786   if (additional_length > real->max_length - real->len)
787     return FALSE; /* would overflow */
788   
789   return set_length (real,
790                      real->len + additional_length);
791 }
792
793 /**
794  * Makes a string shorter by the given number of bytes.
795  *
796  * @param str a string
797  * @param length_to_remove length to remove from the string.
798  */
799 void
800 _dbus_string_shorten (DBusString *str,
801                       int         length_to_remove)
802 {
803   DBUS_STRING_PREAMBLE (str);
804   _dbus_assert (length_to_remove >= 0);
805   _dbus_assert (length_to_remove <= real->len);
806
807   set_length (real,
808               real->len - length_to_remove);
809 }
810
811 /**
812  * Sets the length of a string. Can be used to truncate or lengthen
813  * the string. If the string is lengthened, the function may fail and
814  * return #FALSE. Newly-added bytes are not initialized, as with
815  * _dbus_string_lengthen().
816  *
817  * @param str a string
818  * @param length new length of the string.
819  * @returns #FALSE on failure.
820  */
821 dbus_bool_t
822 _dbus_string_set_length (DBusString *str,
823                          int         length)
824 {
825   DBUS_STRING_PREAMBLE (str);
826   _dbus_assert (length >= 0);
827
828   return set_length (real, length);
829 }
830
831 static dbus_bool_t
832 align_length_then_lengthen (DBusString *str,
833                             int         alignment,
834                             int         then_lengthen_by)
835 {
836   unsigned long new_len; /* ulong to avoid _DBUS_ALIGN_VALUE overflow */
837   int delta;
838   DBUS_STRING_PREAMBLE (str);
839   _dbus_assert (alignment >= 1);
840   _dbus_assert (alignment <= 8); /* it has to be a bug if > 8 */
841
842   new_len = _DBUS_ALIGN_VALUE (real->len, alignment);
843   if (new_len > (unsigned long) real->max_length - then_lengthen_by)
844     return FALSE;
845   new_len += then_lengthen_by;
846   
847   delta = new_len - real->len;
848   _dbus_assert (delta >= 0);
849
850   if (delta == 0)
851     return TRUE;
852
853   if (!set_length (real, new_len))
854     return FALSE;
855
856   /* delta == padding + then_lengthen_by
857    * new_len == old_len + padding + then_lengthen_by
858    */
859   if (then_lengthen_by < delta)
860     {
861       unsigned int i;
862       i = new_len - delta;
863       while (i < (new_len - then_lengthen_by))
864         {
865           real->str[i] = '\0';
866           ++i;
867         }
868     }
869       
870   return TRUE;
871 }
872
873 /**
874  * Align the length of a string to a specific alignment (typically 4 or 8)
875  * by appending nul bytes to the string.
876  *
877  * @param str a string
878  * @param alignment the alignment
879  * @returns #FALSE if no memory
880  */
881 dbus_bool_t
882 _dbus_string_align_length (DBusString *str,
883                            int         alignment)
884 {
885   return align_length_then_lengthen (str, alignment, 0);
886 }
887
888 static dbus_bool_t
889 append (DBusRealString *real,
890         const char     *buffer,
891         int             buffer_len)
892 {
893   if (buffer_len == 0)
894     return TRUE;
895
896   if (!_dbus_string_lengthen ((DBusString*)real, buffer_len))
897     return FALSE;
898
899   memcpy (real->str + (real->len - buffer_len),
900           buffer,
901           buffer_len);
902
903   return TRUE;
904 }
905
906 /**
907  * Appends a nul-terminated C-style string to a DBusString.
908  *
909  * @param str the DBusString
910  * @param buffer the nul-terminated characters to append
911  * @returns #FALSE if not enough memory.
912  */
913 dbus_bool_t
914 _dbus_string_append (DBusString *str,
915                      const char *buffer)
916 {
917   unsigned long buffer_len;
918   
919   DBUS_STRING_PREAMBLE (str);
920   _dbus_assert (buffer != NULL);
921   
922   buffer_len = strlen (buffer);
923   if (buffer_len > (unsigned long) real->max_length)
924     return FALSE;
925   
926   return append (real, buffer, buffer_len);
927 }
928
929 /**
930  * Appends 4 bytes aligned on a 4 byte boundary
931  * with any alignment padding initialized to 0.
932  *
933  * @param str the DBusString
934  * @param octets 4 bytes to append
935  * @returns #FALSE if not enough memory.
936  */
937 dbus_bool_t
938 _dbus_string_append_4_aligned (DBusString         *str,
939                                const unsigned char octets[4])
940 {
941   dbus_uint32_t *p;
942   DBUS_STRING_PREAMBLE (str);
943   
944   if (!align_length_then_lengthen (str, 4, 4))
945     return FALSE;
946
947   p = (dbus_uint32_t*) (real->str + (real->len - 4));
948   *p = *((dbus_uint32_t*)octets);
949
950   return TRUE;
951 }
952
953 /**
954  * Appends 8 bytes aligned on an 8 byte boundary
955  * with any alignment padding initialized to 0.
956  *
957  * @param str the DBusString
958  * @param octets 4 bytes to append
959  * @returns #FALSE if not enough memory.
960  */
961 dbus_bool_t
962 _dbus_string_append_8_aligned (DBusString         *str,
963                                const unsigned char octets[8])
964 {
965 #ifdef DBUS_HAVE_INT64
966   dbus_uint64_t *p;
967   DBUS_STRING_PREAMBLE (str);
968   
969   if (!align_length_then_lengthen (str, 8, 8))
970     return FALSE;
971
972   p = (dbus_uint64_t*) (real->str + (real->len - 8));
973   *p = *((dbus_uint64_t*)octets);
974 #else
975   unsigned char *p;
976   DBUS_STRING_PREAMBLE (str);
977   
978   if (!align_length_then_lengthen (str, 8, 8))
979     return FALSE;
980
981   p = real->str + (real->len - 8);
982   
983   *p++ = octets[0];
984   *p++ = octets[1];
985   *p++ = octets[2];
986   *p++ = octets[3];
987   *p++ = octets[4];
988   *p++ = octets[5];
989   *p++ = octets[6];
990   *p++ = octets[7];
991   _dbus_assert (p == (real->str + real->len));
992 #endif
993
994   return TRUE;
995 }
996
997 /**
998  * Appends a printf-style formatted string
999  * to the #DBusString.
1000  *
1001  * @param str the string
1002  * @param format printf format
1003  * @param args variable argument list
1004  * @returns #FALSE if no memory
1005  */
1006 dbus_bool_t
1007 _dbus_string_append_printf_valist  (DBusString        *str,
1008                                     const char        *format,
1009                                     va_list            args)
1010 {
1011   int len;
1012   char c;
1013   DBUS_STRING_PREAMBLE (str);
1014   
1015   /* Measure the message length without terminating nul */
1016   len = vsnprintf (&c, 1, format, args);
1017
1018   if (!_dbus_string_lengthen (str, len))
1019     return FALSE;
1020
1021   vsprintf (real->str + (real->len - len),
1022             format, args);
1023
1024   return TRUE;
1025 }
1026
1027 /**
1028  * Appends a printf-style formatted string
1029  * to the #DBusString.
1030  *
1031  * @param str the string
1032  * @param format printf format
1033  * @returns #FALSE if no memory
1034  */
1035 dbus_bool_t
1036 _dbus_string_append_printf (DBusString        *str,
1037                             const char        *format,
1038                             ...)
1039 {
1040   va_list args;
1041   dbus_bool_t retval;
1042   
1043   va_start (args, format);
1044   retval = _dbus_string_append_printf_valist (str, format, args);
1045   va_end (args);
1046
1047   return retval;
1048 }
1049
1050 /**
1051  * Appends block of bytes with the given length to a DBusString.
1052  *
1053  * @param str the DBusString
1054  * @param buffer the bytes to append
1055  * @param len the number of bytes to append
1056  * @returns #FALSE if not enough memory.
1057  */
1058 dbus_bool_t
1059 _dbus_string_append_len (DBusString *str,
1060                          const char *buffer,
1061                          int         len)
1062 {
1063   DBUS_STRING_PREAMBLE (str);
1064   _dbus_assert (buffer != NULL);
1065   _dbus_assert (len >= 0);
1066
1067   return append (real, buffer, len);
1068 }
1069
1070 /**
1071  * Appends a single byte to the string, returning #FALSE
1072  * if not enough memory.
1073  *
1074  * @param str the string
1075  * @param byte the byte to append
1076  * @returns #TRUE on success
1077  */
1078 dbus_bool_t
1079 _dbus_string_append_byte (DBusString    *str,
1080                           unsigned char  byte)
1081 {
1082   DBUS_STRING_PREAMBLE (str);
1083
1084   if (!set_length (real, real->len + 1))
1085     return FALSE;
1086
1087   real->str[real->len-1] = byte;
1088
1089   return TRUE;
1090 }
1091
1092 /**
1093  * Appends a single Unicode character, encoding the character
1094  * in UTF-8 format.
1095  *
1096  * @param str the string
1097  * @param ch the Unicode character
1098  */
1099 dbus_bool_t
1100 _dbus_string_append_unichar (DBusString    *str,
1101                              dbus_unichar_t ch)
1102 {
1103   int len;
1104   int first;
1105   int i;
1106   char *out;
1107   
1108   DBUS_STRING_PREAMBLE (str);
1109
1110   /* this code is from GLib but is pretty standard I think */
1111   
1112   len = 0;
1113   
1114   if (ch < 0x80)
1115     {
1116       first = 0;
1117       len = 1;
1118     }
1119   else if (ch < 0x800)
1120     {
1121       first = 0xc0;
1122       len = 2;
1123     }
1124   else if (ch < 0x10000)
1125     {
1126       first = 0xe0;
1127       len = 3;
1128     }
1129    else if (ch < 0x200000)
1130     {
1131       first = 0xf0;
1132       len = 4;
1133     }
1134   else if (ch < 0x4000000)
1135     {
1136       first = 0xf8;
1137       len = 5;
1138     }
1139   else
1140     {
1141       first = 0xfc;
1142       len = 6;
1143     }
1144
1145   if (len > (real->max_length - real->len))
1146     return FALSE; /* real->len + len would overflow */
1147   
1148   if (!set_length (real, real->len + len))
1149     return FALSE;
1150
1151   out = real->str + (real->len - len);
1152   
1153   for (i = len - 1; i > 0; --i)
1154     {
1155       out[i] = (ch & 0x3f) | 0x80;
1156       ch >>= 6;
1157     }
1158   out[0] = ch | first;
1159
1160   return TRUE;
1161 }
1162
1163 static void
1164 delete (DBusRealString *real,
1165         int             start,
1166         int             len)
1167 {
1168   if (len == 0)
1169     return;
1170   
1171   memmove (real->str + start, real->str + start + len, real->len - (start + len));
1172   real->len -= len;
1173   real->str[real->len] = '\0';
1174 }
1175
1176 /**
1177  * Deletes a segment of a DBusString with length len starting at
1178  * start. (Hint: to clear an entire string, setting length to 0
1179  * with _dbus_string_set_length() is easier.)
1180  *
1181  * @param str the DBusString
1182  * @param start where to start deleting
1183  * @param len the number of bytes to delete
1184  */
1185 void
1186 _dbus_string_delete (DBusString       *str,
1187                      int               start,
1188                      int               len)
1189 {
1190   DBUS_STRING_PREAMBLE (str);
1191   _dbus_assert (start >= 0);
1192   _dbus_assert (len >= 0);
1193   _dbus_assert (start <= real->len);
1194   _dbus_assert (len <= real->len - start);
1195   
1196   delete (real, start, len);
1197 }
1198
1199 static dbus_bool_t
1200 copy (DBusRealString *source,
1201       int             start,
1202       int             len,
1203       DBusRealString *dest,
1204       int             insert_at)
1205 {
1206   if (len == 0)
1207     return TRUE;
1208
1209   if (!open_gap (len, dest, insert_at))
1210     return FALSE;
1211   
1212   memcpy (dest->str + insert_at,
1213           source->str + start,
1214           len);
1215
1216   return TRUE;
1217 }
1218
1219 /**
1220  * Checks assertions for two strings we're copying a segment between,
1221  * and declares real_source/real_dest variables.
1222  *
1223  * @param source the source string
1224  * @param start the starting offset
1225  * @param dest the dest string
1226  * @param insert_at where the copied segment is inserted
1227  */
1228 #define DBUS_STRING_COPY_PREAMBLE(source, start, dest, insert_at)       \
1229   DBusRealString *real_source = (DBusRealString*) source;               \
1230   DBusRealString *real_dest = (DBusRealString*) dest;                   \
1231   _dbus_assert ((source) != (dest));                                    \
1232   DBUS_GENERIC_STRING_PREAMBLE (real_source);                           \
1233   DBUS_GENERIC_STRING_PREAMBLE (real_dest);                             \
1234   _dbus_assert (!real_dest->constant);                                  \
1235   _dbus_assert (!real_dest->locked);                                    \
1236   _dbus_assert ((start) >= 0);                                          \
1237   _dbus_assert ((start) <= real_source->len);                           \
1238   _dbus_assert ((insert_at) >= 0);                                      \
1239   _dbus_assert ((insert_at) <= real_dest->len)
1240
1241 /**
1242  * Moves the end of one string into another string. Both strings
1243  * must be initialized, valid strings.
1244  *
1245  * @param source the source string
1246  * @param start where to chop off the source string
1247  * @param dest the destination string
1248  * @param insert_at where to move the chopped-off part of source string
1249  * @returns #FALSE if not enough memory
1250  */
1251 dbus_bool_t
1252 _dbus_string_move (DBusString       *source,
1253                    int               start,
1254                    DBusString       *dest,
1255                    int               insert_at)
1256 {
1257   DBusRealString *real_source = (DBusRealString*) source;
1258   _dbus_assert (start <= real_source->len);
1259   
1260   return _dbus_string_move_len (source, start,
1261                                 real_source->len - start,
1262                                 dest, insert_at);
1263 }
1264
1265 /**
1266  * Like _dbus_string_move(), but does not delete the section
1267  * of the source string that's copied to the dest string.
1268  *
1269  * @param source the source string
1270  * @param start where to start copying the source string
1271  * @param dest the destination string
1272  * @param insert_at where to place the copied part of source string
1273  * @returns #FALSE if not enough memory
1274  */
1275 dbus_bool_t
1276 _dbus_string_copy (const DBusString *source,
1277                    int               start,
1278                    DBusString       *dest,
1279                    int               insert_at)
1280 {
1281   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
1282
1283   return copy (real_source, start,
1284                real_source->len - start,
1285                real_dest,
1286                insert_at);
1287 }
1288
1289 /**
1290  * Like _dbus_string_move(), but can move a segment from
1291  * the middle of the source string.
1292  *
1293  * @todo this doesn't do anything with max_length field.
1294  * we should probably just kill the max_length field though.
1295  * 
1296  * @param source the source string
1297  * @param start first byte of source string to move
1298  * @param len length of segment to move
1299  * @param dest the destination string
1300  * @param insert_at where to move the bytes from the source string
1301  * @returns #FALSE if not enough memory
1302  */
1303 dbus_bool_t
1304 _dbus_string_move_len (DBusString       *source,
1305                        int               start,
1306                        int               len,
1307                        DBusString       *dest,
1308                        int               insert_at)
1309
1310 {
1311   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
1312   _dbus_assert (len >= 0);
1313   _dbus_assert ((start + len) <= real_source->len);
1314
1315
1316   if (len == 0)
1317     {
1318       return TRUE;
1319     }
1320   else if (start == 0 &&
1321            len == real_source->len &&
1322            real_dest->len == 0)
1323     {
1324       /* Short-circuit moving an entire existing string to an empty string
1325        * by just swapping the buffers.
1326        */
1327       /* we assume ->constant doesn't matter as you can't have
1328        * a constant string involved in a move.
1329        */
1330 #define ASSIGN_DATA(a, b) do {                  \
1331         (a)->str = (b)->str;                    \
1332         (a)->len = (b)->len;                    \
1333         (a)->allocated = (b)->allocated;        \
1334         (a)->align_offset = (b)->align_offset;  \
1335       } while (0)
1336       
1337       DBusRealString tmp;
1338
1339       ASSIGN_DATA (&tmp, real_source);
1340       ASSIGN_DATA (real_source, real_dest);
1341       ASSIGN_DATA (real_dest, &tmp);
1342
1343       return TRUE;
1344     }
1345   else
1346     {
1347       if (!copy (real_source, start, len,
1348                  real_dest,
1349                  insert_at))
1350         return FALSE;
1351       
1352       delete (real_source, start,
1353               len);
1354       
1355       return TRUE;
1356     }
1357 }
1358
1359 /**
1360  * Like _dbus_string_copy(), but can copy a segment from the middle of
1361  * the source string.
1362  *
1363  * @param source the source string
1364  * @param start where to start copying the source string
1365  * @param len length of segment to copy
1366  * @param dest the destination string
1367  * @param insert_at where to place the copied segment of source string
1368  * @returns #FALSE if not enough memory
1369  */
1370 dbus_bool_t
1371 _dbus_string_copy_len (const DBusString *source,
1372                        int               start,
1373                        int               len,
1374                        DBusString       *dest,
1375                        int               insert_at)
1376 {
1377   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
1378   _dbus_assert (len >= 0);
1379   _dbus_assert (start <= real_source->len);
1380   _dbus_assert (len <= real_source->len - start);
1381   
1382   return copy (real_source, start, len,
1383                real_dest,
1384                insert_at);
1385 }
1386
1387 /**
1388  * Replaces a segment of dest string with a segment of source string.
1389  *
1390  * @todo optimize the case where the two lengths are the same, and
1391  * avoid memmoving the data in the trailing part of the string twice.
1392  *
1393  * @todo avoid inserting the source into dest, then deleting
1394  * the replaced chunk of dest (which creates a potentially large
1395  * intermediate string). Instead, extend the replaced chunk
1396  * of dest with padding to the same size as the source chunk,
1397  * then copy in the source bytes.
1398  * 
1399  * @param source the source string
1400  * @param start where to start copying the source string
1401  * @param len length of segment to copy
1402  * @param dest the destination string
1403  * @param replace_at start of segment of dest string to replace
1404  * @param replace_len length of segment of dest string to replace
1405  * @returns #FALSE if not enough memory
1406  *
1407  */
1408 dbus_bool_t
1409 _dbus_string_replace_len (const DBusString *source,
1410                           int               start,
1411                           int               len,
1412                           DBusString       *dest,
1413                           int               replace_at,
1414                           int               replace_len)
1415 {
1416   DBUS_STRING_COPY_PREAMBLE (source, start, dest, replace_at);
1417   _dbus_assert (len >= 0);
1418   _dbus_assert (start <= real_source->len);
1419   _dbus_assert (len <= real_source->len - start);
1420   _dbus_assert (replace_at >= 0);
1421   _dbus_assert (replace_at <= real_dest->len);
1422   _dbus_assert (replace_len <= real_dest->len - replace_at);
1423
1424   if (!copy (real_source, start, len,
1425              real_dest, replace_at))
1426     return FALSE;
1427
1428   delete (real_dest, replace_at + len, replace_len);
1429
1430   return TRUE;
1431 }
1432
1433 /* Unicode macros and utf8_validate() from GLib Owen Taylor, Havoc
1434  * Pennington, and Tom Tromey are the authors and authorized relicense.
1435  */
1436
1437 /** computes length and mask of a unicode character
1438  * @param Char the char
1439  * @param Mask the mask variable to assign to
1440  * @param Len the length variable to assign to
1441  */
1442 #define UTF8_COMPUTE(Char, Mask, Len)                                         \
1443   if (Char < 128)                                                             \
1444     {                                                                         \
1445       Len = 1;                                                                \
1446       Mask = 0x7f;                                                            \
1447     }                                                                         \
1448   else if ((Char & 0xe0) == 0xc0)                                             \
1449     {                                                                         \
1450       Len = 2;                                                                \
1451       Mask = 0x1f;                                                            \
1452     }                                                                         \
1453   else if ((Char & 0xf0) == 0xe0)                                             \
1454     {                                                                         \
1455       Len = 3;                                                                \
1456       Mask = 0x0f;                                                            \
1457     }                                                                         \
1458   else if ((Char & 0xf8) == 0xf0)                                             \
1459     {                                                                         \
1460       Len = 4;                                                                \
1461       Mask = 0x07;                                                            \
1462     }                                                                         \
1463   else if ((Char & 0xfc) == 0xf8)                                             \
1464     {                                                                         \
1465       Len = 5;                                                                \
1466       Mask = 0x03;                                                            \
1467     }                                                                         \
1468   else if ((Char & 0xfe) == 0xfc)                                             \
1469     {                                                                         \
1470       Len = 6;                                                                \
1471       Mask = 0x01;                                                            \
1472     }                                                                         \
1473   else                                                                        \
1474     Len = -1;
1475
1476 /**
1477  * computes length of a unicode character in UTF-8
1478  * @param Char the char
1479  */
1480 #define UTF8_LENGTH(Char)              \
1481   ((Char) < 0x80 ? 1 :                 \
1482    ((Char) < 0x800 ? 2 :               \
1483     ((Char) < 0x10000 ? 3 :            \
1484      ((Char) < 0x200000 ? 4 :          \
1485       ((Char) < 0x4000000 ? 5 : 6)))))
1486    
1487 /**
1488  * Gets a UTF-8 value.
1489  *
1490  * @param Result variable for extracted unicode char.
1491  * @param Chars the bytes to decode
1492  * @param Count counter variable
1493  * @param Mask mask for this char
1494  * @param Len length for this char in bytes
1495  */
1496 #define UTF8_GET(Result, Chars, Count, Mask, Len)                             \
1497   (Result) = (Chars)[0] & (Mask);                                             \
1498   for ((Count) = 1; (Count) < (Len); ++(Count))                               \
1499     {                                                                         \
1500       if (((Chars)[(Count)] & 0xc0) != 0x80)                                  \
1501         {                                                                     \
1502           (Result) = -1;                                                      \
1503           break;                                                              \
1504         }                                                                     \
1505       (Result) <<= 6;                                                         \
1506       (Result) |= ((Chars)[(Count)] & 0x3f);                                  \
1507     }
1508
1509 /**
1510  * Check whether a unicode char is in a valid range.
1511  *
1512  * @param Char the character
1513  */
1514 #define UNICODE_VALID(Char)                   \
1515     ((Char) < 0x110000 &&                     \
1516      (((Char) & 0xFFFFF800) != 0xD800) &&     \
1517      ((Char) < 0xFDD0 || (Char) > 0xFDEF) &&  \
1518      ((Char) & 0xFFFF) != 0xFFFF)
1519
1520 /**
1521  * Gets a unicode character from a UTF-8 string. Does no validation;
1522  * you must verify that the string is valid UTF-8 in advance and must
1523  * pass in the start of a character.
1524  *
1525  * @param str the string
1526  * @param start the start of the UTF-8 character.
1527  * @param ch_return location to return the character
1528  * @param end_return location to return the byte index of next character
1529  */
1530 void
1531 _dbus_string_get_unichar (const DBusString *str,
1532                           int               start,
1533                           dbus_unichar_t   *ch_return,
1534                           int              *end_return)
1535 {
1536   int i, mask, len;
1537   dbus_unichar_t result;
1538   unsigned char c;
1539   unsigned char *p;
1540   DBUS_CONST_STRING_PREAMBLE (str);
1541   _dbus_assert (start >= 0);
1542   _dbus_assert (start <= real->len);
1543   
1544   if (ch_return)
1545     *ch_return = 0;
1546   if (end_return)
1547     *end_return = real->len;
1548   
1549   mask = 0;
1550   p = real->str + start;
1551   c = *p;
1552   
1553   UTF8_COMPUTE (c, mask, len);
1554   if (len == -1)
1555     return;
1556   UTF8_GET (result, p, i, mask, len);
1557
1558   if (result == (dbus_unichar_t)-1)
1559     return;
1560
1561   if (ch_return)
1562     *ch_return = result;
1563   if (end_return)
1564     *end_return = start + len;
1565 }
1566
1567 /**
1568  * Finds the given substring in the string,
1569  * returning #TRUE and filling in the byte index
1570  * where the substring was found, if it was found.
1571  * Returns #FALSE if the substring wasn't found.
1572  * Sets *start to the length of the string if the substring
1573  * is not found.
1574  *
1575  * @param str the string
1576  * @param start where to start looking
1577  * @param substr the substring
1578  * @param found return location for where it was found, or #NULL
1579  * @returns #TRUE if found
1580  */
1581 dbus_bool_t
1582 _dbus_string_find (const DBusString *str,
1583                    int               start,
1584                    const char       *substr,
1585                    int              *found)
1586 {
1587   return _dbus_string_find_to (str, start,
1588                                ((const DBusRealString*)str)->len,
1589                                substr, found);
1590 }
1591
1592 /**
1593  * Finds the given substring in the string,
1594  * up to a certain position,
1595  * returning #TRUE and filling in the byte index
1596  * where the substring was found, if it was found.
1597  * Returns #FALSE if the substring wasn't found.
1598  * Sets *start to the length of the string if the substring
1599  * is not found.
1600  *
1601  * @param str the string
1602  * @param start where to start looking
1603  * @param end where to stop looking
1604  * @param substr the substring
1605  * @param found return location for where it was found, or #NULL
1606  * @returns #TRUE if found
1607  */
1608 dbus_bool_t
1609 _dbus_string_find_to (const DBusString *str,
1610                       int               start,
1611                       int               end,
1612                       const char       *substr,
1613                       int              *found)
1614 {
1615   int i;
1616   DBUS_CONST_STRING_PREAMBLE (str);
1617   _dbus_assert (substr != NULL);
1618   _dbus_assert (start <= real->len);
1619   _dbus_assert (start >= 0);
1620   _dbus_assert (substr != NULL);
1621   _dbus_assert (end <= real->len);
1622   _dbus_assert (start <= end);
1623
1624   /* we always "find" an empty string */
1625   if (*substr == '\0')
1626     {
1627       if (found)
1628         *found = start;
1629       return TRUE;
1630     }
1631
1632   i = start;
1633   while (i < end)
1634     {
1635       if (real->str[i] == substr[0])
1636         {
1637           int j = i + 1;
1638           
1639           while (j < end)
1640             {
1641               if (substr[j - i] == '\0')
1642                 break;
1643               else if (real->str[j] != substr[j - i])
1644                 break;
1645               
1646               ++j;
1647             }
1648
1649           if (substr[j - i] == '\0')
1650             {
1651               if (found)
1652                 *found = i;
1653               return TRUE;
1654             }
1655         }
1656       
1657       ++i;
1658     }
1659
1660   if (found)
1661     *found = end;
1662   
1663   return FALSE;  
1664 }
1665
1666 /**
1667  * Find the given byte scanning backward from the given start.
1668  * Sets *found to -1 if the byte is not found.
1669  *
1670  * @param str the string
1671  * @param start the place to start scanning (will not find the byte at this point)
1672  * @param byte the byte to find
1673  * @param found return location for where it was found
1674  * @returns #TRUE if found
1675  */
1676 dbus_bool_t
1677 _dbus_string_find_byte_backward (const DBusString  *str,
1678                                  int                start,
1679                                  unsigned char      byte,
1680                                  int               *found)
1681 {
1682   int i;
1683   DBUS_CONST_STRING_PREAMBLE (str);
1684   _dbus_assert (start <= real->len);
1685   _dbus_assert (start >= 0);
1686   _dbus_assert (found != NULL);
1687
1688   i = start - 1;
1689   while (i >= 0)
1690     {
1691       if (real->str[i] == byte)
1692         break;
1693       
1694       --i;
1695     }
1696
1697   if (found)
1698     *found = i;
1699
1700   return i >= 0;
1701 }
1702
1703 /**
1704  * Finds a blank (space or tab) in the string. Returns #TRUE
1705  * if found, #FALSE otherwise. If a blank is not found sets
1706  * *found to the length of the string.
1707  *
1708  * @param str the string
1709  * @param start byte index to start looking
1710  * @param found place to store the location of the first blank
1711  * @returns #TRUE if a blank was found
1712  */
1713 dbus_bool_t
1714 _dbus_string_find_blank (const DBusString *str,
1715                          int               start,
1716                          int              *found)
1717 {
1718   int i;
1719   DBUS_CONST_STRING_PREAMBLE (str);
1720   _dbus_assert (start <= real->len);
1721   _dbus_assert (start >= 0);
1722   
1723   i = start;
1724   while (i < real->len)
1725     {
1726       if (real->str[i] == ' ' ||
1727           real->str[i] == '\t')
1728         {
1729           if (found)
1730             *found = i;
1731           return TRUE;
1732         }
1733       
1734       ++i;
1735     }
1736
1737   if (found)
1738     *found = real->len;
1739   
1740   return FALSE;
1741 }
1742
1743 /**
1744  * Skips blanks from start, storing the first non-blank in *end
1745  * (blank is space or tab).
1746  *
1747  * @param str the string
1748  * @param start where to start
1749  * @param end where to store the first non-blank byte index
1750  */
1751 void
1752 _dbus_string_skip_blank (const DBusString *str,
1753                          int               start,
1754                          int              *end)
1755 {
1756   int i;
1757   DBUS_CONST_STRING_PREAMBLE (str);
1758   _dbus_assert (start <= real->len);
1759   _dbus_assert (start >= 0);
1760   
1761   i = start;
1762   while (i < real->len)
1763     {
1764       if (!(real->str[i] == ' ' ||
1765             real->str[i] == '\t'))
1766         break;
1767       
1768       ++i;
1769     }
1770
1771   _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
1772                                     real->str[i] == '\t'));
1773   
1774   if (end)
1775     *end = i;
1776 }
1777
1778 /**
1779  * Skips whitespace from start, storing the first non-whitespace in *end.
1780  * (whitespace is space, tab, newline, CR).
1781  *
1782  * @param str the string
1783  * @param start where to start
1784  * @param end where to store the first non-whitespace byte index
1785  */
1786 void
1787 _dbus_string_skip_white (const DBusString *str,
1788                          int               start,
1789                          int              *end)
1790 {
1791   int i;
1792   DBUS_CONST_STRING_PREAMBLE (str);
1793   _dbus_assert (start <= real->len);
1794   _dbus_assert (start >= 0);
1795   
1796   i = start;
1797   while (i < real->len)
1798     {
1799       if (!(real->str[i] == ' ' ||
1800             real->str[i] == '\n' ||
1801             real->str[i] == '\r' ||
1802             real->str[i] == '\t'))
1803         break;
1804       
1805       ++i;
1806     }
1807
1808   _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
1809                                     real->str[i] == '\t'));
1810   
1811   if (end)
1812     *end = i;
1813 }
1814
1815 /**
1816  * Assigns a newline-terminated or \\r\\n-terminated line from the front
1817  * of the string to the given dest string. The dest string's previous
1818  * contents are deleted. If the source string contains no newline,
1819  * moves the entire source string to the dest string.
1820  *
1821  * @todo owen correctly notes that this is a stupid function (it was
1822  * written purely for test code,
1823  * e.g. dbus-message-builder.c). Probably should be enforced as test
1824  * code only with #ifdef DBUS_BUILD_TESTS
1825  * 
1826  * @param source the source string
1827  * @param dest the destination string (contents are replaced)
1828  * @returns #FALSE if no memory, or source has length 0
1829  */
1830 dbus_bool_t
1831 _dbus_string_pop_line (DBusString *source,
1832                        DBusString *dest)
1833 {
1834   int eol;
1835   dbus_bool_t have_newline;
1836   
1837   _dbus_string_set_length (dest, 0);
1838   
1839   eol = 0;
1840   if (_dbus_string_find (source, 0, "\n", &eol))
1841     {
1842       have_newline = TRUE;
1843       eol += 1; /* include newline */
1844     }
1845   else
1846     {
1847       eol = _dbus_string_get_length (source);
1848       have_newline = FALSE;
1849     }
1850
1851   if (eol == 0)
1852     return FALSE; /* eof */
1853   
1854   if (!_dbus_string_move_len (source, 0, eol,
1855                               dest, 0))
1856     {
1857       return FALSE;
1858     }
1859
1860   /* dump the newline and the \r if we have one */
1861   if (have_newline)
1862     {
1863       dbus_bool_t have_cr;
1864       
1865       _dbus_assert (_dbus_string_get_length (dest) > 0);
1866
1867       if (_dbus_string_get_length (dest) > 1 &&
1868           _dbus_string_get_byte (dest,
1869                                  _dbus_string_get_length (dest) - 2) == '\r')
1870         have_cr = TRUE;
1871       else
1872         have_cr = FALSE;
1873         
1874       _dbus_string_set_length (dest,
1875                                _dbus_string_get_length (dest) -
1876                                (have_cr ? 2 : 1));
1877     }
1878   
1879   return TRUE;
1880 }
1881
1882 /**
1883  * Deletes up to and including the first blank space
1884  * in the string.
1885  *
1886  * @param str the string
1887  */
1888 void
1889 _dbus_string_delete_first_word (DBusString *str)
1890 {
1891   int i;
1892   
1893   if (_dbus_string_find_blank (str, 0, &i))
1894     _dbus_string_skip_blank (str, i, &i);
1895
1896   _dbus_string_delete (str, 0, i);
1897 }
1898
1899 /**
1900  * Deletes any leading blanks in the string
1901  *
1902  * @param str the string
1903  */
1904 void
1905 _dbus_string_delete_leading_blanks (DBusString *str)
1906 {
1907   int i;
1908   
1909   _dbus_string_skip_blank (str, 0, &i);
1910
1911   if (i > 0)
1912     _dbus_string_delete (str, 0, i);
1913 }
1914
1915 /**
1916  * Tests two DBusString for equality.
1917  *
1918  * @todo memcmp is probably faster
1919  *
1920  * @param a first string
1921  * @param b second string
1922  * @returns #TRUE if equal
1923  */
1924 dbus_bool_t
1925 _dbus_string_equal (const DBusString *a,
1926                     const DBusString *b)
1927 {
1928   const unsigned char *ap;
1929   const unsigned char *bp;
1930   const unsigned char *a_end;
1931   const DBusRealString *real_a = (const DBusRealString*) a;
1932   const DBusRealString *real_b = (const DBusRealString*) b;
1933   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1934   DBUS_GENERIC_STRING_PREAMBLE (real_b);
1935
1936   if (real_a->len != real_b->len)
1937     return FALSE;
1938
1939   ap = real_a->str;
1940   bp = real_b->str;
1941   a_end = real_a->str + real_a->len;
1942   while (ap != a_end)
1943     {
1944       if (*ap != *bp)
1945         return FALSE;
1946       
1947       ++ap;
1948       ++bp;
1949     }
1950
1951   return TRUE;
1952 }
1953
1954 /**
1955  * Tests two DBusString for equality up to the given length.
1956  *
1957  * @todo write a unit test
1958  *
1959  * @todo memcmp is probably faster
1960  *
1961  * @param a first string
1962  * @param b second string
1963  * @param len the lengh
1964  * @returns #TRUE if equal for the given number of bytes
1965  */
1966 dbus_bool_t
1967 _dbus_string_equal_len (const DBusString *a,
1968                         const DBusString *b,
1969                         int               len)
1970 {
1971   const unsigned char *ap;
1972   const unsigned char *bp;
1973   const unsigned char *a_end;
1974   const DBusRealString *real_a = (const DBusRealString*) a;
1975   const DBusRealString *real_b = (const DBusRealString*) b;
1976   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1977   DBUS_GENERIC_STRING_PREAMBLE (real_b);
1978
1979   if (real_a->len != real_b->len &&
1980       (real_a->len < len || real_b->len < len))
1981     return FALSE;
1982
1983   ap = real_a->str;
1984   bp = real_b->str;
1985   a_end = real_a->str + MIN (real_a->len, len);
1986   while (ap != a_end)
1987     {
1988       if (*ap != *bp)
1989         return FALSE;
1990       
1991       ++ap;
1992       ++bp;
1993     }
1994
1995   return TRUE;
1996 }
1997
1998 /**
1999  * Checks whether a string is equal to a C string.
2000  *
2001  * @param a the string
2002  * @param c_str the C string
2003  * @returns #TRUE if equal
2004  */
2005 dbus_bool_t
2006 _dbus_string_equal_c_str (const DBusString *a,
2007                           const char       *c_str)
2008 {
2009   const unsigned char *ap;
2010   const unsigned char *bp;
2011   const unsigned char *a_end;
2012   const DBusRealString *real_a = (const DBusRealString*) a;
2013   DBUS_GENERIC_STRING_PREAMBLE (real_a);
2014   _dbus_assert (c_str != NULL);
2015   
2016   ap = real_a->str;
2017   bp = (const unsigned char*) c_str;
2018   a_end = real_a->str + real_a->len;
2019   while (ap != a_end && *bp)
2020     {
2021       if (*ap != *bp)
2022         return FALSE;
2023       
2024       ++ap;
2025       ++bp;
2026     }
2027
2028   if (ap != a_end || *bp)
2029     return FALSE;
2030   
2031   return TRUE;
2032 }
2033
2034 /**
2035  * Checks whether a string starts with the given C string.
2036  *
2037  * @param a the string
2038  * @param c_str the C string
2039  * @returns #TRUE if string starts with it
2040  */
2041 dbus_bool_t
2042 _dbus_string_starts_with_c_str (const DBusString *a,
2043                                 const char       *c_str)
2044 {
2045   const unsigned char *ap;
2046   const unsigned char *bp;
2047   const unsigned char *a_end;
2048   const DBusRealString *real_a = (const DBusRealString*) a;
2049   DBUS_GENERIC_STRING_PREAMBLE (real_a);
2050   _dbus_assert (c_str != NULL);
2051   
2052   ap = real_a->str;
2053   bp = (const unsigned char*) c_str;
2054   a_end = real_a->str + real_a->len;
2055   while (ap != a_end && *bp)
2056     {
2057       if (*ap != *bp)
2058         return FALSE;
2059       
2060       ++ap;
2061       ++bp;
2062     }
2063
2064   if (*bp == '\0')
2065     return TRUE;
2066   else
2067     return FALSE;
2068 }
2069
2070 /**
2071  * Returns whether a string ends with the given suffix
2072  *
2073  * @todo memcmp might make this faster.
2074  * 
2075  * @param a the string
2076  * @param c_str the C-style string
2077  * @returns #TRUE if the string ends with the suffix
2078  */
2079 dbus_bool_t
2080 _dbus_string_ends_with_c_str (const DBusString *a,
2081                               const char       *c_str)
2082 {
2083   const unsigned char *ap;
2084   const unsigned char *bp;
2085   const unsigned char *a_end;
2086   unsigned long c_str_len;
2087   const DBusRealString *real_a = (const DBusRealString*) a;
2088   DBUS_GENERIC_STRING_PREAMBLE (real_a);
2089   _dbus_assert (c_str != NULL);
2090   
2091   c_str_len = strlen (c_str);
2092   if (((unsigned long)real_a->len) < c_str_len)
2093     return FALSE;
2094   
2095   ap = real_a->str + (real_a->len - c_str_len);
2096   bp = (const unsigned char*) c_str;
2097   a_end = real_a->str + real_a->len;
2098   while (ap != a_end)
2099     {
2100       if (*ap != *bp)
2101         return FALSE;
2102       
2103       ++ap;
2104       ++bp;
2105     }
2106
2107   _dbus_assert (*ap == '\0');
2108   _dbus_assert (*bp == '\0');
2109   
2110   return TRUE;
2111 }
2112
2113 static const signed char base64_table[] = {
2114   /* 0 */ 'A',
2115   /* 1 */ 'B',
2116   /* 2 */ 'C',
2117   /* 3 */ 'D',
2118   /* 4 */ 'E',
2119   /* 5 */ 'F',
2120   /* 6 */ 'G',
2121   /* 7 */ 'H',
2122   /* 8 */ 'I',
2123   /* 9 */ 'J',
2124   /* 10 */ 'K',
2125   /* 11 */ 'L',
2126   /* 12 */ 'M',
2127   /* 13 */ 'N',
2128   /* 14 */ 'O',
2129   /* 15 */ 'P',
2130   /* 16 */ 'Q',
2131   /* 17 */ 'R',
2132   /* 18 */ 'S',
2133   /* 19 */ 'T',
2134   /* 20 */ 'U',
2135   /* 21 */ 'V',
2136   /* 22 */ 'W',
2137   /* 23 */ 'X',
2138   /* 24 */ 'Y',
2139   /* 25 */ 'Z',
2140   /* 26 */ 'a',
2141   /* 27 */ 'b',
2142   /* 28 */ 'c',
2143   /* 29 */ 'd',
2144   /* 30 */ 'e',
2145   /* 31 */ 'f',
2146   /* 32 */ 'g',
2147   /* 33 */ 'h',
2148   /* 34 */ 'i',
2149   /* 35 */ 'j',
2150   /* 36 */ 'k',
2151   /* 37 */ 'l',
2152   /* 38 */ 'm',
2153   /* 39 */ 'n',
2154   /* 40 */ 'o',
2155   /* 41 */ 'p',
2156   /* 42 */ 'q',
2157   /* 43 */ 'r',
2158   /* 44 */ 's',
2159   /* 45 */ 't',
2160   /* 46 */ 'u',
2161   /* 47 */ 'v',
2162   /* 48 */ 'w',
2163   /* 49 */ 'x',
2164   /* 50 */ 'y',
2165   /* 51 */ 'z',
2166   /* 52 */ '0',
2167   /* 53 */ '1',
2168   /* 54 */ '2',
2169   /* 55 */ '3',
2170   /* 56 */ '4',
2171   /* 57 */ '5',
2172   /* 58 */ '6',
2173   /* 59 */ '7',
2174   /* 60 */ '8',
2175   /* 61 */ '9',
2176   /* 62 */ '+',
2177   /* 63 */ '/'
2178 };
2179
2180 /** The minimum char that's a valid char in Base64-encoded text */
2181 #define UNBASE64_MIN_CHAR (43)
2182 /** The maximum char that's a valid char in Base64-encoded text */
2183 #define UNBASE64_MAX_CHAR (122)
2184 /** Must subtract this from a char's integer value before offsetting
2185  * into unbase64_table
2186  */
2187 #define UNBASE64_TABLE_OFFSET UNBASE64_MIN_CHAR
2188 static const signed char unbase64_table[] = {
2189   /* 43 + */ 62,
2190   /* 44 , */ -1,
2191   /* 45 - */ -1,
2192   /* 46 . */ -1,
2193   /* 47 / */ 63,
2194   /* 48 0 */ 52,
2195   /* 49 1 */ 53,
2196   /* 50 2 */ 54,
2197   /* 51 3 */ 55,
2198   /* 52 4 */ 56,
2199   /* 53 5 */ 57,
2200   /* 54 6 */ 58,
2201   /* 55 7 */ 59,
2202   /* 56 8 */ 60,
2203   /* 57 9 */ 61,
2204   /* 58 : */ -1,
2205   /* 59 ; */ -1,
2206   /* 60 < */ -1,
2207   /* 61 = */ -1,
2208   /* 62 > */ -1,
2209   /* 63 ? */ -1,
2210   /* 64 @ */ -1,
2211   /* 65 A */ 0,
2212   /* 66 B */ 1,
2213   /* 67 C */ 2,
2214   /* 68 D */ 3,
2215   /* 69 E */ 4,
2216   /* 70 F */ 5,
2217   /* 71 G */ 6,
2218   /* 72 H */ 7,
2219   /* 73 I */ 8,
2220   /* 74 J */ 9,
2221   /* 75 K */ 10,
2222   /* 76 L */ 11,
2223   /* 77 M */ 12,
2224   /* 78 N */ 13,
2225   /* 79 O */ 14,
2226   /* 80 P */ 15,
2227   /* 81 Q */ 16,
2228   /* 82 R */ 17,
2229   /* 83 S */ 18,
2230   /* 84 T */ 19,
2231   /* 85 U */ 20,
2232   /* 86 V */ 21,
2233   /* 87 W */ 22,
2234   /* 88 X */ 23,
2235   /* 89 Y */ 24,
2236   /* 90 Z */ 25,
2237   /* 91 [ */ -1,
2238   /* 92 \ */ -1,
2239   /* 93 ] */ -1,
2240   /* 94 ^ */ -1,
2241   /* 95 _ */ -1,
2242   /* 96 ` */ -1,
2243   /* 97 a */ 26,
2244   /* 98 b */ 27,
2245   /* 99 c */ 28,
2246   /* 100 d */ 29,
2247   /* 101 e */ 30,
2248   /* 102 f */ 31,
2249   /* 103 g */ 32,
2250   /* 104 h */ 33,
2251   /* 105 i */ 34,
2252   /* 106 j */ 35,
2253   /* 107 k */ 36,
2254   /* 108 l */ 37,
2255   /* 109 m */ 38,
2256   /* 110 n */ 39,
2257   /* 111 o */ 40,
2258   /* 112 p */ 41,
2259   /* 113 q */ 42,
2260   /* 114 r */ 43,
2261   /* 115 s */ 44,
2262   /* 116 t */ 45,
2263   /* 117 u */ 46,
2264   /* 118 v */ 47,
2265   /* 119 w */ 48,
2266   /* 120 x */ 49,
2267   /* 121 y */ 50,
2268   /* 122 z */ 51
2269 };
2270
2271 /**
2272  * Encodes a string using Base64, as documented in RFC 2045.
2273  *
2274  * @param source the string to encode
2275  * @param start byte index to start encoding
2276  * @param dest string where encoded data should be placed
2277  * @param insert_at where to place encoded data
2278  * @returns #TRUE if encoding was successful, #FALSE if no memory etc.
2279  */
2280 dbus_bool_t
2281 _dbus_string_base64_encode (const DBusString *source,
2282                             int               start,
2283                             DBusString       *dest,
2284                             int               insert_at)
2285 {
2286   int source_len;
2287   unsigned int dest_len; /* unsigned for overflow checks below */
2288   const unsigned char *s;
2289   unsigned char *d;
2290   const unsigned char *triplet_end;
2291   const unsigned char *final_end;
2292   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);  
2293   _dbus_assert (source != dest);
2294   
2295   /* For each 24 bits (3 bytes) of input, we have 4 bytes of
2296    * output.
2297    */
2298   source_len = real_source->len - start;
2299   dest_len = (source_len / 3) * 4;
2300   if (source_len % 3 != 0)
2301     dest_len += 4;
2302
2303   if (dest_len > (unsigned int) real_dest->max_length)
2304     return FALSE;
2305   
2306   if (source_len == 0)
2307     return TRUE;
2308   
2309   if (!open_gap (dest_len, real_dest, insert_at))
2310     return FALSE;
2311
2312   d = real_dest->str + insert_at;
2313   s = real_source->str + start;
2314   final_end = real_source->str + (start + source_len);
2315   triplet_end = final_end - (source_len % 3);
2316   _dbus_assert (triplet_end <= final_end);
2317   _dbus_assert ((final_end - triplet_end) < 3);
2318
2319 #define ENCODE_64(v) (base64_table[ (unsigned char) (v) ])
2320 #define SIX_BITS_MASK (0x3f)
2321   _dbus_assert (SIX_BITS_MASK < _DBUS_N_ELEMENTS (base64_table));
2322   
2323   while (s != triplet_end)
2324     {
2325       unsigned int triplet;
2326
2327       triplet = s[2] | (s[1] << 8) | (s[0] << 16);
2328
2329       /* Encode each 6 bits. */
2330
2331       *d++ = ENCODE_64 (triplet >> 18);
2332       *d++ = ENCODE_64 ((triplet >> 12) & SIX_BITS_MASK);
2333       *d++ = ENCODE_64 ((triplet >> 6) & SIX_BITS_MASK);
2334       *d++ = ENCODE_64 (triplet & SIX_BITS_MASK);
2335       
2336       s += 3;
2337     }
2338
2339   switch (final_end - triplet_end)
2340     {
2341     case 2:
2342       {
2343         unsigned int doublet;
2344         
2345         doublet = s[1] | (s[0] << 8);        
2346
2347         *d++ = ENCODE_64 (doublet >> 12);
2348         *d++ = ENCODE_64 ((doublet >> 6) & SIX_BITS_MASK);
2349         *d++ = ENCODE_64 (doublet & SIX_BITS_MASK);
2350         *d++ = '=';
2351       }
2352       break;
2353     case 1:
2354       {
2355         unsigned int singlet;
2356         
2357         singlet = s[0];
2358
2359         *d++ = ENCODE_64 ((singlet >> 6) & SIX_BITS_MASK);
2360         *d++ = ENCODE_64 (singlet & SIX_BITS_MASK);
2361         *d++ = '=';
2362         *d++ = '=';
2363       }
2364       break;
2365     case 0:
2366       break;
2367     }
2368
2369   _dbus_assert (d == (real_dest->str + (insert_at + dest_len)));
2370
2371   return TRUE;
2372 }
2373
2374 /**
2375  * Decodes a string from Base64, as documented in RFC 2045.
2376  *
2377  * @todo sort out the AUDIT comment in here. The case it mentions
2378  * ("====" or "x===") is not allowed in correct base64, so need to
2379  * decide what to do with that kind of input. Probably ignore it
2380  * since we ignore any other junk seen.
2381  *
2382  * @param source the string to decode
2383  * @param start byte index to start decode
2384  * @param dest string where decoded data should be placed
2385  * @param insert_at where to place decoded data
2386  * @returns #TRUE if decoding was successful, #FALSE if no memory etc.
2387  */
2388 dbus_bool_t
2389 _dbus_string_base64_decode (const DBusString *source,
2390                             int               start,
2391                             DBusString       *dest,
2392                             int               insert_at)
2393 {
2394   int source_len;
2395   const char *s;
2396   const char *end;
2397   DBusString result;
2398   unsigned int triplet = 0;
2399   int sextet_count;
2400   int pad_count;
2401   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
2402   _dbus_assert (source != dest);
2403   
2404   source_len = real_source->len - start;
2405   s = real_source->str + start;
2406   end = real_source->str + source_len;
2407
2408   if (source_len == 0)
2409     return TRUE;
2410
2411   if (!_dbus_string_init (&result))
2412     return FALSE;
2413
2414   pad_count = 0;
2415   sextet_count = 0;
2416   while (s != end)
2417     {
2418       /* The idea is to just skip anything that isn't
2419        * a base64 char - it's allowed to have whitespace,
2420        * newlines, etc. in here. We also ignore trailing
2421        * base64 chars, though that's suspicious.
2422        */
2423       
2424       if (*s >= UNBASE64_MIN_CHAR &&
2425           *s <= UNBASE64_MAX_CHAR)
2426         {
2427           if (*s == '=')
2428             {
2429               /* '=' is padding, doesn't represent additional data
2430                * but does increment our count.
2431                */
2432               pad_count += 1;
2433               sextet_count += 1;
2434             }
2435           else
2436             {
2437               int val;
2438
2439               val = unbase64_table[(*s) - UNBASE64_TABLE_OFFSET];
2440
2441               if (val >= 0)
2442                 {
2443                   triplet <<= 6;
2444                   triplet |= (unsigned int) val;
2445                   sextet_count += 1;
2446                 }
2447             }
2448
2449           if (sextet_count == 4)
2450             {
2451               /* no pad = 3 bytes, 1 pad = 2 bytes, 2 pad = 1 byte */
2452
2453
2454               /* AUDIT: Comment doesn't mention 4 pad => 0,
2455                *         3 pad => 1 byte, though the code should
2456                *        work fine if those are the required outputs.
2457                *
2458                *        I assume that the spec requires dropping
2459                *        the top two bits of, say, ///= which is > 2 
2460                *        bytes worth of bits. (Or otherwise, you couldn't
2461                *        actually represent 2 byte sequences.
2462                */
2463               
2464               if (pad_count < 1)
2465                 {
2466                   if (!_dbus_string_append_byte (&result,
2467                                                  triplet >> 16))
2468                     goto failed;
2469                 }
2470               
2471               if (pad_count < 2)
2472                 {
2473                   if (!_dbus_string_append_byte (&result,
2474                                                  (triplet >> 8) & 0xff))
2475                     goto failed;
2476                 }
2477               
2478               if (!_dbus_string_append_byte (&result,
2479                                              triplet & 0xff))
2480                 goto failed;
2481               
2482               sextet_count = 0;
2483               pad_count = 0;
2484               triplet = 0;
2485             }
2486         }
2487       
2488       ++s;
2489     }
2490
2491   if (!_dbus_string_move (&result, 0, dest, insert_at))
2492     {
2493       _dbus_string_free (&result);
2494       return FALSE;
2495     }
2496
2497   _dbus_string_free (&result);
2498
2499   return TRUE;
2500
2501  failed:
2502   _dbus_string_free (&result);
2503
2504   return FALSE;
2505 }
2506
2507 /**
2508  * Encodes a string in hex, the way MD5 and SHA-1 are usually
2509  * encoded. (Each byte is two hex digits.)
2510  *
2511  * @param source the string to encode
2512  * @param start byte index to start encoding
2513  * @param dest string where encoded data should be placed
2514  * @param insert_at where to place encoded data
2515  * @returns #TRUE if encoding was successful, #FALSE if no memory etc.
2516  */
2517 dbus_bool_t
2518 _dbus_string_hex_encode (const DBusString *source,
2519                          int               start,
2520                          DBusString       *dest,
2521                          int               insert_at)
2522 {
2523   DBusString result;
2524   const char hexdigits[16] = {
2525     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
2526     'a', 'b', 'c', 'd', 'e', 'f'
2527   };
2528   const unsigned char *p;
2529   const unsigned char *end;
2530   dbus_bool_t retval;
2531   
2532   _dbus_assert (start <= _dbus_string_get_length (source));
2533
2534   if (!_dbus_string_init (&result))
2535     return FALSE;
2536
2537   retval = FALSE;
2538   
2539   p = (const unsigned char*) _dbus_string_get_const_data (source);
2540   end = p + _dbus_string_get_length (source);
2541   p += start;
2542   
2543   while (p != end)
2544     {
2545       if (!_dbus_string_append_byte (&result,
2546                                      hexdigits[(*p >> 4)]))
2547         goto out;
2548       
2549       if (!_dbus_string_append_byte (&result,
2550                                      hexdigits[(*p & 0x0f)]))
2551         goto out;
2552
2553       ++p;
2554     }
2555
2556   if (!_dbus_string_move (&result, 0, dest, insert_at))
2557     goto out;
2558
2559   retval = TRUE;
2560
2561  out:
2562   _dbus_string_free (&result);
2563   return retval;
2564 }
2565
2566 /**
2567  * Decodes a string from hex encoding.
2568  *
2569  * @param source the string to decode
2570  * @param start byte index to start decode
2571  * @param dest string where decoded data should be placed
2572  * @param insert_at where to place decoded data
2573  * @returns #TRUE if decoding was successful, #FALSE if no memory etc.
2574  */
2575 dbus_bool_t
2576 _dbus_string_hex_decode (const DBusString *source,
2577                          int               start,
2578                          DBusString       *dest,
2579                          int               insert_at)
2580 {
2581   DBusString result;
2582   const unsigned char *p;
2583   const unsigned char *end;
2584   dbus_bool_t retval;
2585   dbus_bool_t high_bits;
2586   
2587   _dbus_assert (start <= _dbus_string_get_length (source));
2588
2589   if (!_dbus_string_init (&result))
2590     return FALSE;
2591
2592   retval = FALSE;
2593
2594   high_bits = TRUE;
2595   p = (const unsigned char*) _dbus_string_get_const_data (source);
2596   end = p + _dbus_string_get_length (source);
2597   p += start;
2598   
2599   while (p != end)
2600     {
2601       unsigned int val;
2602
2603       switch (*p)
2604         {
2605         case '0':
2606           val = 0;
2607           break;
2608         case '1':
2609           val = 1;
2610           break;
2611         case '2':
2612           val = 2;
2613           break;
2614         case '3':
2615           val = 3;
2616           break;
2617         case '4':
2618           val = 4;
2619           break;
2620         case '5':
2621           val = 5;
2622           break;
2623         case '6':
2624           val = 6;
2625           break;
2626         case '7':
2627           val = 7;
2628           break;
2629         case '8':
2630           val = 8;
2631           break;
2632         case '9':
2633           val = 9;
2634           break;
2635         case 'a':
2636         case 'A':
2637           val = 10;
2638           break;
2639         case 'b':
2640         case 'B':
2641           val = 11;
2642           break;
2643         case 'c':
2644         case 'C':
2645           val = 12;
2646           break;
2647         case 'd':
2648         case 'D':
2649           val = 13;
2650           break;
2651         case 'e':
2652         case 'E':
2653           val = 14;
2654           break;
2655         case 'f':
2656         case 'F':
2657           val = 15;
2658           break;
2659         default:
2660           val = 0;
2661           _dbus_verbose ("invalid character '%c' in hex encoded text\n",
2662                          *p);
2663           goto out;
2664         }
2665
2666       if (high_bits)
2667         {
2668           if (!_dbus_string_append_byte (&result,
2669                                          val << 4))
2670             goto out;
2671         }
2672       else
2673         {
2674           int len;
2675           unsigned char b;
2676
2677           len = _dbus_string_get_length (&result);
2678           
2679           b = _dbus_string_get_byte (&result, len - 1);
2680
2681           b |= val;
2682
2683           _dbus_string_set_byte (&result, len - 1, b);
2684         }
2685
2686       high_bits = !high_bits;
2687
2688       ++p;
2689     }
2690
2691   if (!_dbus_string_move (&result, 0, dest, insert_at))
2692     goto out;
2693
2694   retval = TRUE;
2695   
2696  out:
2697   _dbus_string_free (&result);  
2698   return retval;
2699 }
2700
2701 /**
2702  * Checks that the given range of the string is valid ASCII with no
2703  * nul bytes. If the given range is not entirely contained in the
2704  * string, returns #FALSE.
2705  *
2706  * @todo this is inconsistent with most of DBusString in that
2707  * it allows a start,len range that isn't in the string.
2708  * 
2709  * @param str the string
2710  * @param start first byte index to check
2711  * @param len number of bytes to check
2712  * @returns #TRUE if the byte range exists and is all valid ASCII
2713  */
2714 dbus_bool_t
2715 _dbus_string_validate_ascii (const DBusString *str,
2716                              int               start,
2717                              int               len)
2718 {
2719   const unsigned char *s;
2720   const unsigned char *end;
2721   DBUS_CONST_STRING_PREAMBLE (str);
2722   _dbus_assert (start >= 0);
2723   _dbus_assert (start <= real->len);
2724   _dbus_assert (len >= 0);
2725   
2726   if (len > real->len - start)
2727     return FALSE;
2728   
2729   s = real->str + start;
2730   end = s + len;
2731   while (s != end)
2732     {
2733       if (_DBUS_UNLIKELY (*s == '\0' ||
2734                           ((*s & ~0x7f) != 0)))
2735         return FALSE;
2736         
2737       ++s;
2738     }
2739   
2740   return TRUE;
2741 }
2742
2743 /**
2744  * Checks that the given range of the string is valid UTF-8. If the
2745  * given range is not entirely contained in the string, returns
2746  * #FALSE. If the string contains any nul bytes in the given range,
2747  * returns #FALSE. If the start and start+len are not on character
2748  * boundaries, returns #FALSE.
2749  *
2750  * @todo this is inconsistent with most of DBusString in that
2751  * it allows a start,len range that isn't in the string.
2752  * 
2753  * @param str the string
2754  * @param start first byte index to check
2755  * @param len number of bytes to check
2756  * @returns #TRUE if the byte range exists and is all valid UTF-8
2757  */
2758 dbus_bool_t
2759 _dbus_string_validate_utf8  (const DBusString *str,
2760                              int               start,
2761                              int               len)
2762 {
2763   const unsigned char *p;
2764   const unsigned char *end;
2765   DBUS_CONST_STRING_PREAMBLE (str);
2766   _dbus_assert (start >= 0);
2767   _dbus_assert (start <= real->len);
2768   _dbus_assert (len >= 0);
2769
2770   /* we are doing _DBUS_UNLIKELY() here which might be
2771    * dubious in a generic library like GLib, but in D-BUS
2772    * we know we're validating messages and that it would
2773    * only be evil/broken apps that would have invalid
2774    * UTF-8. Also, this function seems to be a performance
2775    * bottleneck in profiles.
2776    */
2777   
2778   if (_DBUS_UNLIKELY (len > real->len - start))
2779     return FALSE;
2780   
2781   p = real->str + start;
2782   end = p + len;
2783   
2784   while (p < end)
2785     {
2786       int i, mask = 0, char_len;
2787       dbus_unichar_t result;
2788       unsigned char c = (unsigned char) *p;
2789       
2790       UTF8_COMPUTE (c, mask, char_len);
2791
2792       if (_DBUS_UNLIKELY (char_len == -1))
2793         break;
2794
2795       /* check that the expected number of bytes exists in the remaining length */
2796       if (_DBUS_UNLIKELY ((end - p) < char_len))
2797         break;
2798         
2799       UTF8_GET (result, p, i, mask, char_len);
2800
2801       if (_DBUS_UNLIKELY (UTF8_LENGTH (result) != char_len)) /* Check for overlong UTF-8 */
2802         break;
2803
2804       if (_DBUS_UNLIKELY (result == (dbus_unichar_t)-1))
2805         break;
2806
2807       if (_DBUS_UNLIKELY (!UNICODE_VALID (result)))
2808         break;
2809       
2810       p += char_len;
2811     }
2812
2813   /* See that we covered the entire length if a length was
2814    * passed in
2815    */
2816   if (_DBUS_UNLIKELY (p != end))
2817     return FALSE;
2818   else
2819     return TRUE;
2820 }
2821
2822 /**
2823  * Checks that the given range of the string is all nul bytes. If the
2824  * given range is not entirely contained in the string, returns
2825  * #FALSE.
2826  *
2827  * @todo this is inconsistent with most of DBusString in that
2828  * it allows a start,len range that isn't in the string.
2829  * 
2830  * @param str the string
2831  * @param start first byte index to check
2832  * @param len number of bytes to check
2833  * @returns #TRUE if the byte range exists and is all nul bytes
2834  */
2835 dbus_bool_t
2836 _dbus_string_validate_nul (const DBusString *str,
2837                            int               start,
2838                            int               len)
2839 {
2840   const unsigned char *s;
2841   const unsigned char *end;
2842   DBUS_CONST_STRING_PREAMBLE (str);
2843   _dbus_assert (start >= 0);
2844   _dbus_assert (len >= 0);
2845   _dbus_assert (start <= real->len);
2846   
2847   if (len > real->len - start)
2848     return FALSE;
2849   
2850   s = real->str + start;
2851   end = s + len;
2852   while (s != end)
2853     {
2854       if (_DBUS_UNLIKELY (*s != '\0'))
2855         return FALSE;
2856       ++s;
2857     }
2858   
2859   return TRUE;
2860 }
2861
2862 /**
2863  * Checks that the given range of the string is a valid object path
2864  * name in the D-BUS protocol. This includes a length restriction,
2865  * etc., see the specification. It does not validate UTF-8, that has
2866  * to be done separately for now.
2867  *
2868  * @todo this is inconsistent with most of DBusString in that
2869  * it allows a start,len range that isn't in the string.
2870  *
2871  * @todo change spec to disallow more things, such as spaces in the
2872  * path name
2873  * 
2874  * @param str the string
2875  * @param start first byte index to check
2876  * @param len number of bytes to check
2877  * @returns #TRUE if the byte range exists and is a valid name
2878  */
2879 dbus_bool_t
2880 _dbus_string_validate_path (const DBusString  *str,
2881                             int                start,
2882                             int                len)
2883 {
2884   const unsigned char *s;
2885   const unsigned char *end;
2886   const unsigned char *last_slash;
2887   
2888   DBUS_CONST_STRING_PREAMBLE (str);
2889   _dbus_assert (start >= 0);
2890   _dbus_assert (len >= 0);
2891   _dbus_assert (start <= real->len);
2892   
2893   if (len > real->len - start)
2894     return FALSE;
2895
2896   if (len > DBUS_MAXIMUM_NAME_LENGTH)
2897     return FALSE;
2898
2899   if (len == 0)
2900     return FALSE;
2901
2902   s = real->str + start;
2903   end = s + len;
2904
2905   if (*s != '/')
2906     return FALSE;
2907   last_slash = s;
2908   ++s;
2909   
2910   while (s != end)
2911     {
2912       if (*s == '/')
2913         {
2914           if ((s - last_slash) < 2)
2915             return FALSE; /* no empty path components allowed */
2916
2917           last_slash = s;
2918         }
2919       
2920       ++s;
2921     }
2922
2923   if ((end - last_slash) < 2 &&
2924       len > 1)
2925     return FALSE; /* trailing slash not allowed unless the string is "/" */
2926   
2927   return TRUE;
2928 }
2929
2930 #define VALID_INITIAL_NAME_CHARACTER(c)         \
2931   ( ((c) >= 'A' && (c) <= 'Z') ||               \
2932     ((c) >= 'a' && (c) <= 'z') ||               \
2933     ((c) == '_') )
2934
2935 #define VALID_NAME_CHARACTER(c)                 \
2936   ( ((c) >= '0' && (c) <= '9') ||               \
2937     ((c) >= 'A' && (c) <= 'Z') ||               \
2938     ((c) >= 'a' && (c) <= 'z') ||               \
2939     ((c) == '_') )
2940
2941 /**
2942  * Checks that the given range of the string is a valid interface name
2943  * in the D-BUS protocol. This includes a length restriction and an
2944  * ASCII subset, see the specification.
2945  *
2946  * @todo this is inconsistent with most of DBusString in that
2947  * it allows a start,len range that isn't in the string.
2948  * 
2949  * @param str the string
2950  * @param start first byte index to check
2951  * @param len number of bytes to check
2952  * @returns #TRUE if the byte range exists and is a valid name
2953  */
2954 dbus_bool_t
2955 _dbus_string_validate_interface (const DBusString  *str,
2956                                  int                start,
2957                                  int                len)
2958 {  
2959   const unsigned char *s;
2960   const unsigned char *end;
2961   const unsigned char *iface;
2962   const unsigned char *last_dot;
2963   
2964   DBUS_CONST_STRING_PREAMBLE (str);
2965   _dbus_assert (start >= 0);
2966   _dbus_assert (len >= 0);
2967   _dbus_assert (start <= real->len);
2968   
2969   if (len > real->len - start)
2970     return FALSE;
2971
2972   if (len > DBUS_MAXIMUM_NAME_LENGTH)
2973     return FALSE;
2974
2975   if (len == 0)
2976     return FALSE;
2977
2978   last_dot = NULL;
2979   iface = real->str + start;
2980   end = iface + len;
2981   s = iface;
2982
2983   /* check special cases of first char so it doesn't have to be done
2984    * in the loop. Note we know len > 0
2985    */
2986   if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
2987     return FALSE;
2988   else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
2989     return FALSE;
2990   else
2991     ++s;
2992   
2993   while (s != end)
2994     {
2995       if (*s == '.')
2996         {
2997           if (_DBUS_UNLIKELY ((s + 1) == end))
2998             return FALSE;
2999           else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1))))
3000             return FALSE;
3001           last_dot = s;
3002           ++s; /* we just validated the next char, so skip two */
3003         }
3004       else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
3005         {
3006           return FALSE;
3007         }
3008       
3009       ++s;
3010     }
3011
3012   if (_DBUS_UNLIKELY (last_dot == NULL))
3013     return FALSE;
3014   
3015   return TRUE;
3016 }
3017
3018 /**
3019  * Checks that the given range of the string is a valid member name
3020  * in the D-BUS protocol. This includes a length restriction, etc.,
3021  * see the specification.
3022  *
3023  * @todo this is inconsistent with most of DBusString in that
3024  * it allows a start,len range that isn't in the string.
3025  * 
3026  * @param str the string
3027  * @param start first byte index to check
3028  * @param len number of bytes to check
3029  * @returns #TRUE if the byte range exists and is a valid name
3030  */
3031 dbus_bool_t
3032 _dbus_string_validate_member (const DBusString  *str,
3033                               int                start,
3034                               int                len)
3035 {
3036   const unsigned char *s;
3037   const unsigned char *end;
3038   const unsigned char *member;
3039   
3040   DBUS_CONST_STRING_PREAMBLE (str);
3041   _dbus_assert (start >= 0);
3042   _dbus_assert (len >= 0);
3043   _dbus_assert (start <= real->len);
3044   
3045   if (len > real->len - start)
3046     return FALSE;
3047
3048   if (len > DBUS_MAXIMUM_NAME_LENGTH)
3049     return FALSE;
3050
3051   if (len == 0)
3052     return FALSE;
3053
3054   member = real->str + start;
3055   end = member + len;
3056   s = member;
3057
3058   /* check special cases of first char so it doesn't have to be done
3059    * in the loop. Note we know len > 0
3060    */
3061
3062   if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
3063     return FALSE;
3064   else
3065     ++s;
3066   
3067   while (s != end)
3068     {
3069       if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
3070         {
3071           return FALSE;
3072         }
3073       
3074       ++s;
3075     }
3076   
3077   return TRUE;
3078 }
3079
3080 /**
3081  * Checks that the given range of the string is a valid error name
3082  * in the D-BUS protocol. This includes a length restriction, etc.,
3083  * see the specification.
3084  *
3085  * @todo this is inconsistent with most of DBusString in that
3086  * it allows a start,len range that isn't in the string.
3087  * 
3088  * @param str the string
3089  * @param start first byte index to check
3090  * @param len number of bytes to check
3091  * @returns #TRUE if the byte range exists and is a valid name
3092  */
3093 dbus_bool_t
3094 _dbus_string_validate_error_name (const DBusString  *str,
3095                                   int                start,
3096                                   int                len)
3097 {
3098   /* Same restrictions as interface name at the moment */
3099   return _dbus_string_validate_interface (str, start, len);
3100 }
3101
3102 /* This assumes the first char exists and is ':' */
3103 static dbus_bool_t
3104 _dbus_string_validate_base_service (const DBusString  *str,
3105                                     int                start,
3106                                     int                len)
3107 {
3108   const unsigned char *s;
3109   const unsigned char *end;
3110   const unsigned char *service;
3111   
3112   DBUS_CONST_STRING_PREAMBLE (str);
3113   _dbus_assert (start >= 0);
3114   _dbus_assert (len >= 0);
3115   _dbus_assert (start <= real->len);
3116   
3117   if (len > real->len - start)
3118     return FALSE;
3119
3120   if (len > DBUS_MAXIMUM_NAME_LENGTH)
3121     return FALSE;
3122
3123   _dbus_assert (len > 0);
3124
3125   service = real->str + start;
3126   end = service + len;
3127   _dbus_assert (*service == ':');
3128   s = service + 1;
3129   
3130   while (s != end)
3131     {
3132       if (*s == '.')
3133         {
3134           if (_DBUS_UNLIKELY ((s + 1) == end))
3135             return FALSE;
3136           if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*(s + 1))))
3137             return FALSE;
3138           ++s; /* we just validated the next char, so skip two */
3139         }
3140       else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
3141         {
3142           return FALSE;
3143         }
3144       
3145       ++s;
3146     }
3147   
3148   return TRUE;
3149 }
3150
3151 /**
3152  * Checks that the given range of the string is a valid service name
3153  * in the D-BUS protocol. This includes a length restriction, etc.,
3154  * see the specification.
3155  *
3156  * @todo this is inconsistent with most of DBusString in that
3157  * it allows a start,len range that isn't in the string.
3158  * 
3159  * @param str the string
3160  * @param start first byte index to check
3161  * @param len number of bytes to check
3162  * @returns #TRUE if the byte range exists and is a valid name
3163  */
3164 dbus_bool_t
3165 _dbus_string_validate_service (const DBusString  *str,
3166                                int                start,
3167                                int                len)
3168 {
3169   if (_DBUS_UNLIKELY (len == 0))
3170     return FALSE;
3171   if (_dbus_string_get_byte (str, start) == ':')
3172     return _dbus_string_validate_base_service (str, start, len);
3173   else
3174     return _dbus_string_validate_interface (str, start, len);
3175 }
3176
3177 /**
3178  * Clears all allocated bytes in the string to zero.
3179  *
3180  * @param str the string
3181  */
3182 void
3183 _dbus_string_zero (DBusString *str)
3184 {
3185   DBUS_STRING_PREAMBLE (str);
3186
3187   memset (real->str - real->align_offset, '\0', real->allocated);
3188 }
3189 /** @} */
3190
3191 #ifdef DBUS_BUILD_TESTS
3192 #include "dbus-test.h"
3193 #include <stdio.h>
3194
3195 static void
3196 test_max_len (DBusString *str,
3197               int         max_len)
3198 {
3199   if (max_len > 0)
3200     {
3201       if (!_dbus_string_set_length (str, max_len - 1))
3202         _dbus_assert_not_reached ("setting len to one less than max should have worked");
3203     }
3204
3205   if (!_dbus_string_set_length (str, max_len))
3206     _dbus_assert_not_reached ("setting len to max len should have worked");
3207
3208   if (_dbus_string_set_length (str, max_len + 1))
3209     _dbus_assert_not_reached ("setting len to one more than max len should not have worked");
3210
3211   if (!_dbus_string_set_length (str, 0))
3212     _dbus_assert_not_reached ("setting len to zero should have worked");
3213 }
3214
3215 static void
3216 test_base64_roundtrip (const unsigned char *data,
3217                        int                  len)
3218 {
3219   DBusString orig;
3220   DBusString encoded;
3221   DBusString decoded;
3222
3223   if (len < 0)
3224     len = strlen (data);
3225   
3226   if (!_dbus_string_init (&orig))
3227     _dbus_assert_not_reached ("could not init string");
3228
3229   if (!_dbus_string_init (&encoded))
3230     _dbus_assert_not_reached ("could not init string");
3231   
3232   if (!_dbus_string_init (&decoded))
3233     _dbus_assert_not_reached ("could not init string");
3234
3235   if (!_dbus_string_append_len (&orig, data, len))
3236     _dbus_assert_not_reached ("couldn't append orig data");
3237
3238   if (!_dbus_string_base64_encode (&orig, 0, &encoded, 0))
3239     _dbus_assert_not_reached ("could not encode");
3240
3241   if (!_dbus_string_base64_decode (&encoded, 0, &decoded, 0))
3242     _dbus_assert_not_reached ("could not decode");
3243
3244   if (!_dbus_string_equal (&orig, &decoded))
3245     {
3246       const char *s;
3247       
3248       printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n",
3249               _dbus_string_get_length (&orig),
3250               _dbus_string_get_length (&encoded),
3251               _dbus_string_get_length (&decoded));
3252       printf ("Original: %s\n", data);
3253       s = _dbus_string_get_const_data (&decoded);
3254       printf ("Decoded: %s\n", s);
3255       _dbus_assert_not_reached ("original string not the same as string decoded from base64");
3256     }
3257   
3258   _dbus_string_free (&orig);
3259   _dbus_string_free (&encoded);
3260   _dbus_string_free (&decoded);  
3261 }
3262
3263 static void
3264 test_hex_roundtrip (const unsigned char *data,
3265                     int                  len)
3266 {
3267   DBusString orig;
3268   DBusString encoded;
3269   DBusString decoded;
3270
3271   if (len < 0)
3272     len = strlen (data);
3273   
3274   if (!_dbus_string_init (&orig))
3275     _dbus_assert_not_reached ("could not init string");
3276
3277   if (!_dbus_string_init (&encoded))
3278     _dbus_assert_not_reached ("could not init string");
3279   
3280   if (!_dbus_string_init (&decoded))
3281     _dbus_assert_not_reached ("could not init string");
3282
3283   if (!_dbus_string_append_len (&orig, data, len))
3284     _dbus_assert_not_reached ("couldn't append orig data");
3285
3286   if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0))
3287     _dbus_assert_not_reached ("could not encode");
3288
3289   if (!_dbus_string_hex_decode (&encoded, 0, &decoded, 0))
3290     _dbus_assert_not_reached ("could not decode");
3291     
3292   if (!_dbus_string_equal (&orig, &decoded))
3293     {
3294       const char *s;
3295       
3296       printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n",
3297               _dbus_string_get_length (&orig),
3298               _dbus_string_get_length (&encoded),
3299               _dbus_string_get_length (&decoded));
3300       printf ("Original: %s\n", data);
3301       s = _dbus_string_get_const_data (&decoded);
3302       printf ("Decoded: %s\n", s);
3303       _dbus_assert_not_reached ("original string not the same as string decoded from base64");
3304     }
3305   
3306   _dbus_string_free (&orig);
3307   _dbus_string_free (&encoded);
3308   _dbus_string_free (&decoded);  
3309 }
3310
3311 typedef void (* TestRoundtripFunc) (const unsigned char *data,
3312                                     int                  len);
3313 static void
3314 test_roundtrips (TestRoundtripFunc func)
3315 {
3316   (* func) ("Hello this is a string\n", -1);
3317   (* func) ("Hello this is a string\n1", -1);
3318   (* func) ("Hello this is a string\n12", -1);
3319   (* func) ("Hello this is a string\n123", -1);
3320   (* func) ("Hello this is a string\n1234", -1);
3321   (* func) ("Hello this is a string\n12345", -1);
3322   (* func) ("", 0);
3323   (* func) ("1", 1);
3324   (* func) ("12", 2);
3325   (* func) ("123", 3);
3326   (* func) ("1234", 4);
3327   (* func) ("12345", 5);
3328   (* func) ("", 1);
3329   (* func) ("1", 2);
3330   (* func) ("12", 3);
3331   (* func) ("123", 4);
3332   (* func) ("1234", 5);
3333   (* func) ("12345", 6);
3334   {
3335     unsigned char buf[512];
3336     int i;
3337     
3338     i = 0;
3339     while (i < _DBUS_N_ELEMENTS (buf))
3340       {
3341         buf[i] = i;
3342         ++i;
3343       }
3344     i = 0;
3345     while (i < _DBUS_N_ELEMENTS (buf))
3346       {
3347         (* func) (buf, i);
3348         ++i;
3349       }
3350   }
3351 }
3352
3353
3354 /**
3355  * @ingroup DBusStringInternals
3356  * Unit test for DBusString.
3357  *
3358  * @todo Need to write tests for _dbus_string_copy() and
3359  * _dbus_string_move() moving to/from each of start/middle/end of a
3360  * string. Also need tests for _dbus_string_move_len ()
3361  * 
3362  * @returns #TRUE on success.
3363  */
3364 dbus_bool_t
3365 _dbus_string_test (void)
3366 {
3367   DBusString str;
3368   DBusString other;
3369   int i, end;
3370   long v;
3371   double d;
3372   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 };
3373   char *s;
3374   dbus_unichar_t ch;
3375   const char *valid_paths[] = {
3376     "/",
3377     "/foo/bar",
3378     "/foo",
3379     "/foo/bar/baz"
3380   };
3381   const char *invalid_paths[] = {
3382     "bar",
3383     "bar/baz",
3384     "/foo/bar/",
3385     "/foo/"
3386     "foo/",
3387     "boo//blah",
3388     "//",
3389     "///",
3390     "foo///blah/",
3391     "Hello World",
3392     "",
3393     "   ",
3394     "foo bar"
3395   };
3396
3397   const char *valid_interfaces[] = {
3398     "org.freedesktop.Foo",
3399     "Bar.Baz",
3400     "Blah.Blah.Blah.Blah.Blah",
3401     "a.b",
3402     "a.b.c.d.e.f.g",
3403     "a0.b1.c2.d3.e4.f5.g6",
3404     "abc123.foo27"
3405   };
3406   const char *invalid_interfaces[] = {
3407     ".",
3408     "",
3409     "..",
3410     ".Foo.Bar",
3411     "..Foo.Bar",
3412     "Foo.Bar.",
3413     "Foo.Bar..",
3414     "Foo",
3415     "9foo.bar.baz",
3416     "foo.bar..baz",
3417     "foo.bar...baz",
3418     "foo.bar.b..blah",
3419     ":",
3420     ":0-1",
3421     "10",
3422     ":11.34324",
3423     "0.0.0",
3424     "0..0",
3425     "foo.Bar.%",
3426     "foo.Bar!!",
3427     "!Foo.bar.bz",
3428     "foo.$.blah",
3429     "",
3430     "   ",
3431     "foo bar"
3432   };
3433
3434   const char *valid_base_services[] = {
3435     ":0",
3436     ":a",
3437     ":",
3438     ":.a",
3439     ":.1",
3440     ":0.1",
3441     ":000.2222",
3442     ":.blah",
3443     ":abce.freedesktop.blah"
3444   };
3445   const char *invalid_base_services[] = {
3446     ":-",
3447     ":!",
3448     ":0-10",
3449     ":blah.",
3450     ":blah.",
3451     ":blah..org",
3452     ":blah.org..",
3453     ":..blah.org",
3454     "",
3455     "   ",
3456     "foo bar"
3457   };
3458
3459   const char *valid_members[] = {
3460     "Hello",
3461     "Bar",
3462     "foobar",
3463     "_foobar",
3464     "foo89"
3465   };
3466
3467   const char *invalid_members[] = {
3468     "9Hello",
3469     "10",
3470     "1",
3471     "foo-bar",
3472     "blah.org",
3473     ".blah",
3474     "blah.",
3475     "Hello.",
3476     "!foo",
3477     "",
3478     "   ",
3479     "foo bar"
3480   };
3481   
3482   i = 0;
3483   while (i < _DBUS_N_ELEMENTS (lens))
3484     {
3485       if (!_dbus_string_init (&str))
3486         _dbus_assert_not_reached ("failed to init string");
3487
3488       set_max_length (&str, lens[i]);
3489       
3490       test_max_len (&str, lens[i]);
3491       _dbus_string_free (&str);
3492
3493       ++i;
3494     }
3495
3496   /* Test shortening and setting length */
3497   i = 0;
3498   while (i < _DBUS_N_ELEMENTS (lens))
3499     {
3500       int j;
3501       
3502       if (!_dbus_string_init (&str))
3503         _dbus_assert_not_reached ("failed to init string");
3504
3505       set_max_length (&str, lens[i]);
3506       
3507       if (!_dbus_string_set_length (&str, lens[i]))
3508         _dbus_assert_not_reached ("failed to set string length");
3509
3510       j = lens[i];
3511       while (j > 0)
3512         {
3513           _dbus_assert (_dbus_string_get_length (&str) == j);
3514           if (j > 0)
3515             {
3516               _dbus_string_shorten (&str, 1);
3517               _dbus_assert (_dbus_string_get_length (&str) == (j - 1));
3518             }
3519           --j;
3520         }
3521       
3522       _dbus_string_free (&str);
3523
3524       ++i;
3525     }
3526
3527   /* Test appending data */
3528   if (!_dbus_string_init (&str))
3529     _dbus_assert_not_reached ("failed to init string");
3530
3531   i = 0;
3532   while (i < 10)
3533     {
3534       if (!_dbus_string_append (&str, "a"))
3535         _dbus_assert_not_reached ("failed to append string to string\n");
3536
3537       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1);
3538
3539       if (!_dbus_string_append_byte (&str, 'b'))
3540         _dbus_assert_not_reached ("failed to append byte to string\n");
3541
3542       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2);
3543                     
3544       ++i;
3545     }
3546
3547   _dbus_string_free (&str);
3548
3549   /* Check steal_data */
3550   
3551   if (!_dbus_string_init (&str))
3552     _dbus_assert_not_reached ("failed to init string");
3553
3554   if (!_dbus_string_append (&str, "Hello World"))
3555     _dbus_assert_not_reached ("could not append to string");
3556
3557   i = _dbus_string_get_length (&str);
3558   
3559   if (!_dbus_string_steal_data (&str, &s))
3560     _dbus_assert_not_reached ("failed to steal data");
3561
3562   _dbus_assert (_dbus_string_get_length (&str) == 0);
3563   _dbus_assert (((int)strlen (s)) == i);
3564
3565   dbus_free (s);
3566
3567   /* Check move */
3568   
3569   if (!_dbus_string_append (&str, "Hello World"))
3570     _dbus_assert_not_reached ("could not append to string");
3571
3572   i = _dbus_string_get_length (&str);
3573
3574   if (!_dbus_string_init (&other))
3575     _dbus_assert_not_reached ("could not init string");
3576   
3577   if (!_dbus_string_move (&str, 0, &other, 0))
3578     _dbus_assert_not_reached ("could not move");
3579
3580   _dbus_assert (_dbus_string_get_length (&str) == 0);
3581   _dbus_assert (_dbus_string_get_length (&other) == i);
3582
3583   if (!_dbus_string_append (&str, "Hello World"))
3584     _dbus_assert_not_reached ("could not append to string");
3585   
3586   if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other)))
3587     _dbus_assert_not_reached ("could not move");
3588
3589   _dbus_assert (_dbus_string_get_length (&str) == 0);
3590   _dbus_assert (_dbus_string_get_length (&other) == i * 2);
3591
3592     if (!_dbus_string_append (&str, "Hello World"))
3593     _dbus_assert_not_reached ("could not append to string");
3594   
3595   if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2))
3596     _dbus_assert_not_reached ("could not move");
3597
3598   _dbus_assert (_dbus_string_get_length (&str) == 0);
3599   _dbus_assert (_dbus_string_get_length (&other) == i * 3);
3600   
3601   _dbus_string_free (&other);
3602
3603   /* Check copy */
3604   
3605   if (!_dbus_string_append (&str, "Hello World"))
3606     _dbus_assert_not_reached ("could not append to string");
3607
3608   i = _dbus_string_get_length (&str);
3609   
3610   if (!_dbus_string_init (&other))
3611     _dbus_assert_not_reached ("could not init string");
3612   
3613   if (!_dbus_string_copy (&str, 0, &other, 0))
3614     _dbus_assert_not_reached ("could not copy");
3615
3616   _dbus_assert (_dbus_string_get_length (&str) == i);
3617   _dbus_assert (_dbus_string_get_length (&other) == i);
3618
3619   if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other)))
3620     _dbus_assert_not_reached ("could not copy");
3621
3622   _dbus_assert (_dbus_string_get_length (&str) == i);
3623   _dbus_assert (_dbus_string_get_length (&other) == i * 2);
3624   _dbus_assert (_dbus_string_equal_c_str (&other,
3625                                           "Hello WorldHello World"));
3626
3627   if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2))
3628     _dbus_assert_not_reached ("could not copy");
3629
3630   _dbus_assert (_dbus_string_get_length (&str) == i);
3631   _dbus_assert (_dbus_string_get_length (&other) == i * 3);
3632   _dbus_assert (_dbus_string_equal_c_str (&other,
3633                                           "Hello WorldHello WorldHello World"));
3634   
3635   _dbus_string_free (&str);
3636   _dbus_string_free (&other);
3637
3638   /* Check replace */
3639
3640   if (!_dbus_string_init (&str))
3641     _dbus_assert_not_reached ("failed to init string");
3642   
3643   if (!_dbus_string_append (&str, "Hello World"))
3644     _dbus_assert_not_reached ("could not append to string");
3645
3646   i = _dbus_string_get_length (&str);
3647   
3648   if (!_dbus_string_init (&other))
3649     _dbus_assert_not_reached ("could not init string");
3650   
3651   if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
3652                                  &other, 0, _dbus_string_get_length (&other)))
3653     _dbus_assert_not_reached ("could not replace");
3654
3655   _dbus_assert (_dbus_string_get_length (&str) == i);
3656   _dbus_assert (_dbus_string_get_length (&other) == i);
3657   _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World"));
3658   
3659   if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
3660                                  &other, 5, 1))
3661     _dbus_assert_not_reached ("could not replace center space");
3662
3663   _dbus_assert (_dbus_string_get_length (&str) == i);
3664   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
3665   _dbus_assert (_dbus_string_equal_c_str (&other,
3666                                           "HelloHello WorldWorld"));
3667
3668   
3669   if (!_dbus_string_replace_len (&str, 1, 1,
3670                                  &other,
3671                                  _dbus_string_get_length (&other) - 1,
3672                                  1))
3673     _dbus_assert_not_reached ("could not replace end character");
3674   
3675   _dbus_assert (_dbus_string_get_length (&str) == i);
3676   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
3677   _dbus_assert (_dbus_string_equal_c_str (&other,
3678                                           "HelloHello WorldWorle"));
3679   
3680   _dbus_string_free (&str);
3681   _dbus_string_free (&other);
3682   
3683   /* Check append/get unichar */
3684   
3685   if (!_dbus_string_init (&str))
3686     _dbus_assert_not_reached ("failed to init string");
3687
3688   ch = 0;
3689   if (!_dbus_string_append_unichar (&str, 0xfffc))
3690     _dbus_assert_not_reached ("failed to append unichar");
3691
3692   _dbus_string_get_unichar (&str, 0, &ch, &i);
3693
3694   _dbus_assert (ch == 0xfffc);
3695   _dbus_assert (i == _dbus_string_get_length (&str));
3696
3697   _dbus_string_free (&str);
3698
3699   /* Check insert/set/get byte */
3700   
3701   if (!_dbus_string_init (&str))
3702     _dbus_assert_not_reached ("failed to init string");
3703
3704   if (!_dbus_string_append (&str, "Hello"))
3705     _dbus_assert_not_reached ("failed to append Hello");
3706
3707   _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H');
3708   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e');
3709   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l');
3710   _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l');
3711   _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o');
3712
3713   _dbus_string_set_byte (&str, 1, 'q');
3714   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q');
3715
3716   if (!_dbus_string_insert_bytes (&str, 0, 1, 255))
3717     _dbus_assert_not_reached ("can't insert byte");
3718
3719   if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z'))
3720     _dbus_assert_not_reached ("can't insert byte");
3721
3722   if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W'))
3723     _dbus_assert_not_reached ("can't insert byte");
3724   
3725   _dbus_assert (_dbus_string_get_byte (&str, 0) == 255);
3726   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H');
3727   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z');
3728   _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z');
3729   _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z');
3730   _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z');
3731   _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q');
3732   _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l');
3733   _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l');
3734   _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o');
3735   _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W');
3736
3737   _dbus_string_free (&str);
3738   
3739   /* Check append/parse int/double */
3740   
3741   if (!_dbus_string_init (&str))
3742     _dbus_assert_not_reached ("failed to init string");
3743
3744   if (!_dbus_string_append_int (&str, 27))
3745     _dbus_assert_not_reached ("failed to append int");
3746
3747   i = _dbus_string_get_length (&str);
3748
3749   if (!_dbus_string_parse_int (&str, 0, &v, &end))
3750     _dbus_assert_not_reached ("failed to parse int");
3751
3752   _dbus_assert (v == 27);
3753   _dbus_assert (end == i);
3754
3755   _dbus_string_free (&str);
3756   
3757   if (!_dbus_string_init (&str))
3758     _dbus_assert_not_reached ("failed to init string");
3759   
3760   if (!_dbus_string_append_double (&str, 50.3))
3761     _dbus_assert_not_reached ("failed to append float");
3762
3763   i = _dbus_string_get_length (&str);
3764
3765   if (!_dbus_string_parse_double (&str, 0, &d, &end))
3766     _dbus_assert_not_reached ("failed to parse float");
3767
3768   _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6));
3769   _dbus_assert (end == i);
3770
3771   _dbus_string_free (&str);
3772
3773   /* Test find */
3774   if (!_dbus_string_init (&str))
3775     _dbus_assert_not_reached ("failed to init string");
3776
3777   if (!_dbus_string_append (&str, "Hello"))
3778     _dbus_assert_not_reached ("couldn't append to string");
3779   
3780   if (!_dbus_string_find (&str, 0, "He", &i))
3781     _dbus_assert_not_reached ("didn't find 'He'");
3782   _dbus_assert (i == 0);
3783
3784   if (!_dbus_string_find (&str, 0, "Hello", &i))
3785     _dbus_assert_not_reached ("didn't find 'Hello'");
3786   _dbus_assert (i == 0);
3787   
3788   if (!_dbus_string_find (&str, 0, "ello", &i))
3789     _dbus_assert_not_reached ("didn't find 'ello'");
3790   _dbus_assert (i == 1);
3791
3792   if (!_dbus_string_find (&str, 0, "lo", &i))
3793     _dbus_assert_not_reached ("didn't find 'lo'");
3794   _dbus_assert (i == 3);
3795
3796   if (!_dbus_string_find (&str, 2, "lo", &i))
3797     _dbus_assert_not_reached ("didn't find 'lo'");
3798   _dbus_assert (i == 3);
3799
3800   if (_dbus_string_find (&str, 4, "lo", &i))
3801     _dbus_assert_not_reached ("did find 'lo'");
3802   
3803   if (!_dbus_string_find (&str, 0, "l", &i))
3804     _dbus_assert_not_reached ("didn't find 'l'");
3805   _dbus_assert (i == 2);
3806
3807   if (!_dbus_string_find (&str, 0, "H", &i))
3808     _dbus_assert_not_reached ("didn't find 'H'");
3809   _dbus_assert (i == 0);
3810
3811   if (!_dbus_string_find (&str, 0, "", &i))
3812     _dbus_assert_not_reached ("didn't find ''");
3813   _dbus_assert (i == 0);
3814   
3815   if (_dbus_string_find (&str, 0, "Hello!", NULL))
3816     _dbus_assert_not_reached ("Did find 'Hello!'");
3817
3818   if (_dbus_string_find (&str, 0, "Oh, Hello", NULL))
3819     _dbus_assert_not_reached ("Did find 'Oh, Hello'");
3820   
3821   if (_dbus_string_find (&str, 0, "ill", NULL))
3822     _dbus_assert_not_reached ("Did find 'ill'");
3823
3824   if (_dbus_string_find (&str, 0, "q", NULL))
3825     _dbus_assert_not_reached ("Did find 'q'");
3826
3827   if (!_dbus_string_find_to (&str, 0, 2, "He", NULL))
3828     _dbus_assert_not_reached ("Didn't find 'He'");
3829
3830   if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL))
3831     _dbus_assert_not_reached ("Did find 'Hello'");
3832
3833   if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'H', &i))
3834     _dbus_assert_not_reached ("Did not find 'H'");
3835   _dbus_assert (i == 0);
3836
3837   if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'o', &i))
3838     _dbus_assert_not_reached ("Did not find 'o'");
3839   _dbus_assert (i == _dbus_string_get_length (&str) - 1);
3840
3841   if (_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str) - 1, 'o', &i))
3842     _dbus_assert_not_reached ("Did find 'o'");
3843   _dbus_assert (i == -1);
3844
3845   if (_dbus_string_find_byte_backward (&str, 1, 'e', &i))
3846     _dbus_assert_not_reached ("Did find 'e'");
3847   _dbus_assert (i == -1);
3848
3849   if (!_dbus_string_find_byte_backward (&str, 2, 'e', &i))
3850     _dbus_assert_not_reached ("Didn't find 'e'");
3851   _dbus_assert (i == 1);
3852   
3853   _dbus_string_free (&str);
3854
3855   /* Base 64 and Hex encoding */
3856   test_roundtrips (test_base64_roundtrip);
3857   test_roundtrips (test_hex_roundtrip);
3858
3859   /* Path validation */
3860   i = 0;
3861   while (i < (int) _DBUS_N_ELEMENTS (valid_paths))
3862     {
3863       _dbus_string_init_const (&str, valid_paths[i]);
3864
3865       if (!_dbus_string_validate_path (&str, 0,
3866                                        _dbus_string_get_length (&str)))
3867         {
3868           _dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]);
3869           _dbus_assert_not_reached ("invalid path");
3870         }
3871       
3872       ++i;
3873     }
3874
3875   i = 0;
3876   while (i < (int) _DBUS_N_ELEMENTS (invalid_paths))
3877     {
3878       _dbus_string_init_const (&str, invalid_paths[i]);
3879       
3880       if (_dbus_string_validate_path (&str, 0,
3881                                       _dbus_string_get_length (&str)))
3882         {
3883           _dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]);
3884           _dbus_assert_not_reached ("valid path");
3885         }
3886       
3887       ++i;
3888     }
3889
3890   /* Interface validation */
3891   i = 0;
3892   while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
3893     {
3894       _dbus_string_init_const (&str, valid_interfaces[i]);
3895
3896       if (!_dbus_string_validate_interface (&str, 0,
3897                                             _dbus_string_get_length (&str)))
3898         {
3899           _dbus_warn ("Interface \"%s\" should have been valid\n", valid_interfaces[i]);
3900           _dbus_assert_not_reached ("invalid interface");
3901         }
3902       
3903       ++i;
3904     }
3905
3906   i = 0;
3907   while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
3908     {
3909       _dbus_string_init_const (&str, invalid_interfaces[i]);
3910       
3911       if (_dbus_string_validate_interface (&str, 0,
3912                                            _dbus_string_get_length (&str)))
3913         {
3914           _dbus_warn ("Interface \"%s\" should have been invalid\n", invalid_interfaces[i]);
3915           _dbus_assert_not_reached ("valid interface");
3916         }
3917       
3918       ++i;
3919     }
3920
3921   /* Service validation (check that valid interfaces are valid services,
3922    * and invalid interfaces are invalid services except if they start with ':')
3923    */
3924   i = 0;
3925   while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
3926     {
3927       _dbus_string_init_const (&str, valid_interfaces[i]);
3928
3929       if (!_dbus_string_validate_service (&str, 0,
3930                                           _dbus_string_get_length (&str)))
3931         {
3932           _dbus_warn ("Service \"%s\" should have been valid\n", valid_interfaces[i]);
3933           _dbus_assert_not_reached ("invalid service");
3934         }
3935       
3936       ++i;
3937     }
3938
3939   i = 0;
3940   while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
3941     {
3942       if (invalid_interfaces[i][0] != ':')
3943         {
3944           _dbus_string_init_const (&str, invalid_interfaces[i]);
3945           
3946           if (_dbus_string_validate_service (&str, 0,
3947                                              _dbus_string_get_length (&str)))
3948             {
3949               _dbus_warn ("Service \"%s\" should have been invalid\n", invalid_interfaces[i]);
3950               _dbus_assert_not_reached ("valid service");
3951             }
3952         }
3953       
3954       ++i;
3955     }
3956
3957   /* Base service validation */
3958   i = 0;
3959   while (i < (int) _DBUS_N_ELEMENTS (valid_base_services))
3960     {
3961       _dbus_string_init_const (&str, valid_base_services[i]);
3962
3963       if (!_dbus_string_validate_service (&str, 0,
3964                                           _dbus_string_get_length (&str)))
3965         {
3966           _dbus_warn ("Service \"%s\" should have been valid\n", valid_base_services[i]);
3967           _dbus_assert_not_reached ("invalid base service");
3968         }
3969       
3970       ++i;
3971     }
3972
3973   i = 0;
3974   while (i < (int) _DBUS_N_ELEMENTS (invalid_base_services))
3975     {
3976       _dbus_string_init_const (&str, invalid_base_services[i]);
3977       
3978       if (_dbus_string_validate_service (&str, 0,
3979                                          _dbus_string_get_length (&str)))
3980         {
3981           _dbus_warn ("Service \"%s\" should have been invalid\n", invalid_base_services[i]);
3982           _dbus_assert_not_reached ("valid base service");
3983         }
3984       
3985       ++i;
3986     }
3987
3988
3989   /* Error name validation (currently identical to interfaces)
3990    */
3991   i = 0;
3992   while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
3993     {
3994       _dbus_string_init_const (&str, valid_interfaces[i]);
3995
3996       if (!_dbus_string_validate_error_name (&str, 0,
3997                                              _dbus_string_get_length (&str)))
3998         {
3999           _dbus_warn ("Error name \"%s\" should have been valid\n", valid_interfaces[i]);
4000           _dbus_assert_not_reached ("invalid error name");
4001         }
4002       
4003       ++i;
4004     }
4005
4006   i = 0;
4007   while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
4008     {
4009       if (invalid_interfaces[i][0] != ':')
4010         {
4011           _dbus_string_init_const (&str, invalid_interfaces[i]);
4012           
4013           if (_dbus_string_validate_error_name (&str, 0,
4014                                                 _dbus_string_get_length (&str)))
4015             {
4016               _dbus_warn ("Error name \"%s\" should have been invalid\n", invalid_interfaces[i]);
4017               _dbus_assert_not_reached ("valid error name");
4018             }
4019         }
4020       
4021       ++i;
4022     }
4023   
4024   /* Member validation */
4025   i = 0;
4026   while (i < (int) _DBUS_N_ELEMENTS (valid_members))
4027     {
4028       _dbus_string_init_const (&str, valid_members[i]);
4029
4030       if (!_dbus_string_validate_member (&str, 0,
4031                                          _dbus_string_get_length (&str)))
4032         {
4033           _dbus_warn ("Member \"%s\" should have been valid\n", valid_members[i]);
4034           _dbus_assert_not_reached ("invalid member");
4035         }
4036       
4037       ++i;
4038     }
4039
4040   i = 0;
4041   while (i < (int) _DBUS_N_ELEMENTS (invalid_members))
4042     {
4043       _dbus_string_init_const (&str, invalid_members[i]);
4044       
4045       if (_dbus_string_validate_member (&str, 0,
4046                                         _dbus_string_get_length (&str)))
4047         {
4048           _dbus_warn ("Member \"%s\" should have been invalid\n", invalid_members[i]);
4049           _dbus_assert_not_reached ("valid member");
4050         }
4051       
4052       ++i;
4053     }
4054
4055   /* Validate claimed length longer than real length */
4056   _dbus_string_init_const (&str, "abc.efg");
4057   if (_dbus_string_validate_service (&str, 0, 8))
4058     _dbus_assert_not_reached ("validated too-long string");
4059   if (_dbus_string_validate_interface (&str, 0, 8))
4060     _dbus_assert_not_reached ("validated too-long string");
4061   if (_dbus_string_validate_error_name (&str, 0, 8))
4062     _dbus_assert_not_reached ("validated too-long string");
4063
4064   _dbus_string_init_const (&str, "abc");
4065   if (_dbus_string_validate_member (&str, 0, 4))
4066     _dbus_assert_not_reached ("validated too-long string");
4067
4068   /* Validate string exceeding max name length */
4069   if (!_dbus_string_init (&str))
4070     _dbus_assert_not_reached ("no memory");
4071
4072   while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
4073     if (!_dbus_string_append (&str, "abc.def"))
4074       _dbus_assert_not_reached ("no memory");
4075
4076   if (_dbus_string_validate_service (&str, 0, _dbus_string_get_length (&str)))
4077     _dbus_assert_not_reached ("validated overmax string");
4078   if (_dbus_string_validate_interface (&str, 0, _dbus_string_get_length (&str)))
4079     _dbus_assert_not_reached ("validated overmax string");
4080   if (_dbus_string_validate_error_name (&str, 0, _dbus_string_get_length (&str)))
4081     _dbus_assert_not_reached ("validated overmax string");
4082
4083   /* overlong member */
4084   _dbus_string_set_length (&str, 0);
4085   while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
4086     if (!_dbus_string_append (&str, "abc"))
4087       _dbus_assert_not_reached ("no memory");  
4088
4089   if (_dbus_string_validate_member (&str, 0, _dbus_string_get_length (&str)))
4090     _dbus_assert_not_reached ("validated overmax string");
4091
4092   /* overlong base service */
4093   _dbus_string_set_length (&str, 0);
4094   _dbus_string_append (&str, ":");
4095   while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
4096     if (!_dbus_string_append (&str, "abc"))
4097       _dbus_assert_not_reached ("no memory");  
4098
4099   if (_dbus_string_validate_service (&str, 0, _dbus_string_get_length (&str)))
4100     _dbus_assert_not_reached ("validated overmax string");
4101   
4102   _dbus_string_free (&str);
4103   
4104   return TRUE;
4105 }
4106
4107 #endif /* DBUS_BUILD_TESTS */