2003-02-27 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-string.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-string.c String utility class (internal to D-BUS implementation)
3  * 
4  * Copyright (C) 2002, 2003 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-string.h"
26 /* we allow a system header here, for speed/convenience */
27 #include <string.h>
28 #include "dbus-marshal.h"
29 #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1
30 #include "dbus-string-private.h"
31
32 /**
33  * @defgroup DBusString string class
34  * @ingroup  DBusInternals
35  * @brief DBusString data structure
36  *
37  * Types and functions related to DBusString. DBusString is intended
38  * to be a string class that makes it hard to mess up security issues
39  * (and just in general harder to write buggy code).  It should be
40  * used (or extended and then used) rather than the libc stuff in
41  * string.h.  The string class is a bit inconvenient at spots because
42  * it handles out-of-memory failures and tries to be extra-robust.
43  * 
44  * A DBusString has a maximum length set at initialization time; this
45  * can be used to ensure that a buffer doesn't get too big.  The
46  * _dbus_string_lengthen() method checks for overflow, and for max
47  * length being exceeded.
48  * 
49  * Try to avoid conversion to a plain C string, i.e. add methods on
50  * the string object instead, only convert to C string when passing
51  * things out to the public API. In particular, no sprintf, strcpy,
52  * strcat, any of that should be used. The GString feature of
53  * accepting negative numbers for "length of string" is also absent,
54  * because it could keep us from detecting bogus huge lengths. i.e. if
55  * we passed in some bogus huge length it would be taken to mean
56  * "current length of string" instead of "broken crack"
57  */
58
59 /**
60  * @defgroup DBusStringInternals DBusString implementation details
61  * @ingroup  DBusInternals
62  * @brief DBusString implementation details
63  *
64  * The guts of DBusString.
65  *
66  * @{
67  */
68
69 /**
70  * We allocate 1 byte for nul termination, plus 7 bytes for possible
71  * align_offset, so we always need 8 bytes on top of the string's
72  * length to be in the allocated block.
73  */
74 #define ALLOCATION_PADDING 8
75
76 /**
77  * This is the maximum max length (and thus also the maximum length)
78  * of a DBusString
79  */
80 #define MAX_MAX_LENGTH (_DBUS_INT_MAX - ALLOCATION_PADDING)
81
82 /**
83  * Checks a bunch of assertions about a string object
84  *
85  * @param real the DBusRealString
86  */
87 #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)
88
89 /**
90  * Checks assertions about a string object that needs to be
91  * modifiable - may not be locked or const. Also declares
92  * the "real" variable pointing to DBusRealString. 
93  * @param str the string
94  */
95 #define DBUS_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \
96   DBUS_GENERIC_STRING_PREAMBLE (real);                                          \
97   _dbus_assert (!(real)->constant);                                             \
98   _dbus_assert (!(real)->locked)
99
100 /**
101  * Checks assertions about a string object that may be locked but
102  * can't be const. i.e. a string object that we can free.  Also
103  * declares the "real" variable pointing to DBusRealString.
104  *
105  * @param str the string
106  */
107 #define DBUS_LOCKED_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \
108   DBUS_GENERIC_STRING_PREAMBLE (real);                                                 \
109   _dbus_assert (!(real)->constant)
110
111 /**
112  * Checks assertions about a string that may be const or locked.  Also
113  * declares the "real" variable pointing to DBusRealString.
114  * @param str the string.
115  */
116 #define DBUS_CONST_STRING_PREAMBLE(str) const DBusRealString *real = (DBusRealString*) str; \
117   DBUS_GENERIC_STRING_PREAMBLE (real)
118
119 /** @} */
120
121 /**
122  * @addtogroup DBusString
123  * @{
124  */
125
126 static void
127 fixup_alignment (DBusRealString *real)
128 {
129   char *aligned;
130   char *real_block;
131   unsigned int old_align_offset;
132
133   /* we have to have extra space in real->allocated for the align offset and nul byte */
134   _dbus_assert (real->len <= real->allocated - ALLOCATION_PADDING);
135   
136   old_align_offset = real->align_offset;
137   real_block = real->str - old_align_offset;
138   
139   aligned = _DBUS_ALIGN_ADDRESS (real_block, 8);
140
141   real->align_offset = aligned - real_block;
142   real->str = aligned;
143   
144   if (old_align_offset != real->align_offset)
145     {
146       /* Here comes the suck */
147       memmove (real_block + real->align_offset,
148                real_block + old_align_offset,
149                real->len + 1);
150     }
151
152   _dbus_assert (real->align_offset < 8);
153   _dbus_assert (_DBUS_ALIGN_ADDRESS (real->str, 8) == real->str);
154 }
155
156 static void
157 undo_alignment (DBusRealString *real)
158 {
159   if (real->align_offset != 0)
160     {
161       memmove (real->str - real->align_offset,
162                real->str,
163                real->len + 1);
164
165       real->align_offset = 0;
166       real->str = real->str - real->align_offset;
167     }
168 }
169
170 /**
171  * Initializes a string. The maximum length may be _DBUS_INT_MAX for
172  * no maximum. The string starts life with zero length.
173  * The string must eventually be freed with _dbus_string_free().
174  *
175  * @todo the max length feature is useless, because it looks to the
176  * app like out of memory, and the app might try to "recover" - but
177  * recovery in this case is impossible, as we can't ever "get more
178  * memory" - so should delete the max length feature I think. Well, at
179  * least there's a strong caveat that it can only be used when
180  * out-of-memory is a permanent fatal error.
181  *
182  * @todo we could make this init routine not alloc any memory and
183  * return void, would simplify a lot of code, however it might
184  * complexify things elsewhere because _dbus_string_get_data()
185  * etc. could suddenly fail as they'd need to alloc new memory.
186  * 
187  * @param str memory to hold the string
188  * @param max_length the maximum size of the string
189  * @returns #TRUE on success */
190 dbus_bool_t
191 _dbus_string_init (DBusString *str,
192                    int         max_length)
193 {
194   DBusRealString *real;
195   
196   _dbus_assert (str != NULL);
197   _dbus_assert (max_length >= 0);
198
199   _dbus_assert (sizeof (DBusString) == sizeof (DBusRealString));
200   
201   real = (DBusRealString*) str;
202
203   /* It's very important not to touch anything
204    * other than real->str if we're going to fail,
205    * since we also use this function to reset
206    * an existing string, e.g. in _dbus_string_steal_data()
207    */
208   
209   real->str = dbus_malloc (ALLOCATION_PADDING);
210   if (real->str == NULL)
211     return FALSE;  
212   
213   real->allocated = ALLOCATION_PADDING;
214   real->len = 0;
215   real->str[real->len] = '\0';
216   
217   real->max_length = max_length;
218   if (real->max_length > MAX_MAX_LENGTH)
219     real->max_length = MAX_MAX_LENGTH;
220   real->constant = FALSE;
221   real->locked = FALSE;
222   real->invalid = FALSE;
223   real->align_offset = 0;
224   
225   fixup_alignment (real);
226   
227   return TRUE;
228 }
229
230 /**
231  * Initializes a constant string. The value parameter is not copied
232  * (should be static), and the string may never be modified.
233  * It is safe but not necessary to call _dbus_string_free()
234  * on a const string. The string has a length limit of MAXINT - 8.
235  * 
236  * @param str memory to use for the string
237  * @param value a string to be stored in str (not copied!!!)
238  */
239 void
240 _dbus_string_init_const (DBusString *str,
241                          const char *value)
242 {
243   _dbus_assert (value != NULL);
244   
245   _dbus_string_init_const_len (str, value,
246                                strlen (value));
247 }
248
249 /**
250  * Initializes a constant string with a length. The value parameter is
251  * not copied (should be static), and the string may never be
252  * modified.  It is safe but not necessary to call _dbus_string_free()
253  * on a const string.
254  * 
255  * @param str memory to use for the string
256  * @param value a string to be stored in str (not copied!!!)
257  * @param len the length to use
258  */
259 void
260 _dbus_string_init_const_len (DBusString *str,
261                              const char *value,
262                              int         len)
263 {
264   DBusRealString *real;
265   
266   _dbus_assert (str != NULL);
267   _dbus_assert (value != NULL);
268   _dbus_assert (len <= MAX_MAX_LENGTH);
269   _dbus_assert (len >= 0);
270   
271   real = (DBusRealString*) str;
272   
273   real->str = (char*) value;
274   real->len = len;
275   real->allocated = real->len + ALLOCATION_PADDING; /* a lie, just to avoid special-case assertions... */
276   real->max_length = real->len + 1;
277   real->constant = TRUE;
278   real->invalid = FALSE;
279
280   /* We don't require const strings to be 8-byte aligned as the
281    * memory is coming from elsewhere.
282    */
283 }
284
285 /**
286  * Frees a string created by _dbus_string_init().
287  *
288  * @param str memory where the string is stored.
289  */
290 void
291 _dbus_string_free (DBusString *str)
292 {
293   DBusRealString *real = (DBusRealString*) str;
294   DBUS_GENERIC_STRING_PREAMBLE (real);
295   
296   if (real->constant)
297     return;
298   dbus_free (real->str - real->align_offset);
299
300   real->invalid = TRUE;
301 }
302
303 /**
304  * Locks a string such that any attempts to change the string will
305  * result in aborting the program. Also, if the string is wasting a
306  * lot of memory (allocation is sufficiently larger than what the
307  * string is really using), _dbus_string_lock() will realloc the
308  * string's data to "compact" it.
309  *
310  * @param str the string to lock.
311  */
312 void
313 _dbus_string_lock (DBusString *str)
314 {  
315   DBUS_LOCKED_STRING_PREAMBLE (str); /* can lock multiple times */
316
317   real->locked = TRUE;
318
319   /* Try to realloc to avoid excess memory usage, since
320    * we know we won't change the string further
321    */
322 #define MAX_WASTE 48
323   if (real->allocated - MAX_WASTE > real->len)
324     {
325       char *new_str;
326       int new_allocated;
327
328       new_allocated = real->len + ALLOCATION_PADDING;
329
330       new_str = dbus_realloc (real->str - real->align_offset,
331                               new_allocated);
332       if (new_str != NULL)
333         {
334           real->str = new_str + real->align_offset;
335           real->allocated = new_allocated;
336           fixup_alignment (real);
337         }
338     }
339 }
340
341 static dbus_bool_t
342 set_length (DBusRealString *real,
343             int             new_length)
344 {
345   /* Note, we are setting the length without nul termination */
346
347   /* exceeding max length is the same as failure to allocate memory */
348   if (new_length > real->max_length)
349     return FALSE;
350   
351   if (new_length > (real->allocated - ALLOCATION_PADDING))
352     {
353       int new_allocated;
354       char *new_str;
355
356       /* at least double our old allocation to avoid O(n), avoiding
357        * overflow
358        */
359       if (real->allocated > (MAX_MAX_LENGTH + ALLOCATION_PADDING) / 2)
360         new_allocated = MAX_MAX_LENGTH + ALLOCATION_PADDING;
361       else
362         new_allocated = real->allocated * 2;
363
364       /* But be sure we always alloc at least space for the new length */
365       new_allocated = MAX (real->allocated, new_length + ALLOCATION_PADDING);
366         
367       new_str = dbus_realloc (real->str - real->align_offset, new_allocated);
368       if (new_str == NULL)
369         return FALSE;
370
371       real->str = new_str + real->align_offset;
372       real->allocated = new_allocated;
373       fixup_alignment (real);
374     }
375
376   real->len = new_length;
377   real->str[real->len] = '\0';
378
379   return TRUE;
380 }
381
382 static dbus_bool_t
383 open_gap (int             len,
384           DBusRealString *dest,
385           int             insert_at)
386 {
387   if (len == 0)
388     return TRUE;
389
390   if (len > dest->max_length - dest->len)
391     return FALSE; /* detected overflow of dest->len + len below */
392   
393   if (!set_length (dest, dest->len + len))
394     return FALSE;
395
396   memmove (dest->str + insert_at + len, 
397            dest->str + insert_at,
398            dest->len - len - insert_at);
399
400   return TRUE;
401 }
402
403 /**
404  * Gets the raw character buffer from the string.  The returned buffer
405  * will be nul-terminated, but note that strings may contain binary
406  * data so there may be extra nul characters prior to the termination.
407  * This function should be little-used, extend DBusString or add
408  * stuff to dbus-sysdeps.c instead. It's an error to use this
409  * function on a const string.
410  *
411  * @param str the string
412  * @param data_return place to store the returned data
413  */
414 void
415 _dbus_string_get_data (DBusString        *str,
416                        char             **data_return)
417 {
418   DBUS_STRING_PREAMBLE (str);
419   _dbus_assert (data_return != NULL);
420   
421   *data_return = real->str;
422 }
423
424 /**
425  * Gets the raw character buffer from a const string.
426  *
427  * @todo should return the const char* instead of using an out param;
428  * the temporary variable encourages a bug where you use const data
429  * after modifying the string and possibly causing a realloc.
430  *
431  * @param str the string
432  * @param data_return location to store returned data
433  */
434 void
435 _dbus_string_get_const_data (const DBusString  *str,
436                              const char       **data_return)
437 {
438   DBUS_CONST_STRING_PREAMBLE (str);
439   _dbus_assert (data_return != NULL);
440   
441   *data_return = real->str;
442 }
443
444 /**
445  * Gets a sub-portion of the raw character buffer from the
446  * string. The "len" field is required simply for error
447  * checking, to be sure you don't try to use more
448  * string than exists. The nul termination of the
449  * returned buffer remains at the end of the entire
450  * string, not at start + len.
451  *
452  * @param str the string
453  * @param data_return location to return the buffer
454  * @param start byte offset to return
455  * @param len length of segment to return
456  */
457 void
458 _dbus_string_get_data_len (DBusString *str,
459                            char      **data_return,
460                            int         start,
461                            int         len)
462 {
463   DBUS_STRING_PREAMBLE (str);
464   _dbus_assert (data_return != NULL);
465   _dbus_assert (start >= 0);
466   _dbus_assert (len >= 0);
467   _dbus_assert (start <= real->len);
468   _dbus_assert (len <= real->len - start);
469   
470   *data_return = real->str + start;
471 }
472
473 /**
474  * const version of _dbus_string_get_data_len().
475  *
476  * @todo should return the const char* instead of using an out param;
477  * the temporary variable encourages a bug where you use const data
478  * after modifying the string and possibly causing a realloc.
479  * 
480  * @param str the string
481  * @param data_return location to return the buffer
482  * @param start byte offset to return
483  * @param len length of segment to return
484  */
485 void
486 _dbus_string_get_const_data_len (const DBusString  *str,
487                                  const char       **data_return,
488                                  int                start,
489                                  int                len)
490 {
491   DBUS_CONST_STRING_PREAMBLE (str);
492   _dbus_assert (data_return != NULL);
493   _dbus_assert (start >= 0);
494   _dbus_assert (len >= 0);
495   _dbus_assert (start <= real->len);
496   _dbus_assert (len <= real->len - start);
497   
498   *data_return = real->str + start;
499 }
500
501 /**
502  * Sets the value of the byte at the given position.
503  *
504  * @param str the string
505  * @param i the position
506  * @param byte the new value
507  */
508 void
509 _dbus_string_set_byte (DBusString    *str,
510                        int            i,
511                        unsigned char  byte)
512 {
513   DBUS_STRING_PREAMBLE (str);
514   _dbus_assert (i < real->len);
515   _dbus_assert (i >= 0);
516   
517   real->str[i] = byte;
518 }
519
520 /**
521  * Gets the byte at the given position.
522  *
523  * @param str the string
524  * @param start the position
525  * @returns the byte at that position
526  */
527 unsigned char
528 _dbus_string_get_byte (const DBusString  *str,
529                        int                start)
530 {
531   DBUS_CONST_STRING_PREAMBLE (str);
532   _dbus_assert (start < real->len);
533   _dbus_assert (start >= 0);
534   
535   return real->str[start];
536 }
537
538 /**
539  * Inserts the given byte at the given position.
540  *
541  * @param str the string
542  * @param i the position
543  * @param byte the value to insert
544  * @returns #TRUE on success
545  */
546 dbus_bool_t
547 _dbus_string_insert_byte (DBusString   *str,
548                           int           i,
549                           unsigned char byte)
550 {
551   DBUS_STRING_PREAMBLE (str);
552   _dbus_assert (i <= real->len);
553   _dbus_assert (i >= 0);
554   
555   if (!open_gap (1, real, i))
556     return FALSE;
557   
558   real->str[i] = byte;
559
560   return TRUE;
561 }
562
563 /**
564  * Like _dbus_string_get_data(), but removes the
565  * gotten data from the original string. The caller
566  * must free the data returned. This function may
567  * fail due to lack of memory, and return #FALSE.
568  *
569  * @param str the string
570  * @param data_return location to return the buffer
571  * @returns #TRUE on success
572  */
573 dbus_bool_t
574 _dbus_string_steal_data (DBusString        *str,
575                          char             **data_return)
576 {
577   DBUS_STRING_PREAMBLE (str);
578   _dbus_assert (data_return != NULL);
579
580   undo_alignment (real);
581   
582   *data_return = real->str;
583
584   /* reset the string */
585   if (!_dbus_string_init (str, real->max_length))
586     {
587       /* hrm, put it back then */
588       real->str = *data_return;
589       *data_return = NULL;
590       fixup_alignment (real);
591       return FALSE;
592     }
593
594   return TRUE;
595 }
596
597 /**
598  * Like _dbus_string_get_data_len(), but removes the gotten data from
599  * the original string. The caller must free the data returned. This
600  * function may fail due to lack of memory, and return #FALSE.
601  * The returned string is nul-terminated and has length len.
602  *
603  * @todo this function is broken because on failure it
604  * may corrupt the source string.
605  * 
606  * @param str the string
607  * @param data_return location to return the buffer
608  * @param start the start of segment to steal
609  * @param len the length of segment to steal
610  * @returns #TRUE on success
611  */
612 dbus_bool_t
613 _dbus_string_steal_data_len (DBusString        *str,
614                              char             **data_return,
615                              int                start,
616                              int                len)
617 {
618   DBusString dest;
619   
620   DBUS_STRING_PREAMBLE (str);
621   _dbus_assert (data_return != NULL);
622   _dbus_assert (start >= 0);
623   _dbus_assert (len >= 0);
624   _dbus_assert (start <= real->len);
625   _dbus_assert (len <= real->len - start);
626
627   if (!_dbus_string_init (&dest, real->max_length))
628     return FALSE;
629
630   if (!_dbus_string_move_len (str, start, len, &dest, 0))
631     {
632       _dbus_string_free (&dest);
633       return FALSE;
634     }
635
636   _dbus_warn ("Broken code in _dbus_string_steal_data_len(), FIXME\n");
637   if (!_dbus_string_steal_data (&dest, data_return))
638     {
639       _dbus_string_free (&dest);
640       return FALSE;
641     }
642
643   _dbus_string_free (&dest);
644   return TRUE;
645 }
646
647 /**
648  * Gets the length of a string (not including nul termination).
649  *
650  * @returns the length.
651  */
652 int
653 _dbus_string_get_length (const DBusString  *str)
654 {
655   DBUS_CONST_STRING_PREAMBLE (str);
656   
657   return real->len;
658 }
659
660 /**
661  * Makes a string longer by the given number of bytes.  Checks whether
662  * adding additional_length to the current length would overflow an
663  * integer, and checks for exceeding a string's max length.
664  * The new bytes are not initialized, other than nul-terminating
665  * the end of the string. The uninitialized bytes may contain
666  * nul bytes or other junk.
667  *
668  * @param str a string
669  * @param additional_length length to add to the string.
670  * @returns #TRUE on success.
671  */
672 dbus_bool_t
673 _dbus_string_lengthen (DBusString *str,
674                        int         additional_length)
675 {
676   DBUS_STRING_PREAMBLE (str);  
677   _dbus_assert (additional_length >= 0);
678
679   if (additional_length > real->max_length - real->len)
680     return FALSE; /* would overflow */
681   
682   return set_length (real,
683                      real->len + additional_length);
684 }
685
686 /**
687  * Makes a string shorter by the given number of bytes.
688  *
689  * @param str a string
690  * @param length_to_remove length to remove from the string.
691  */
692 void
693 _dbus_string_shorten (DBusString *str,
694                       int         length_to_remove)
695 {
696   DBUS_STRING_PREAMBLE (str);
697   _dbus_assert (length_to_remove >= 0);
698   _dbus_assert (length_to_remove <= real->len);
699
700   set_length (real,
701               real->len - length_to_remove);
702 }
703
704 /**
705  * Sets the length of a string. Can be used to truncate or lengthen
706  * the string. If the string is lengthened, the function may fail and
707  * return #FALSE. Newly-added bytes are not initialized, as with
708  * _dbus_string_lengthen().
709  *
710  * @param str a string
711  * @param length new length of the string.
712  * @returns #FALSE on failure.
713  */
714 dbus_bool_t
715 _dbus_string_set_length (DBusString *str,
716                          int         length)
717 {
718   DBUS_STRING_PREAMBLE (str);
719   _dbus_assert (length >= 0);
720
721   return set_length (real, length);
722 }
723
724 /**
725  * Align the length of a string to a specific alignment (typically 4 or 8)
726  * by appending nul bytes to the string.
727  *
728  * @param str a string
729  * @param alignment the alignment
730  * @returns #FALSE if no memory
731  */
732 dbus_bool_t
733 _dbus_string_align_length (DBusString *str,
734                            int         alignment)
735 {
736   unsigned long new_len; /* ulong to avoid _DBUS_ALIGN_VALUE overflow */
737   int delta;
738   DBUS_STRING_PREAMBLE (str);
739   _dbus_assert (alignment >= 1);
740   _dbus_assert (alignment <= 8); /* it has to be a bug if > 8 */
741
742   new_len = _DBUS_ALIGN_VALUE (real->len, alignment);
743   if (new_len > (unsigned long) real->max_length)
744     return FALSE;
745   
746   delta = new_len - real->len;
747   _dbus_assert (delta >= 0);
748
749   if (delta == 0)
750     return TRUE;
751
752   if (!set_length (real, new_len))
753     return FALSE;
754
755   memset (real->str + (new_len - delta),
756           '\0', delta);
757
758   return TRUE;
759 }
760
761 static dbus_bool_t
762 append (DBusRealString *real,
763         const char     *buffer,
764         int             buffer_len)
765 {
766   if (buffer_len == 0)
767     return TRUE;
768
769   if (!_dbus_string_lengthen ((DBusString*)real, buffer_len))
770     return FALSE;
771
772   memcpy (real->str + (real->len - buffer_len),
773           buffer,
774           buffer_len);
775
776   return TRUE;
777 }
778
779 /**
780  * Appends a nul-terminated C-style string to a DBusString.
781  *
782  * @param str the DBusString
783  * @param buffer the nul-terminated characters to append
784  * @returns #FALSE if not enough memory.
785  */
786 dbus_bool_t
787 _dbus_string_append (DBusString *str,
788                      const char *buffer)
789 {
790   unsigned long buffer_len;
791   
792   DBUS_STRING_PREAMBLE (str);
793   _dbus_assert (buffer != NULL);
794   
795   buffer_len = strlen (buffer);
796   if (buffer_len > (unsigned long) real->max_length)
797     return FALSE;
798   
799   return append (real, buffer, buffer_len);
800 }
801
802 /**
803  * Appends block of bytes with the given length to a DBusString.
804  *
805  * @param str the DBusString
806  * @param buffer the bytes to append
807  * @param len the number of bytes to append
808  * @returns #FALSE if not enough memory.
809  */
810 dbus_bool_t
811 _dbus_string_append_len (DBusString *str,
812                          const char *buffer,
813                          int         len)
814 {
815   DBUS_STRING_PREAMBLE (str);
816   _dbus_assert (buffer != NULL);
817   _dbus_assert (len >= 0);
818
819   return append (real, buffer, len);
820 }
821
822 /**
823  * Appends a single byte to the string, returning #FALSE
824  * if not enough memory.
825  *
826  * @param str the string
827  * @param byte the byte to append
828  * @returns #TRUE on success
829  */
830 dbus_bool_t
831 _dbus_string_append_byte (DBusString    *str,
832                           unsigned char  byte)
833 {
834   DBUS_STRING_PREAMBLE (str);
835
836   if (!set_length (real, real->len + 1))
837     return FALSE;
838
839   real->str[real->len-1] = byte;
840
841   return TRUE;
842 }
843
844 /**
845  * Appends a single Unicode character, encoding the character
846  * in UTF-8 format.
847  *
848  * @param str the string
849  * @param ch the Unicode character
850  */
851 dbus_bool_t
852 _dbus_string_append_unichar (DBusString    *str,
853                              dbus_unichar_t ch)
854 {
855   int len;
856   int first;
857   int i;
858   char *out;
859   
860   DBUS_STRING_PREAMBLE (str);
861
862   /* this code is from GLib but is pretty standard I think */
863   
864   len = 0;
865   
866   if (ch < 0x80)
867     {
868       first = 0;
869       len = 1;
870     }
871   else if (ch < 0x800)
872     {
873       first = 0xc0;
874       len = 2;
875     }
876   else if (ch < 0x10000)
877     {
878       first = 0xe0;
879       len = 3;
880     }
881    else if (ch < 0x200000)
882     {
883       first = 0xf0;
884       len = 4;
885     }
886   else if (ch < 0x4000000)
887     {
888       first = 0xf8;
889       len = 5;
890     }
891   else
892     {
893       first = 0xfc;
894       len = 6;
895     }
896
897   if (len > (real->max_length - real->len))
898     return FALSE; /* real->len + len would overflow */
899   
900   if (!set_length (real, real->len + len))
901     return FALSE;
902
903   out = real->str + (real->len - len);
904   
905   for (i = len - 1; i > 0; --i)
906     {
907       out[i] = (ch & 0x3f) | 0x80;
908       ch >>= 6;
909     }
910   out[0] = ch | first;
911
912   return TRUE;
913 }
914
915 static void
916 delete (DBusRealString *real,
917         int             start,
918         int             len)
919 {
920   if (len == 0)
921     return;
922   
923   memmove (real->str + start, real->str + start + len, real->len - (start + len));
924   real->len -= len;
925   real->str[real->len] = '\0';
926 }
927
928 /**
929  * Deletes a segment of a DBusString with length len starting at
930  * start. (Hint: to clear an entire string, setting length to 0
931  * with _dbus_string_set_length() is easier.)
932  *
933  * @param str the DBusString
934  * @param start where to start deleting
935  * @param len the number of bytes to delete
936  */
937 void
938 _dbus_string_delete (DBusString       *str,
939                      int               start,
940                      int               len)
941 {
942   DBUS_STRING_PREAMBLE (str);
943   _dbus_assert (start >= 0);
944   _dbus_assert (len >= 0);
945   _dbus_assert (start <= real->len);
946   _dbus_assert (len <= real->len - start);
947   
948   delete (real, start, len);
949 }
950
951 static dbus_bool_t
952 copy (DBusRealString *source,
953       int             start,
954       int             len,
955       DBusRealString *dest,
956       int             insert_at)
957 {
958   if (len == 0)
959     return TRUE;
960
961   if (!open_gap (len, dest, insert_at))
962     return FALSE;
963   
964   memcpy (dest->str + insert_at,
965           source->str + start,
966           len);
967
968   return TRUE;
969 }
970
971 /**
972  * Checks assertions for two strings we're copying a segment between,
973  * and declares real_source/real_dest variables.
974  *
975  * @param source the source string
976  * @param start the starting offset
977  * @param dest the dest string
978  * @param insert_at where the copied segment is inserted
979  */
980 #define DBUS_STRING_COPY_PREAMBLE(source, start, dest, insert_at)       \
981   DBusRealString *real_source = (DBusRealString*) source;               \
982   DBusRealString *real_dest = (DBusRealString*) dest;                   \
983   _dbus_assert ((source) != (dest));                                    \
984   DBUS_GENERIC_STRING_PREAMBLE (real_source);                           \
985   DBUS_GENERIC_STRING_PREAMBLE (real_dest);                             \
986   _dbus_assert (!real_dest->constant);                                  \
987   _dbus_assert (!real_dest->locked);                                    \
988   _dbus_assert ((start) >= 0);                                          \
989   _dbus_assert ((start) <= real_source->len);                           \
990   _dbus_assert ((insert_at) >= 0);                                      \
991   _dbus_assert ((insert_at) <= real_dest->len)
992
993 /**
994  * Moves the end of one string into another string. Both strings
995  * must be initialized, valid strings.
996  *
997  * @param source the source string
998  * @param start where to chop off the source string
999  * @param dest the destination string
1000  * @param insert_at where to move the chopped-off part of source string
1001  * @returns #FALSE if not enough memory
1002  */
1003 dbus_bool_t
1004 _dbus_string_move (DBusString       *source,
1005                    int               start,
1006                    DBusString       *dest,
1007                    int               insert_at)
1008 {
1009   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
1010   
1011   if (!copy (real_source, start,
1012              real_source->len - start,
1013              real_dest,
1014              insert_at))
1015     return FALSE;
1016
1017   delete (real_source, start,
1018           real_source->len - start);
1019
1020   return TRUE;
1021 }
1022
1023 /**
1024  * Like _dbus_string_move(), but does not delete the section
1025  * of the source string that's copied to the dest string.
1026  *
1027  * @param source the source string
1028  * @param start where to start copying the source string
1029  * @param dest the destination string
1030  * @param insert_at where to place the copied part of source string
1031  * @returns #FALSE if not enough memory
1032  */
1033 dbus_bool_t
1034 _dbus_string_copy (const DBusString *source,
1035                    int               start,
1036                    DBusString       *dest,
1037                    int               insert_at)
1038 {
1039   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
1040
1041   return copy (real_source, start,
1042                real_source->len - start,
1043                real_dest,
1044                insert_at);
1045 }
1046
1047 /**
1048  * Like _dbus_string_move(), but can move a segment from
1049  * the middle of the source string.
1050  * 
1051  * @param source the source string
1052  * @param start first byte of source string to move
1053  * @param len length of segment to move
1054  * @param dest the destination string
1055  * @param insert_at where to move the bytes from the source string
1056  * @returns #FALSE if not enough memory
1057  */
1058 dbus_bool_t
1059 _dbus_string_move_len (DBusString       *source,
1060                        int               start,
1061                        int               len,
1062                        DBusString       *dest,
1063                        int               insert_at)
1064
1065 {
1066   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
1067   _dbus_assert (len >= 0);
1068   _dbus_assert ((start + len) <= real_source->len);
1069
1070   if (!copy (real_source, start, len,
1071              real_dest,
1072              insert_at))
1073     return FALSE;
1074
1075   delete (real_source, start,
1076           len);
1077
1078   return TRUE;
1079 }
1080
1081 /**
1082  * Like _dbus_string_copy(), but can copy a segment from the middle of
1083  * the source string.
1084  *
1085  * @param source the source string
1086  * @param start where to start copying the source string
1087  * @param len length of segment to copy
1088  * @param dest the destination string
1089  * @param insert_at where to place the copied segment of source string
1090  * @returns #FALSE if not enough memory
1091  */
1092 dbus_bool_t
1093 _dbus_string_copy_len (const DBusString *source,
1094                        int               start,
1095                        int               len,
1096                        DBusString       *dest,
1097                        int               insert_at)
1098 {
1099   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
1100   _dbus_assert (len >= 0);
1101   _dbus_assert (start <= real_source->len);
1102   _dbus_assert (len <= real_source->len - start);
1103   
1104   return copy (real_source, start, len,
1105                real_dest,
1106                insert_at);
1107 }
1108
1109 /**
1110  * Replaces a segment of dest string with a segment of source string.
1111  *
1112  * @todo optimize the case where the two lengths are the same, and
1113  * avoid memmoving the data in the trailing part of the string twice.
1114  *
1115  * @todo avoid inserting the source into dest, then deleting
1116  * the replaced chunk of dest (which creates a potentially large
1117  * intermediate string). Instead, extend the replaced chunk
1118  * of dest with padding to the same size as the source chunk,
1119  * then copy in the source bytes.
1120  * 
1121  * @param source the source string
1122  * @param start where to start copying the source string
1123  * @param len length of segment to copy
1124  * @param dest the destination string
1125  * @param replace_at start of segment of dest string to replace
1126  * @param replace_len length of segment of dest string to replace
1127  * @returns #FALSE if not enough memory
1128  *
1129  */
1130 dbus_bool_t
1131 _dbus_string_replace_len (const DBusString *source,
1132                           int               start,
1133                           int               len,
1134                           DBusString       *dest,
1135                           int               replace_at,
1136                           int               replace_len)
1137 {
1138   DBUS_STRING_COPY_PREAMBLE (source, start, dest, replace_at);
1139   _dbus_assert (len >= 0);
1140   _dbus_assert (start <= real_source->len);
1141   _dbus_assert (len <= real_source->len - start);
1142   _dbus_assert (replace_at >= 0);
1143   _dbus_assert (replace_at <= real_dest->len);
1144   _dbus_assert (replace_len <= real_dest->len - replace_at);
1145
1146   if (!copy (real_source, start, len,
1147              real_dest, replace_at))
1148     return FALSE;
1149
1150   delete (real_dest, replace_at + len, replace_len);
1151
1152   return TRUE;
1153 }
1154
1155 /* Unicode macros from GLib */
1156
1157 /** computes length and mask of a unicode character
1158  * @param Char the char
1159  * @param Mask the mask variable to assign to
1160  * @param Len the length variable to assign to
1161  */
1162 #define UTF8_COMPUTE(Char, Mask, Len)                                         \
1163   if (Char < 128)                                                             \
1164     {                                                                         \
1165       Len = 1;                                                                \
1166       Mask = 0x7f;                                                            \
1167     }                                                                         \
1168   else if ((Char & 0xe0) == 0xc0)                                             \
1169     {                                                                         \
1170       Len = 2;                                                                \
1171       Mask = 0x1f;                                                            \
1172     }                                                                         \
1173   else if ((Char & 0xf0) == 0xe0)                                             \
1174     {                                                                         \
1175       Len = 3;                                                                \
1176       Mask = 0x0f;                                                            \
1177     }                                                                         \
1178   else if ((Char & 0xf8) == 0xf0)                                             \
1179     {                                                                         \
1180       Len = 4;                                                                \
1181       Mask = 0x07;                                                            \
1182     }                                                                         \
1183   else if ((Char & 0xfc) == 0xf8)                                             \
1184     {                                                                         \
1185       Len = 5;                                                                \
1186       Mask = 0x03;                                                            \
1187     }                                                                         \
1188   else if ((Char & 0xfe) == 0xfc)                                             \
1189     {                                                                         \
1190       Len = 6;                                                                \
1191       Mask = 0x01;                                                            \
1192     }                                                                         \
1193   else                                                                        \
1194     Len = -1;
1195
1196 /**
1197  * computes length of a unicode character in UTF-8
1198  * @param Char the char
1199  */
1200 #define UTF8_LENGTH(Char)              \
1201   ((Char) < 0x80 ? 1 :                 \
1202    ((Char) < 0x800 ? 2 :               \
1203     ((Char) < 0x10000 ? 3 :            \
1204      ((Char) < 0x200000 ? 4 :          \
1205       ((Char) < 0x4000000 ? 5 : 6)))))
1206    
1207 /**
1208  * Gets a UTF-8 value.
1209  *
1210  * @param Result variable for extracted unicode char.
1211  * @param Chars the bytes to decode
1212  * @param Count counter variable
1213  * @param Mask mask for this char
1214  * @param Len length for this char in bytes
1215  */
1216 #define UTF8_GET(Result, Chars, Count, Mask, Len)                             \
1217   (Result) = (Chars)[0] & (Mask);                                             \
1218   for ((Count) = 1; (Count) < (Len); ++(Count))                               \
1219     {                                                                         \
1220       if (((Chars)[(Count)] & 0xc0) != 0x80)                                  \
1221         {                                                                     \
1222           (Result) = -1;                                                      \
1223           break;                                                              \
1224         }                                                                     \
1225       (Result) <<= 6;                                                         \
1226       (Result) |= ((Chars)[(Count)] & 0x3f);                                  \
1227     }
1228
1229 /**
1230  * Check whether a unicode char is in a valid range.
1231  *
1232  * @param Char the character
1233  */
1234 #define UNICODE_VALID(Char)                   \
1235     ((Char) < 0x110000 &&                     \
1236      ((Char) < 0xD800 || (Char) >= 0xE000) && \
1237      (Char) != 0xFFFE && (Char) != 0xFFFF)   
1238
1239 /**
1240  * Gets a unicode character from a UTF-8 string. Does no validation;
1241  * you must verify that the string is valid UTF-8 in advance and must
1242  * pass in the start of a character.
1243  *
1244  * @param str the string
1245  * @param start the start of the UTF-8 character.
1246  * @param ch_return location to return the character
1247  * @param end_return location to return the byte index of next character
1248  */
1249 void
1250 _dbus_string_get_unichar (const DBusString *str,
1251                           int               start,
1252                           dbus_unichar_t   *ch_return,
1253                           int              *end_return)
1254 {
1255   int i, mask, len;
1256   dbus_unichar_t result;
1257   unsigned char c;
1258   unsigned char *p;
1259   DBUS_CONST_STRING_PREAMBLE (str);
1260   _dbus_assert (start >= 0);
1261   _dbus_assert (start <= real->len);
1262   
1263   if (ch_return)
1264     *ch_return = 0;
1265   if (end_return)
1266     *end_return = real->len;
1267   
1268   mask = 0;
1269   p = real->str + start;
1270   c = *p;
1271   
1272   UTF8_COMPUTE (c, mask, len);
1273   if (len == -1)
1274     return;
1275   UTF8_GET (result, p, i, mask, len);
1276
1277   if (result == (dbus_unichar_t)-1)
1278     return;
1279
1280   if (ch_return)
1281     *ch_return = result;
1282   if (end_return)
1283     *end_return = start + len;
1284 }
1285
1286 /**
1287  * Finds the given substring in the string,
1288  * returning #TRUE and filling in the byte index
1289  * where the substring was found, if it was found.
1290  * Returns #FALSE if the substring wasn't found.
1291  * Sets *start to the length of the string if the substring
1292  * is not found.
1293  *
1294  * @param str the string
1295  * @param start where to start looking
1296  * @param substr the substring
1297  * @param found return location for where it was found, or #NULL
1298  * @returns #TRUE if found
1299  */
1300 dbus_bool_t
1301 _dbus_string_find (const DBusString *str,
1302                    int               start,
1303                    const char       *substr,
1304                    int              *found)
1305 {
1306   return _dbus_string_find_to (str, start,
1307                                ((const DBusRealString*)str)->len,
1308                                substr, found);
1309 }
1310
1311 /**
1312  * Finds the given substring in the string,
1313  * up to a certain position,
1314  * returning #TRUE and filling in the byte index
1315  * where the substring was found, if it was found.
1316  * Returns #FALSE if the substring wasn't found.
1317  * Sets *start to the length of the string if the substring
1318  * is not found.
1319  *
1320  * @param str the string
1321  * @param start where to start looking
1322  * @param end where to stop looking
1323  * @param substr the substring
1324  * @param found return location for where it was found, or #NULL
1325  * @returns #TRUE if found
1326  */
1327 dbus_bool_t
1328 _dbus_string_find_to (const DBusString *str,
1329                       int               start,
1330                       int               end,
1331                       const char       *substr,
1332                       int              *found)
1333 {
1334   int i;
1335   DBUS_CONST_STRING_PREAMBLE (str);
1336   _dbus_assert (substr != NULL);
1337   _dbus_assert (start <= real->len);
1338   _dbus_assert (start >= 0);
1339   _dbus_assert (substr != NULL);
1340   _dbus_assert (end <= real->len);
1341   _dbus_assert (start <= end);
1342
1343   /* we always "find" an empty string */
1344   if (*substr == '\0')
1345     {
1346       if (found)
1347         *found = start;
1348       return TRUE;
1349     }
1350
1351   i = start;
1352   while (i < end)
1353     {
1354       if (real->str[i] == substr[0])
1355         {
1356           int j = i + 1;
1357           
1358           while (j < end)
1359             {
1360               if (substr[j - i] == '\0')
1361                 break;
1362               else if (real->str[j] != substr[j - i])
1363                 break;
1364               
1365               ++j;
1366             }
1367
1368           if (substr[j - i] == '\0')
1369             {
1370               if (found)
1371                 *found = i;
1372               return TRUE;
1373             }
1374         }
1375       
1376       ++i;
1377     }
1378
1379   if (found)
1380     *found = end;
1381   
1382   return FALSE;  
1383 }
1384
1385 /**
1386  * Finds a blank (space or tab) in the string. Returns #TRUE
1387  * if found, #FALSE otherwise. If a blank is not found sets
1388  * *found to the length of the string.
1389  *
1390  * @param str the string
1391  * @param start byte index to start looking
1392  * @param found place to store the location of the first blank
1393  * @returns #TRUE if a blank was found
1394  */
1395 dbus_bool_t
1396 _dbus_string_find_blank (const DBusString *str,
1397                          int               start,
1398                          int              *found)
1399 {
1400   int i;
1401   DBUS_CONST_STRING_PREAMBLE (str);
1402   _dbus_assert (start <= real->len);
1403   _dbus_assert (start >= 0);
1404   
1405   i = start;
1406   while (i < real->len)
1407     {
1408       if (real->str[i] == ' ' ||
1409           real->str[i] == '\t')
1410         {
1411           if (found)
1412             *found = i;
1413           return TRUE;
1414         }
1415       
1416       ++i;
1417     }
1418
1419   if (found)
1420     *found = real->len;
1421   
1422   return FALSE;
1423 }
1424
1425 /**
1426  * Skips blanks from start, storing the first non-blank in *end
1427  *
1428  * @param str the string
1429  * @param start where to start
1430  * @param end where to store the first non-blank byte index
1431  */
1432 void
1433 _dbus_string_skip_blank (const DBusString *str,
1434                          int               start,
1435                          int              *end)
1436 {
1437   int i;
1438   DBUS_CONST_STRING_PREAMBLE (str);
1439   _dbus_assert (start <= real->len);
1440   _dbus_assert (start >= 0);
1441   
1442   i = start;
1443   while (i < real->len)
1444     {
1445       if (!(real->str[i] == ' ' ||
1446             real->str[i] == '\t'))
1447         break;
1448       
1449       ++i;
1450     }
1451
1452   _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
1453                                     real->str[i] == '\t'));
1454   
1455   if (end)
1456     *end = i;
1457 }
1458
1459 /**
1460  * Assigns a newline-terminated or \r\n-terminated line from the front
1461  * of the string to the given dest string. The dest string's previous
1462  * contents are deleted. If the source string contains no newline,
1463  * moves the entire source string to the dest string.
1464  *
1465  * @todo owen correctly notes that this is a stupid function (it was
1466  * written purely for test code,
1467  * e.g. dbus-message-builder.c). Probably should be enforced as test
1468  * code only with #ifdef DBUS_BUILD_TESTS
1469  * 
1470  * @param source the source string
1471  * @param dest the destination string (contents are replaced)
1472  * @returns #FALSE if no memory, or source has length 0
1473  */
1474 dbus_bool_t
1475 _dbus_string_pop_line (DBusString *source,
1476                        DBusString *dest)
1477 {
1478   int eol;
1479   dbus_bool_t have_newline;
1480   
1481   _dbus_string_set_length (dest, 0);
1482   
1483   eol = 0;
1484   if (_dbus_string_find (source, 0, "\n", &eol))
1485     {
1486       have_newline = TRUE;
1487       eol += 1; /* include newline */
1488     }
1489   else
1490     {
1491       eol = _dbus_string_get_length (source);
1492       have_newline = FALSE;
1493     }
1494
1495   if (eol == 0)
1496     return FALSE; /* eof */
1497   
1498   if (!_dbus_string_move_len (source, 0, eol,
1499                               dest, 0))
1500     {
1501       return FALSE;
1502     }
1503
1504   /* dump the newline and the \r if we have one */
1505   if (have_newline)
1506     {
1507       dbus_bool_t have_cr;
1508       
1509       _dbus_assert (_dbus_string_get_length (dest) > 0);
1510
1511       if (_dbus_string_get_length (dest) > 1 &&
1512           _dbus_string_get_byte (dest,
1513                                  _dbus_string_get_length (dest) - 2) == '\r')
1514         have_cr = TRUE;
1515       else
1516         have_cr = FALSE;
1517         
1518       _dbus_string_set_length (dest,
1519                                _dbus_string_get_length (dest) -
1520                                (have_cr ? 2 : 1));
1521     }
1522   
1523   return TRUE;
1524 }
1525
1526 /**
1527  * Deletes up to and including the first blank space
1528  * in the string.
1529  *
1530  * @param str the string
1531  */
1532 void
1533 _dbus_string_delete_first_word (DBusString *str)
1534 {
1535   int i;
1536   
1537   if (_dbus_string_find_blank (str, 0, &i))
1538     _dbus_string_skip_blank (str, i, &i);
1539
1540   _dbus_string_delete (str, 0, i);
1541 }
1542
1543 /**
1544  * Deletes any leading blanks in the string
1545  *
1546  * @param str the string
1547  */
1548 void
1549 _dbus_string_delete_leading_blanks (DBusString *str)
1550 {
1551   int i;
1552   
1553   _dbus_string_skip_blank (str, 0, &i);
1554
1555   if (i > 0)
1556     _dbus_string_delete (str, 0, i);
1557 }
1558
1559 /**
1560  * Tests two DBusString for equality.
1561  *
1562  * @todo memcmp is probably faster
1563  *
1564  * @param a first string
1565  * @param b second string
1566  * @returns #TRUE if equal
1567  */
1568 dbus_bool_t
1569 _dbus_string_equal (const DBusString *a,
1570                     const DBusString *b)
1571 {
1572   const unsigned char *ap;
1573   const unsigned char *bp;
1574   const unsigned char *a_end;
1575   const DBusRealString *real_a = (const DBusRealString*) a;
1576   const DBusRealString *real_b = (const DBusRealString*) b;
1577   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1578   DBUS_GENERIC_STRING_PREAMBLE (real_b);
1579
1580   if (real_a->len != real_b->len)
1581     return FALSE;
1582
1583   ap = real_a->str;
1584   bp = real_b->str;
1585   a_end = real_a->str + real_a->len;
1586   while (ap != a_end)
1587     {
1588       if (*ap != *bp)
1589         return FALSE;
1590       
1591       ++ap;
1592       ++bp;
1593     }
1594
1595   return TRUE;
1596 }
1597
1598 /**
1599  * Tests two DBusString for equality up to the given length.
1600  *
1601  * @todo write a unit test
1602  *
1603  * @todo memcmp is probably faster
1604  *
1605  * @param a first string
1606  * @param b second string
1607  * @param len the lengh
1608  * @returns #TRUE if equal for the given number of bytes
1609  */
1610 dbus_bool_t
1611 _dbus_string_equal_len (const DBusString *a,
1612                         const DBusString *b,
1613                         int               len)
1614 {
1615   const unsigned char *ap;
1616   const unsigned char *bp;
1617   const unsigned char *a_end;
1618   const DBusRealString *real_a = (const DBusRealString*) a;
1619   const DBusRealString *real_b = (const DBusRealString*) b;
1620   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1621   DBUS_GENERIC_STRING_PREAMBLE (real_b);
1622
1623   if (real_a->len != real_b->len &&
1624       (real_a->len < len || real_b->len < len))
1625     return FALSE;
1626
1627   ap = real_a->str;
1628   bp = real_b->str;
1629   a_end = real_a->str + MIN (real_a->len, len);
1630   while (ap != a_end)
1631     {
1632       if (*ap != *bp)
1633         return FALSE;
1634       
1635       ++ap;
1636       ++bp;
1637     }
1638
1639   return TRUE;
1640 }
1641
1642 /**
1643  * Checks whether a string is equal to a C string.
1644  *
1645  * @param a the string
1646  * @param c_str the C string
1647  * @returns #TRUE if equal
1648  */
1649 dbus_bool_t
1650 _dbus_string_equal_c_str (const DBusString *a,
1651                           const char       *c_str)
1652 {
1653   const unsigned char *ap;
1654   const unsigned char *bp;
1655   const unsigned char *a_end;
1656   const DBusRealString *real_a = (const DBusRealString*) a;
1657   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1658   _dbus_assert (c_str != NULL);
1659   
1660   ap = real_a->str;
1661   bp = (const unsigned char*) c_str;
1662   a_end = real_a->str + real_a->len;
1663   while (ap != a_end && *bp)
1664     {
1665       if (*ap != *bp)
1666         return FALSE;
1667       
1668       ++ap;
1669       ++bp;
1670     }
1671
1672   if (ap != a_end || *bp)
1673     return FALSE;
1674   
1675   return TRUE;
1676 }
1677
1678 /**
1679  * Checks whether a string starts with the given C string.
1680  *
1681  * @param a the string
1682  * @param c_str the C string
1683  * @returns #TRUE if string starts with it
1684  */
1685 dbus_bool_t
1686 _dbus_string_starts_with_c_str (const DBusString *a,
1687                                 const char       *c_str)
1688 {
1689   const unsigned char *ap;
1690   const unsigned char *bp;
1691   const unsigned char *a_end;
1692   const DBusRealString *real_a = (const DBusRealString*) a;
1693   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1694   _dbus_assert (c_str != NULL);
1695   
1696   ap = real_a->str;
1697   bp = (const unsigned char*) c_str;
1698   a_end = real_a->str + real_a->len;
1699   while (ap != a_end && *bp)
1700     {
1701       if (*ap != *bp)
1702         return FALSE;
1703       
1704       ++ap;
1705       ++bp;
1706     }
1707
1708   if (*bp == '\0')
1709     return TRUE;
1710   else
1711     return FALSE;
1712 }
1713
1714 /**
1715  * Returns whether a string ends with the given suffix
1716  *
1717  * @todo memcmp might make this faster.
1718  * 
1719  * @param a the string
1720  * @param c_str the C-style string
1721  * @returns #TRUE if the string ends with the suffix
1722  */
1723 dbus_bool_t
1724 _dbus_string_ends_with_c_str (const DBusString *a,
1725                               const char       *c_str)
1726 {
1727   const unsigned char *ap;
1728   const unsigned char *bp;
1729   const unsigned char *a_end;
1730   unsigned long c_str_len;
1731   const DBusRealString *real_a = (const DBusRealString*) a;
1732   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1733   _dbus_assert (c_str != NULL);
1734   
1735   c_str_len = strlen (c_str);
1736   if (((unsigned long)real_a->len) < c_str_len)
1737     return FALSE;
1738   
1739   ap = real_a->str + (real_a->len - c_str_len);
1740   bp = (const unsigned char*) c_str;
1741   a_end = real_a->str + real_a->len;
1742   while (ap != a_end)
1743     {
1744       if (*ap != *bp)
1745         return FALSE;
1746       
1747       ++ap;
1748       ++bp;
1749     }
1750
1751   _dbus_assert (*ap == '\0');
1752   _dbus_assert (*bp == '\0');
1753   
1754   return TRUE;
1755 }
1756
1757 static const signed char base64_table[] = {
1758   /* 0 */ 'A',
1759   /* 1 */ 'B',
1760   /* 2 */ 'C',
1761   /* 3 */ 'D',
1762   /* 4 */ 'E',
1763   /* 5 */ 'F',
1764   /* 6 */ 'G',
1765   /* 7 */ 'H',
1766   /* 8 */ 'I',
1767   /* 9 */ 'J',
1768   /* 10 */ 'K',
1769   /* 11 */ 'L',
1770   /* 12 */ 'M',
1771   /* 13 */ 'N',
1772   /* 14 */ 'O',
1773   /* 15 */ 'P',
1774   /* 16 */ 'Q',
1775   /* 17 */ 'R',
1776   /* 18 */ 'S',
1777   /* 19 */ 'T',
1778   /* 20 */ 'U',
1779   /* 21 */ 'V',
1780   /* 22 */ 'W',
1781   /* 23 */ 'X',
1782   /* 24 */ 'Y',
1783   /* 25 */ 'Z',
1784   /* 26 */ 'a',
1785   /* 27 */ 'b',
1786   /* 28 */ 'c',
1787   /* 29 */ 'd',
1788   /* 30 */ 'e',
1789   /* 31 */ 'f',
1790   /* 32 */ 'g',
1791   /* 33 */ 'h',
1792   /* 34 */ 'i',
1793   /* 35 */ 'j',
1794   /* 36 */ 'k',
1795   /* 37 */ 'l',
1796   /* 38 */ 'm',
1797   /* 39 */ 'n',
1798   /* 40 */ 'o',
1799   /* 41 */ 'p',
1800   /* 42 */ 'q',
1801   /* 43 */ 'r',
1802   /* 44 */ 's',
1803   /* 45 */ 't',
1804   /* 46 */ 'u',
1805   /* 47 */ 'v',
1806   /* 48 */ 'w',
1807   /* 49 */ 'x',
1808   /* 50 */ 'y',
1809   /* 51 */ 'z',
1810   /* 52 */ '0',
1811   /* 53 */ '1',
1812   /* 54 */ '2',
1813   /* 55 */ '3',
1814   /* 56 */ '4',
1815   /* 57 */ '5',
1816   /* 58 */ '6',
1817   /* 59 */ '7',
1818   /* 60 */ '8',
1819   /* 61 */ '9',
1820   /* 62 */ '+',
1821   /* 63 */ '/'
1822 };
1823
1824 /** The minimum char that's a valid char in Base64-encoded text */
1825 #define UNBASE64_MIN_CHAR (43)
1826 /** The maximum char that's a valid char in Base64-encoded text */
1827 #define UNBASE64_MAX_CHAR (122)
1828 /** Must subtract this from a char's integer value before offsetting
1829  * into unbase64_table
1830  */
1831 #define UNBASE64_TABLE_OFFSET UNBASE64_MIN_CHAR
1832 static const signed char unbase64_table[] = {
1833   /* 43 + */ 62,
1834   /* 44 , */ -1,
1835   /* 45 - */ -1,
1836   /* 46 . */ -1,
1837   /* 47 / */ 63,
1838   /* 48 0 */ 52,
1839   /* 49 1 */ 53,
1840   /* 50 2 */ 54,
1841   /* 51 3 */ 55,
1842   /* 52 4 */ 56,
1843   /* 53 5 */ 57,
1844   /* 54 6 */ 58,
1845   /* 55 7 */ 59,
1846   /* 56 8 */ 60,
1847   /* 57 9 */ 61,
1848   /* 58 : */ -1,
1849   /* 59 ; */ -1,
1850   /* 60 < */ -1,
1851   /* 61 = */ -1,
1852   /* 62 > */ -1,
1853   /* 63 ? */ -1,
1854   /* 64 @ */ -1,
1855   /* 65 A */ 0,
1856   /* 66 B */ 1,
1857   /* 67 C */ 2,
1858   /* 68 D */ 3,
1859   /* 69 E */ 4,
1860   /* 70 F */ 5,
1861   /* 71 G */ 6,
1862   /* 72 H */ 7,
1863   /* 73 I */ 8,
1864   /* 74 J */ 9,
1865   /* 75 K */ 10,
1866   /* 76 L */ 11,
1867   /* 77 M */ 12,
1868   /* 78 N */ 13,
1869   /* 79 O */ 14,
1870   /* 80 P */ 15,
1871   /* 81 Q */ 16,
1872   /* 82 R */ 17,
1873   /* 83 S */ 18,
1874   /* 84 T */ 19,
1875   /* 85 U */ 20,
1876   /* 86 V */ 21,
1877   /* 87 W */ 22,
1878   /* 88 X */ 23,
1879   /* 89 Y */ 24,
1880   /* 90 Z */ 25,
1881   /* 91 [ */ -1,
1882   /* 92 \ */ -1,
1883   /* 93 ] */ -1,
1884   /* 94 ^ */ -1,
1885   /* 95 _ */ -1,
1886   /* 96 ` */ -1,
1887   /* 97 a */ 26,
1888   /* 98 b */ 27,
1889   /* 99 c */ 28,
1890   /* 100 d */ 29,
1891   /* 101 e */ 30,
1892   /* 102 f */ 31,
1893   /* 103 g */ 32,
1894   /* 104 h */ 33,
1895   /* 105 i */ 34,
1896   /* 106 j */ 35,
1897   /* 107 k */ 36,
1898   /* 108 l */ 37,
1899   /* 109 m */ 38,
1900   /* 110 n */ 39,
1901   /* 111 o */ 40,
1902   /* 112 p */ 41,
1903   /* 113 q */ 42,
1904   /* 114 r */ 43,
1905   /* 115 s */ 44,
1906   /* 116 t */ 45,
1907   /* 117 u */ 46,
1908   /* 118 v */ 47,
1909   /* 119 w */ 48,
1910   /* 120 x */ 49,
1911   /* 121 y */ 50,
1912   /* 122 z */ 51
1913 };
1914
1915 /**
1916  * Encodes a string using Base64, as documented in RFC 2045.
1917  *
1918  * @param source the string to encode
1919  * @param start byte index to start encoding
1920  * @param dest string where encoded data should be placed
1921  * @param insert_at where to place encoded data
1922  * @returns #TRUE if encoding was successful, #FALSE if no memory etc.
1923  */
1924 dbus_bool_t
1925 _dbus_string_base64_encode (const DBusString *source,
1926                             int               start,
1927                             DBusString       *dest,
1928                             int               insert_at)
1929 {
1930   int source_len;
1931   unsigned int dest_len; /* unsigned for overflow checks below */
1932   const unsigned char *s;
1933   unsigned char *d;
1934   const unsigned char *triplet_end;
1935   const unsigned char *final_end;
1936   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);  
1937   _dbus_assert (source != dest);
1938   
1939   /* For each 24 bits (3 bytes) of input, we have 4 bytes of
1940    * output.
1941    */
1942   source_len = real_source->len - start;
1943   dest_len = (source_len / 3) * 4;
1944   if (source_len % 3 != 0)
1945     dest_len += 4;
1946
1947   if (dest_len > (unsigned int) real_dest->max_length)
1948     return FALSE;
1949   
1950   if (source_len == 0)
1951     return TRUE;
1952   
1953   if (!open_gap (dest_len, real_dest, insert_at))
1954     return FALSE;
1955
1956   d = real_dest->str + insert_at;
1957   s = real_source->str + start;
1958   final_end = real_source->str + (start + source_len);
1959   triplet_end = final_end - (source_len % 3);
1960   _dbus_assert (triplet_end <= final_end);
1961   _dbus_assert ((final_end - triplet_end) < 3);
1962
1963 #define ENCODE_64(v) (base64_table[ (unsigned char) (v) ])
1964 #define SIX_BITS_MASK (0x3f)
1965   _dbus_assert (SIX_BITS_MASK < _DBUS_N_ELEMENTS (base64_table));
1966   
1967   while (s != triplet_end)
1968     {
1969       unsigned int triplet;
1970
1971       triplet = s[2] | (s[1] << 8) | (s[0] << 16);
1972
1973       /* Encode each 6 bits. */
1974
1975       *d++ = ENCODE_64 (triplet >> 18);
1976       *d++ = ENCODE_64 ((triplet >> 12) & SIX_BITS_MASK);
1977       *d++ = ENCODE_64 ((triplet >> 6) & SIX_BITS_MASK);
1978       *d++ = ENCODE_64 (triplet & SIX_BITS_MASK);
1979       
1980       s += 3;
1981     }
1982
1983   switch (final_end - triplet_end)
1984     {
1985     case 2:
1986       {
1987         unsigned int doublet;
1988         
1989         doublet = s[1] | (s[0] << 8);        
1990
1991         *d++ = ENCODE_64 (doublet >> 12);
1992         *d++ = ENCODE_64 ((doublet >> 6) & SIX_BITS_MASK);
1993         *d++ = ENCODE_64 (doublet & SIX_BITS_MASK);
1994         *d++ = '=';
1995       }
1996       break;
1997     case 1:
1998       {
1999         unsigned int singlet;
2000         
2001         singlet = s[0];
2002
2003         *d++ = ENCODE_64 ((singlet >> 6) & SIX_BITS_MASK);
2004         *d++ = ENCODE_64 (singlet & SIX_BITS_MASK);
2005         *d++ = '=';
2006         *d++ = '=';
2007       }
2008       break;
2009     case 0:
2010       break;
2011     }
2012
2013   _dbus_assert (d == (real_dest->str + (insert_at + dest_len)));
2014
2015   return TRUE;
2016 }
2017
2018 /**
2019  * Decodes a string from Base64, as documented in RFC 2045.
2020  *
2021  * @todo sort out the AUDIT comment in here. The case it mentions
2022  * ("====" or "x===") is not allowed in correct base64, so need to
2023  * decide what to do with that kind of input. Probably ignore it
2024  * since we ignore any other junk seen.
2025  *
2026  * @param source the string to decode
2027  * @param start byte index to start decode
2028  * @param dest string where decoded data should be placed
2029  * @param insert_at where to place decoded data
2030  * @returns #TRUE if decoding was successful, #FALSE if no memory etc.
2031  */
2032 dbus_bool_t
2033 _dbus_string_base64_decode (const DBusString *source,
2034                             int               start,
2035                             DBusString       *dest,
2036                             int               insert_at)
2037 {
2038   int source_len;
2039   const char *s;
2040   const char *end;
2041   DBusString result;
2042   unsigned int triplet = 0;
2043   int sextet_count;
2044   int pad_count;
2045   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
2046   _dbus_assert (source != dest);
2047   
2048   source_len = real_source->len - start;
2049   s = real_source->str + start;
2050   end = real_source->str + source_len;
2051
2052   if (source_len == 0)
2053     return TRUE;
2054
2055   if (!_dbus_string_init (&result, _DBUS_INT_MAX))
2056     return FALSE;
2057
2058   pad_count = 0;
2059   sextet_count = 0;
2060   while (s != end)
2061     {
2062       /* The idea is to just skip anything that isn't
2063        * a base64 char - it's allowed to have whitespace,
2064        * newlines, etc. in here. We also ignore trailing
2065        * base64 chars, though that's suspicious.
2066        */
2067       
2068       if (*s >= UNBASE64_MIN_CHAR &&
2069           *s <= UNBASE64_MAX_CHAR)
2070         {
2071           if (*s == '=')
2072             {
2073               /* '=' is padding, doesn't represent additional data
2074                * but does increment our count.
2075                */
2076               pad_count += 1;
2077               sextet_count += 1;
2078             }
2079           else
2080             {
2081               int val;
2082
2083               val = unbase64_table[(*s) - UNBASE64_TABLE_OFFSET];
2084
2085               if (val >= 0)
2086                 {
2087                   triplet <<= 6;
2088                   triplet |= (unsigned int) val;
2089                   sextet_count += 1;
2090                 }
2091             }
2092
2093           if (sextet_count == 4)
2094             {
2095               /* no pad = 3 bytes, 1 pad = 2 bytes, 2 pad = 1 byte */
2096
2097
2098               /* AUDIT: Comment doesn't mention 4 pad => 0,
2099                *         3 pad => 1 byte, though the code should
2100                *        work fine if those are the required outputs.
2101                *
2102                *        I assume that the spec requires dropping
2103                *        the top two bits of, say, ///= which is > 2 
2104                *        bytes worth of bits. (Or otherwise, you couldn't
2105                *        actually represent 2 byte sequences.
2106                */
2107               
2108               if (pad_count < 1)
2109                 _dbus_string_append_byte (&result,
2110                                           triplet >> 16);
2111               
2112               if (pad_count < 2)
2113                 _dbus_string_append_byte (&result,
2114                                           (triplet >> 8) & 0xff);              
2115               
2116               _dbus_string_append_byte (&result,
2117                                         triplet & 0xff);
2118               
2119               sextet_count = 0;
2120               pad_count = 0;
2121               triplet = 0;
2122             }
2123         }
2124       
2125       ++s;
2126     }
2127
2128   if (!_dbus_string_move (&result, 0, dest, insert_at))
2129     {
2130       _dbus_string_free (&result);
2131       return FALSE;
2132     }
2133
2134   _dbus_string_free (&result);
2135
2136   return TRUE;
2137 }
2138
2139 /**
2140  * Encodes a string in hex, the way MD5 and SHA-1 are usually
2141  * encoded. (Each byte is two hex digits.)
2142  *
2143  * @param source the string to encode
2144  * @param start byte index to start encoding
2145  * @param dest string where encoded data should be placed
2146  * @param insert_at where to place encoded data
2147  * @returns #TRUE if encoding was successful, #FALSE if no memory etc.
2148  */
2149 dbus_bool_t
2150 _dbus_string_hex_encode (const DBusString *source,
2151                          int               start,
2152                          DBusString       *dest,
2153                          int               insert_at)
2154 {
2155   DBusString result;
2156   const char hexdigits[16] = {
2157     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
2158     'a', 'b', 'c', 'd', 'e', 'f'
2159   };
2160   const unsigned char *p;
2161   const unsigned char *end;
2162   dbus_bool_t retval;
2163   
2164   _dbus_assert (start <= _dbus_string_get_length (source));
2165
2166   if (!_dbus_string_init (&result, _DBUS_INT_MAX))
2167     return FALSE;
2168
2169   retval = FALSE;
2170   
2171   _dbus_string_get_const_data (source, (const char**) &p);
2172   end = p + _dbus_string_get_length (source);
2173   p += start;
2174   
2175   while (p != end)
2176     {
2177       if (!_dbus_string_append_byte (&result,
2178                                      hexdigits[(*p >> 4)]))
2179         goto out;
2180       
2181       if (!_dbus_string_append_byte (&result,
2182                                      hexdigits[(*p & 0x0f)]))
2183         goto out;
2184
2185       ++p;
2186     }
2187
2188   if (!_dbus_string_move (&result, 0, dest, insert_at))
2189     goto out;
2190
2191   retval = TRUE;
2192
2193  out:
2194   _dbus_string_free (&result);
2195   return retval;
2196 }
2197
2198 /**
2199  * Decodes a string from hex encoding.
2200  *
2201  * @param source the string to decode
2202  * @param start byte index to start decode
2203  * @param dest string where decoded data should be placed
2204  * @param insert_at where to place decoded data
2205  * @returns #TRUE if decoding was successful, #FALSE if no memory etc.
2206  */
2207 dbus_bool_t
2208 _dbus_string_hex_decode (const DBusString *source,
2209                          int               start,
2210                          DBusString       *dest,
2211                          int               insert_at)
2212 {
2213   DBusString result;
2214   const unsigned char *p;
2215   const unsigned char *end;
2216   dbus_bool_t retval;
2217   dbus_bool_t high_bits;
2218   
2219   _dbus_assert (start <= _dbus_string_get_length (source));
2220
2221   if (!_dbus_string_init (&result, _DBUS_INT_MAX))
2222     return FALSE;
2223
2224   retval = FALSE;
2225
2226   high_bits = TRUE;
2227   _dbus_string_get_const_data (source, (const char**) &p);
2228   end = p + _dbus_string_get_length (source);
2229   p += start;
2230   
2231   while (p != end)
2232     {
2233       unsigned int val;
2234
2235       switch (*p)
2236         {
2237         case '0':
2238           val = 0;
2239           break;
2240         case '1':
2241           val = 1;
2242           break;
2243         case '2':
2244           val = 2;
2245           break;
2246         case '3':
2247           val = 3;
2248           break;
2249         case '4':
2250           val = 4;
2251           break;
2252         case '5':
2253           val = 5;
2254           break;
2255         case '6':
2256           val = 6;
2257           break;
2258         case '7':
2259           val = 7;
2260           break;
2261         case '8':
2262           val = 8;
2263           break;
2264         case '9':
2265           val = 9;
2266           break;
2267         case 'a':
2268         case 'A':
2269           val = 10;
2270           break;
2271         case 'b':
2272         case 'B':
2273           val = 11;
2274           break;
2275         case 'c':
2276         case 'C':
2277           val = 12;
2278           break;
2279         case 'd':
2280         case 'D':
2281           val = 13;
2282           break;
2283         case 'e':
2284         case 'E':
2285           val = 14;
2286           break;
2287         case 'f':
2288         case 'F':
2289           val = 15;
2290           break;
2291         default:
2292           val = 0;
2293           _dbus_verbose ("invalid character '%c' in hex encoded text\n",
2294                          *p);
2295           goto out;
2296         }
2297
2298       if (high_bits)
2299         {
2300           if (!_dbus_string_append_byte (&result,
2301                                          val << 4))
2302             goto out;
2303         }
2304       else
2305         {
2306           int len;
2307           unsigned char b;
2308
2309           len = _dbus_string_get_length (&result);
2310           
2311           b = _dbus_string_get_byte (&result, len - 1);
2312
2313           b |= val;
2314
2315           _dbus_string_set_byte (&result, len - 1, b);
2316         }
2317
2318       high_bits = !high_bits;
2319
2320       ++p;
2321     }
2322
2323   if (!_dbus_string_move (&result, 0, dest, insert_at))
2324     goto out;
2325
2326   retval = TRUE;
2327   
2328  out:
2329   _dbus_string_free (&result);  
2330   return retval;
2331 }
2332
2333 /**
2334  * Checks that the given range of the string is valid ASCII with no
2335  * nul bytes. If the given range is not entirely contained in the
2336  * string, returns #FALSE.
2337  *
2338  * @todo this is inconsistent with most of DBusString in that
2339  * it allows a start,len range that isn't in the string.
2340  * 
2341  * @param str the string
2342  * @param start first byte index to check
2343  * @param len number of bytes to check
2344  * @returns #TRUE if the byte range exists and is all valid ASCII
2345  */
2346 dbus_bool_t
2347 _dbus_string_validate_ascii (const DBusString *str,
2348                              int               start,
2349                              int               len)
2350 {
2351   const unsigned char *s;
2352   const unsigned char *end;
2353   DBUS_CONST_STRING_PREAMBLE (str);
2354   _dbus_assert (start >= 0);
2355   _dbus_assert (start <= real->len);
2356   _dbus_assert (len >= 0);
2357   
2358   if (len > real->len - start)
2359     return FALSE;
2360   
2361   s = real->str + start;
2362   end = s + len;
2363   while (s != end)
2364     {
2365       if (*s == '\0' ||
2366           ((*s & ~0x7f) != 0))
2367         return FALSE;
2368         
2369       ++s;
2370     }
2371   
2372   return TRUE;
2373 }
2374
2375 /**
2376  * Checks that the given range of the string is valid UTF-8. If the
2377  * given range is not entirely contained in the string, returns
2378  * #FALSE. If the string contains any nul bytes in the given range,
2379  * returns #FALSE.
2380  *
2381  * @todo right now just calls _dbus_string_validate_ascii()
2382  *
2383  * @todo this is inconsistent with most of DBusString in that
2384  * it allows a start,len range that isn't in the string.
2385  * 
2386  * @param str the string
2387  * @param start first byte index to check
2388  * @param len number of bytes to check
2389  * @returns #TRUE if the byte range exists and is all valid UTF-8
2390  */
2391 dbus_bool_t
2392 _dbus_string_validate_utf8  (const DBusString *str,
2393                              int               start,
2394                              int               len)
2395 {
2396   /* FIXME actually validate UTF-8 */
2397   return _dbus_string_validate_ascii (str, start, len);
2398 }
2399
2400 /**
2401  * Checks that the given range of the string is all nul bytes. If the
2402  * given range is not entirely contained in the string, returns
2403  * #FALSE.
2404  *
2405  * @todo this is inconsistent with most of DBusString in that
2406  * it allows a start,len range that isn't in the string.
2407  * 
2408  * @param str the string
2409  * @param start first byte index to check
2410  * @param len number of bytes to check
2411  * @returns #TRUE if the byte range exists and is all nul bytes
2412  */
2413 dbus_bool_t
2414 _dbus_string_validate_nul (const DBusString *str,
2415                            int               start,
2416                            int               len)
2417 {
2418   const unsigned char *s;
2419   const unsigned char *end;
2420   DBUS_CONST_STRING_PREAMBLE (str);
2421   _dbus_assert (start >= 0);
2422   _dbus_assert (len >= 0);
2423   _dbus_assert (start <= real->len);
2424   
2425   if (len > real->len - start)
2426     return FALSE;
2427   
2428   s = real->str + start;
2429   end = s + len;
2430   while (s != end)
2431     {
2432       if (*s != '\0')
2433         return FALSE;
2434       ++s;
2435     }
2436   
2437   return TRUE;
2438 }
2439
2440 /**
2441  * Clears all allocated bytes in the string to zero.
2442  *
2443  * @param str the string
2444  */
2445 void
2446 _dbus_string_zero (DBusString *str)
2447 {
2448   DBUS_STRING_PREAMBLE (str);
2449
2450   memset (real->str, '\0', real->allocated);
2451 }
2452 /** @} */
2453
2454 #ifdef DBUS_BUILD_TESTS
2455 #include "dbus-test.h"
2456 #include <stdio.h>
2457
2458 static void
2459 test_max_len (DBusString *str,
2460               int         max_len)
2461 {
2462   if (max_len > 0)
2463     {
2464       if (!_dbus_string_set_length (str, max_len - 1))
2465         _dbus_assert_not_reached ("setting len to one less than max should have worked");
2466     }
2467
2468   if (!_dbus_string_set_length (str, max_len))
2469     _dbus_assert_not_reached ("setting len to max len should have worked");
2470
2471   if (_dbus_string_set_length (str, max_len + 1))
2472     _dbus_assert_not_reached ("setting len to one more than max len should not have worked");
2473
2474   if (!_dbus_string_set_length (str, 0))
2475     _dbus_assert_not_reached ("setting len to zero should have worked");
2476 }
2477
2478 static void
2479 test_base64_roundtrip (const unsigned char *data,
2480                        int                  len)
2481 {
2482   DBusString orig;
2483   DBusString encoded;
2484   DBusString decoded;
2485
2486   if (len < 0)
2487     len = strlen (data);
2488   
2489   if (!_dbus_string_init (&orig, _DBUS_INT_MAX))
2490     _dbus_assert_not_reached ("could not init string");
2491
2492   if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
2493     _dbus_assert_not_reached ("could not init string");
2494   
2495   if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
2496     _dbus_assert_not_reached ("could not init string");
2497
2498   if (!_dbus_string_append_len (&orig, data, len))
2499     _dbus_assert_not_reached ("couldn't append orig data");
2500
2501   if (!_dbus_string_base64_encode (&orig, 0, &encoded, 0))
2502     _dbus_assert_not_reached ("could not encode");
2503
2504   if (!_dbus_string_base64_decode (&encoded, 0, &decoded, 0))
2505     _dbus_assert_not_reached ("could not decode");
2506
2507   if (!_dbus_string_equal (&orig, &decoded))
2508     {
2509       const char *s;
2510       
2511       printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n",
2512               _dbus_string_get_length (&orig),
2513               _dbus_string_get_length (&encoded),
2514               _dbus_string_get_length (&decoded));
2515       printf ("Original: %s\n", data);
2516       _dbus_string_get_const_data (&decoded, &s);
2517       printf ("Decoded: %s\n", s);
2518       _dbus_assert_not_reached ("original string not the same as string decoded from base64");
2519     }
2520   
2521   _dbus_string_free (&orig);
2522   _dbus_string_free (&encoded);
2523   _dbus_string_free (&decoded);  
2524 }
2525
2526 static void
2527 test_hex_roundtrip (const unsigned char *data,
2528                     int                  len)
2529 {
2530   DBusString orig;
2531   DBusString encoded;
2532   DBusString decoded;
2533
2534   if (len < 0)
2535     len = strlen (data);
2536   
2537   if (!_dbus_string_init (&orig, _DBUS_INT_MAX))
2538     _dbus_assert_not_reached ("could not init string");
2539
2540   if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
2541     _dbus_assert_not_reached ("could not init string");
2542   
2543   if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
2544     _dbus_assert_not_reached ("could not init string");
2545
2546   if (!_dbus_string_append_len (&orig, data, len))
2547     _dbus_assert_not_reached ("couldn't append orig data");
2548
2549   if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0))
2550     _dbus_assert_not_reached ("could not encode");
2551
2552   if (!_dbus_string_hex_decode (&encoded, 0, &decoded, 0))
2553     _dbus_assert_not_reached ("could not decode");
2554     
2555   if (!_dbus_string_equal (&orig, &decoded))
2556     {
2557       const char *s;
2558       
2559       printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n",
2560               _dbus_string_get_length (&orig),
2561               _dbus_string_get_length (&encoded),
2562               _dbus_string_get_length (&decoded));
2563       printf ("Original: %s\n", data);
2564       _dbus_string_get_const_data (&decoded, &s);
2565       printf ("Decoded: %s\n", s);
2566       _dbus_assert_not_reached ("original string not the same as string decoded from base64");
2567     }
2568   
2569   _dbus_string_free (&orig);
2570   _dbus_string_free (&encoded);
2571   _dbus_string_free (&decoded);  
2572 }
2573
2574 typedef void (* TestRoundtripFunc) (const unsigned char *data,
2575                                     int                  len);
2576 static void
2577 test_roundtrips (TestRoundtripFunc func)
2578 {
2579   (* func) ("Hello this is a string\n", -1);
2580   (* func) ("Hello this is a string\n1", -1);
2581   (* func) ("Hello this is a string\n12", -1);
2582   (* func) ("Hello this is a string\n123", -1);
2583   (* func) ("Hello this is a string\n1234", -1);
2584   (* func) ("Hello this is a string\n12345", -1);
2585   (* func) ("", 0);
2586   (* func) ("1", 1);
2587   (* func) ("12", 2);
2588   (* func) ("123", 3);
2589   (* func) ("1234", 4);
2590   (* func) ("12345", 5);
2591   (* func) ("", 1);
2592   (* func) ("1", 2);
2593   (* func) ("12", 3);
2594   (* func) ("123", 4);
2595   (* func) ("1234", 5);
2596   (* func) ("12345", 6);
2597   {
2598     unsigned char buf[512];
2599     int i;
2600     
2601     i = 0;
2602     while (i < _DBUS_N_ELEMENTS (buf))
2603       {
2604         buf[i] = i;
2605         ++i;
2606       }
2607     i = 0;
2608     while (i < _DBUS_N_ELEMENTS (buf))
2609       {
2610         (* func) (buf, i);
2611         ++i;
2612       }
2613   }
2614 }
2615
2616
2617 /**
2618  * @ingroup DBusStringInternals
2619  * Unit test for DBusString.
2620  *
2621  * @todo Need to write tests for _dbus_string_copy() and
2622  * _dbus_string_move() moving to/from each of start/middle/end of a
2623  * string. Also need tests for _dbus_string_move_len ()
2624  * 
2625  * @returns #TRUE on success.
2626  */
2627 dbus_bool_t
2628 _dbus_string_test (void)
2629 {
2630   DBusString str;
2631   DBusString other;
2632   int i, end;
2633   long v;
2634   double d;
2635   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 };
2636   char *s;
2637   dbus_unichar_t ch;
2638   
2639   i = 0;
2640   while (i < _DBUS_N_ELEMENTS (lens))
2641     {
2642       if (!_dbus_string_init (&str, lens[i]))
2643         _dbus_assert_not_reached ("failed to init string");
2644       
2645       test_max_len (&str, lens[i]);
2646       _dbus_string_free (&str);
2647
2648       ++i;
2649     }
2650
2651   /* Test shortening and setting length */
2652   i = 0;
2653   while (i < _DBUS_N_ELEMENTS (lens))
2654     {
2655       int j;
2656       
2657       if (!_dbus_string_init (&str, lens[i]))
2658         _dbus_assert_not_reached ("failed to init string");
2659       
2660       if (!_dbus_string_set_length (&str, lens[i]))
2661         _dbus_assert_not_reached ("failed to set string length");
2662
2663       j = lens[i];
2664       while (j > 0)
2665         {
2666           _dbus_assert (_dbus_string_get_length (&str) == j);
2667           if (j > 0)
2668             {
2669               _dbus_string_shorten (&str, 1);
2670               _dbus_assert (_dbus_string_get_length (&str) == (j - 1));
2671             }
2672           --j;
2673         }
2674       
2675       _dbus_string_free (&str);
2676
2677       ++i;
2678     }
2679
2680   /* Test appending data */
2681   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2682     _dbus_assert_not_reached ("failed to init string");
2683
2684   i = 0;
2685   while (i < 10)
2686     {
2687       if (!_dbus_string_append (&str, "a"))
2688         _dbus_assert_not_reached ("failed to append string to string\n");
2689
2690       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1);
2691
2692       if (!_dbus_string_append_byte (&str, 'b'))
2693         _dbus_assert_not_reached ("failed to append byte to string\n");
2694
2695       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2);
2696                     
2697       ++i;
2698     }
2699
2700   _dbus_string_free (&str);
2701
2702   /* Check steal_data */
2703   
2704   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2705     _dbus_assert_not_reached ("failed to init string");
2706
2707   if (!_dbus_string_append (&str, "Hello World"))
2708     _dbus_assert_not_reached ("could not append to string");
2709
2710   i = _dbus_string_get_length (&str);
2711   
2712   if (!_dbus_string_steal_data (&str, &s))
2713     _dbus_assert_not_reached ("failed to steal data");
2714
2715   _dbus_assert (_dbus_string_get_length (&str) == 0);
2716   _dbus_assert (((int)strlen (s)) == i);
2717
2718   dbus_free (s);
2719
2720   /* Check move */
2721   
2722   if (!_dbus_string_append (&str, "Hello World"))
2723     _dbus_assert_not_reached ("could not append to string");
2724
2725   i = _dbus_string_get_length (&str);
2726
2727   if (!_dbus_string_init (&other, _DBUS_INT_MAX))
2728     _dbus_assert_not_reached ("could not init string");
2729   
2730   if (!_dbus_string_move (&str, 0, &other, 0))
2731     _dbus_assert_not_reached ("could not move");
2732
2733   _dbus_assert (_dbus_string_get_length (&str) == 0);
2734   _dbus_assert (_dbus_string_get_length (&other) == i);
2735
2736   if (!_dbus_string_append (&str, "Hello World"))
2737     _dbus_assert_not_reached ("could not append to string");
2738   
2739   if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other)))
2740     _dbus_assert_not_reached ("could not move");
2741
2742   _dbus_assert (_dbus_string_get_length (&str) == 0);
2743   _dbus_assert (_dbus_string_get_length (&other) == i * 2);
2744
2745     if (!_dbus_string_append (&str, "Hello World"))
2746     _dbus_assert_not_reached ("could not append to string");
2747   
2748   if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2))
2749     _dbus_assert_not_reached ("could not move");
2750
2751   _dbus_assert (_dbus_string_get_length (&str) == 0);
2752   _dbus_assert (_dbus_string_get_length (&other) == i * 3);
2753   
2754   _dbus_string_free (&other);
2755
2756   /* Check copy */
2757   
2758   if (!_dbus_string_append (&str, "Hello World"))
2759     _dbus_assert_not_reached ("could not append to string");
2760
2761   i = _dbus_string_get_length (&str);
2762   
2763   if (!_dbus_string_init (&other, _DBUS_INT_MAX))
2764     _dbus_assert_not_reached ("could not init string");
2765   
2766   if (!_dbus_string_copy (&str, 0, &other, 0))
2767     _dbus_assert_not_reached ("could not copy");
2768
2769   _dbus_assert (_dbus_string_get_length (&str) == i);
2770   _dbus_assert (_dbus_string_get_length (&other) == i);
2771
2772   if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other)))
2773     _dbus_assert_not_reached ("could not copy");
2774
2775   _dbus_assert (_dbus_string_get_length (&str) == i);
2776   _dbus_assert (_dbus_string_get_length (&other) == i * 2);
2777   _dbus_assert (_dbus_string_equal_c_str (&other,
2778                                           "Hello WorldHello World"));
2779
2780   if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2))
2781     _dbus_assert_not_reached ("could not copy");
2782
2783   _dbus_assert (_dbus_string_get_length (&str) == i);
2784   _dbus_assert (_dbus_string_get_length (&other) == i * 3);
2785   _dbus_assert (_dbus_string_equal_c_str (&other,
2786                                           "Hello WorldHello WorldHello World"));
2787   
2788   _dbus_string_free (&str);
2789   _dbus_string_free (&other);
2790
2791   /* Check replace */
2792
2793   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2794     _dbus_assert_not_reached ("failed to init string");
2795   
2796   if (!_dbus_string_append (&str, "Hello World"))
2797     _dbus_assert_not_reached ("could not append to string");
2798
2799   i = _dbus_string_get_length (&str);
2800   
2801   if (!_dbus_string_init (&other, _DBUS_INT_MAX))
2802     _dbus_assert_not_reached ("could not init string");
2803   
2804   if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
2805                                  &other, 0, _dbus_string_get_length (&other)))
2806     _dbus_assert_not_reached ("could not replace");
2807
2808   _dbus_assert (_dbus_string_get_length (&str) == i);
2809   _dbus_assert (_dbus_string_get_length (&other) == i);
2810   _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World"));
2811   
2812   if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
2813                                  &other, 5, 1))
2814     _dbus_assert_not_reached ("could not replace center space");
2815
2816   _dbus_assert (_dbus_string_get_length (&str) == i);
2817   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
2818   _dbus_assert (_dbus_string_equal_c_str (&other,
2819                                           "HelloHello WorldWorld"));
2820
2821   
2822   if (!_dbus_string_replace_len (&str, 1, 1,
2823                                  &other,
2824                                  _dbus_string_get_length (&other) - 1,
2825                                  1))
2826     _dbus_assert_not_reached ("could not replace end character");
2827   
2828   _dbus_assert (_dbus_string_get_length (&str) == i);
2829   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
2830   _dbus_assert (_dbus_string_equal_c_str (&other,
2831                                           "HelloHello WorldWorle"));
2832   
2833   _dbus_string_free (&str);
2834   _dbus_string_free (&other);
2835   
2836   /* Check append/get unichar */
2837   
2838   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2839     _dbus_assert_not_reached ("failed to init string");
2840
2841   ch = 0;
2842   if (!_dbus_string_append_unichar (&str, 0xfffc))
2843     _dbus_assert_not_reached ("failed to append unichar");
2844
2845   _dbus_string_get_unichar (&str, 0, &ch, &i);
2846
2847   _dbus_assert (ch == 0xfffc);
2848   _dbus_assert (i == _dbus_string_get_length (&str));
2849
2850   _dbus_string_free (&str);
2851
2852   /* Check insert/set/get byte */
2853   
2854   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2855     _dbus_assert_not_reached ("failed to init string");
2856
2857   if (!_dbus_string_append (&str, "Hello"))
2858     _dbus_assert_not_reached ("failed to append Hello");
2859
2860   _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H');
2861   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e');
2862   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l');
2863   _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l');
2864   _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o');
2865
2866   _dbus_string_set_byte (&str, 1, 'q');
2867   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q');
2868
2869   if (!_dbus_string_insert_byte (&str, 0, 255))
2870     _dbus_assert_not_reached ("can't insert byte");
2871
2872   if (!_dbus_string_insert_byte (&str, 2, 'Z'))
2873     _dbus_assert_not_reached ("can't insert byte");
2874
2875   if (!_dbus_string_insert_byte (&str, _dbus_string_get_length (&str), 'W'))
2876     _dbus_assert_not_reached ("can't insert byte");
2877   
2878   _dbus_assert (_dbus_string_get_byte (&str, 0) == 255);
2879   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H');
2880   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z');
2881   _dbus_assert (_dbus_string_get_byte (&str, 3) == 'q');
2882   _dbus_assert (_dbus_string_get_byte (&str, 4) == 'l');
2883   _dbus_assert (_dbus_string_get_byte (&str, 5) == 'l');
2884   _dbus_assert (_dbus_string_get_byte (&str, 6) == 'o');
2885   _dbus_assert (_dbus_string_get_byte (&str, 7) == 'W');
2886
2887   _dbus_string_free (&str);
2888   
2889   /* Check append/parse int/double */
2890   
2891   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2892     _dbus_assert_not_reached ("failed to init string");
2893
2894   if (!_dbus_string_append_int (&str, 27))
2895     _dbus_assert_not_reached ("failed to append int");
2896
2897   i = _dbus_string_get_length (&str);
2898
2899   if (!_dbus_string_parse_int (&str, 0, &v, &end))
2900     _dbus_assert_not_reached ("failed to parse int");
2901
2902   _dbus_assert (v == 27);
2903   _dbus_assert (end == i);
2904
2905   _dbus_string_free (&str);
2906   
2907   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2908     _dbus_assert_not_reached ("failed to init string");
2909   
2910   if (!_dbus_string_append_double (&str, 50.3))
2911     _dbus_assert_not_reached ("failed to append float");
2912
2913   i = _dbus_string_get_length (&str);
2914
2915   if (!_dbus_string_parse_double (&str, 0, &d, &end))
2916     _dbus_assert_not_reached ("failed to parse float");
2917
2918   _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6));
2919   _dbus_assert (end == i);
2920
2921   _dbus_string_free (&str);
2922
2923   /* Test find */
2924   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2925     _dbus_assert_not_reached ("failed to init string");
2926
2927   if (!_dbus_string_append (&str, "Hello"))
2928     _dbus_assert_not_reached ("couldn't append to string");
2929   
2930   if (!_dbus_string_find (&str, 0, "He", &i))
2931     _dbus_assert_not_reached ("didn't find 'He'");
2932   _dbus_assert (i == 0);
2933
2934   if (!_dbus_string_find (&str, 0, "Hello", &i))
2935     _dbus_assert_not_reached ("didn't find 'Hello'");
2936   _dbus_assert (i == 0);
2937   
2938   if (!_dbus_string_find (&str, 0, "ello", &i))
2939     _dbus_assert_not_reached ("didn't find 'ello'");
2940   _dbus_assert (i == 1);
2941
2942   if (!_dbus_string_find (&str, 0, "lo", &i))
2943     _dbus_assert_not_reached ("didn't find 'lo'");
2944   _dbus_assert (i == 3);
2945
2946   if (!_dbus_string_find (&str, 2, "lo", &i))
2947     _dbus_assert_not_reached ("didn't find 'lo'");
2948   _dbus_assert (i == 3);
2949
2950   if (_dbus_string_find (&str, 4, "lo", &i))
2951     _dbus_assert_not_reached ("did find 'lo'");
2952   
2953   if (!_dbus_string_find (&str, 0, "l", &i))
2954     _dbus_assert_not_reached ("didn't find 'l'");
2955   _dbus_assert (i == 2);
2956
2957   if (!_dbus_string_find (&str, 0, "H", &i))
2958     _dbus_assert_not_reached ("didn't find 'H'");
2959   _dbus_assert (i == 0);
2960
2961   if (!_dbus_string_find (&str, 0, "", &i))
2962     _dbus_assert_not_reached ("didn't find ''");
2963   _dbus_assert (i == 0);
2964   
2965   if (_dbus_string_find (&str, 0, "Hello!", NULL))
2966     _dbus_assert_not_reached ("Did find 'Hello!'");
2967
2968   if (_dbus_string_find (&str, 0, "Oh, Hello", NULL))
2969     _dbus_assert_not_reached ("Did find 'Oh, Hello'");
2970   
2971   if (_dbus_string_find (&str, 0, "ill", NULL))
2972     _dbus_assert_not_reached ("Did find 'ill'");
2973
2974   if (_dbus_string_find (&str, 0, "q", NULL))
2975     _dbus_assert_not_reached ("Did find 'q'");
2976
2977   if (!_dbus_string_find_to (&str, 0, 2, "He", NULL))
2978     _dbus_assert_not_reached ("Didn't find 'He'");
2979
2980   if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL))
2981     _dbus_assert_not_reached ("Did find 'Hello'");
2982   
2983   _dbus_string_free (&str);
2984
2985   /* Base 64 and Hex encoding */
2986   test_roundtrips (test_base64_roundtrip);
2987   test_roundtrips (test_hex_roundtrip);
2988   
2989   return TRUE;
2990 }
2991
2992 #endif /* DBUS_BUILD_TESTS */