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