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