2003-02-18 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 or \r\n-terminated line from the front
1420  * of the string to the given dest string. The dest string's previous
1421  * contents are deleted. If the source string contains no newline,
1422  * moves the 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 and the \r if we have one */
1459   if (have_newline)
1460     {
1461       dbus_bool_t have_cr;
1462       
1463       _dbus_assert (_dbus_string_get_length (dest) > 0);
1464
1465       if (_dbus_string_get_length (dest) > 1 &&
1466           _dbus_string_get_byte (dest,
1467                                  _dbus_string_get_length (dest) - 2) == '\r')
1468         have_cr = TRUE;
1469       else
1470         have_cr = FALSE;
1471         
1472       _dbus_string_set_length (dest,
1473                                _dbus_string_get_length (dest) -
1474                                (have_cr ? 2 : 1));
1475     }
1476   
1477   return TRUE;
1478 }
1479
1480 /**
1481  * Deletes up to and including the first blank space
1482  * in the string.
1483  *
1484  * @param str the string
1485  */
1486 void
1487 _dbus_string_delete_first_word (DBusString *str)
1488 {
1489   int i;
1490   
1491   i = 0;
1492   if (_dbus_string_find_blank (str, 0, &i))
1493     _dbus_string_skip_blank (str, i, &i);
1494
1495   _dbus_string_delete (str, 0, i);
1496 }
1497
1498 /**
1499  * Deletes any leading blanks in the string
1500  *
1501  * @param str the string
1502  */
1503 void
1504 _dbus_string_delete_leading_blanks (DBusString *str)
1505 {
1506   int i;
1507   
1508   i = 0;
1509   _dbus_string_skip_blank (str, 0, &i);
1510
1511   if (i > 0)
1512     _dbus_string_delete (str, 0, i);
1513 }
1514
1515 /**
1516  * Tests two DBusString for equality.
1517  *
1518  * @param a first string
1519  * @param b second string
1520  * @returns #TRUE if equal
1521  */
1522 dbus_bool_t
1523 _dbus_string_equal (const DBusString *a,
1524                     const DBusString *b)
1525 {
1526   const unsigned char *ap;
1527   const unsigned char *bp;
1528   const unsigned char *a_end;
1529   const DBusRealString *real_a = (const DBusRealString*) a;
1530   const DBusRealString *real_b = (const DBusRealString*) b;
1531   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1532   DBUS_GENERIC_STRING_PREAMBLE (real_b);
1533
1534   if (real_a->len != real_b->len)
1535     return FALSE;
1536
1537   ap = real_a->str;
1538   bp = real_b->str;
1539   a_end = real_a->str + real_a->len;
1540   while (ap != a_end)
1541     {
1542       if (*ap != *bp)
1543         return FALSE;
1544       
1545       ++ap;
1546       ++bp;
1547     }
1548
1549   return TRUE;
1550 }
1551
1552 /**
1553  * Tests two DBusString for equality up to the given length.
1554  *
1555  * @todo write a unit test
1556  *
1557  * @param a first string
1558  * @param b second string
1559  * @param len the lengh
1560  * @returns #TRUE if equal for the given number of bytes
1561  */
1562 dbus_bool_t
1563 _dbus_string_equal_len (const DBusString *a,
1564                         const DBusString *b,
1565                         int               len)
1566 {
1567   const unsigned char *ap;
1568   const unsigned char *bp;
1569   const unsigned char *a_end;
1570   const DBusRealString *real_a = (const DBusRealString*) a;
1571   const DBusRealString *real_b = (const DBusRealString*) b;
1572   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1573   DBUS_GENERIC_STRING_PREAMBLE (real_b);
1574
1575   if (real_a->len != real_b->len &&
1576       (real_a->len < len || real_b->len < len))
1577     return FALSE;
1578
1579   ap = real_a->str;
1580   bp = real_b->str;
1581   a_end = real_a->str + MIN (real_a->len, len);
1582   while (ap != a_end)
1583     {
1584       if (*ap != *bp)
1585         return FALSE;
1586       
1587       ++ap;
1588       ++bp;
1589     }
1590
1591   return TRUE;
1592 }
1593
1594 /**
1595  * Checks whether a string is equal to a C string.
1596  *
1597  * @param a the string
1598  * @param c_str the C string
1599  * @returns #TRUE if equal
1600  */
1601 dbus_bool_t
1602 _dbus_string_equal_c_str (const DBusString *a,
1603                           const char       *c_str)
1604 {
1605   const unsigned char *ap;
1606   const unsigned char *bp;
1607   const unsigned char *a_end;
1608   const DBusRealString *real_a = (const DBusRealString*) a;
1609   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1610
1611   ap = real_a->str;
1612   bp = (const unsigned char*) c_str;
1613   a_end = real_a->str + real_a->len;
1614   while (ap != a_end && *bp)
1615     {
1616       if (*ap != *bp)
1617         return FALSE;
1618       
1619       ++ap;
1620       ++bp;
1621     }
1622
1623   if (*ap && *bp == '\0')
1624     return FALSE;
1625   else if (ap == a_end && *bp)
1626     return FALSE;
1627   
1628   return TRUE;
1629 }
1630
1631 /**
1632  * Checks whether a string starts with the given C string.
1633  *
1634  * @param a the string
1635  * @param c_str the C string
1636  * @returns #TRUE if string starts with it
1637  */
1638 dbus_bool_t
1639 _dbus_string_starts_with_c_str (const DBusString *a,
1640                                 const char       *c_str)
1641 {
1642   const unsigned char *ap;
1643   const unsigned char *bp;
1644   const unsigned char *a_end;
1645   const DBusRealString *real_a = (const DBusRealString*) a;
1646   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1647
1648   ap = real_a->str;
1649   bp = (const unsigned char*) c_str;
1650   a_end = real_a->str + real_a->len;
1651   while (ap != a_end && *bp)
1652     {
1653       if (*ap != *bp)
1654         return FALSE;
1655       
1656       ++ap;
1657       ++bp;
1658     }
1659
1660   if (*bp == '\0')
1661     return TRUE;
1662   else
1663     return FALSE;
1664 }
1665
1666 /**
1667  * Returns whether a string ends with the given suffix
1668  *
1669  * @param a the string
1670  * @param c_str the C-style string
1671  * @returns #TRUE if the string ends with the suffix
1672  */
1673 dbus_bool_t
1674 _dbus_string_ends_with_c_str (const DBusString *a,
1675                               const char       *c_str)
1676 {
1677   const unsigned char *ap;
1678   const unsigned char *bp;
1679   const unsigned char *a_end;
1680   int c_str_len;
1681   const DBusRealString *real_a = (const DBusRealString*) a;
1682   DBUS_GENERIC_STRING_PREAMBLE (real_a);
1683
1684   c_str_len = strlen (c_str);
1685   if (real_a->len < c_str_len)
1686     return FALSE;
1687   
1688   ap = real_a->str + (real_a->len - c_str_len);
1689   bp = (const unsigned char*) c_str;
1690   a_end = real_a->str + real_a->len;
1691   while (ap != a_end)
1692     {
1693       if (*ap != *bp)
1694         return FALSE;
1695       
1696       ++ap;
1697       ++bp;
1698     }
1699
1700   _dbus_assert (*ap == '\0');
1701   _dbus_assert (*bp == '\0');
1702   
1703   return TRUE;
1704 }
1705
1706 static const signed char base64_table[] = {
1707   /* 0 */ 'A',
1708   /* 1 */ 'B',
1709   /* 2 */ 'C',
1710   /* 3 */ 'D',
1711   /* 4 */ 'E',
1712   /* 5 */ 'F',
1713   /* 6 */ 'G',
1714   /* 7 */ 'H',
1715   /* 8 */ 'I',
1716   /* 9 */ 'J',
1717   /* 10 */ 'K',
1718   /* 11 */ 'L',
1719   /* 12 */ 'M',
1720   /* 13 */ 'N',
1721   /* 14 */ 'O',
1722   /* 15 */ 'P',
1723   /* 16 */ 'Q',
1724   /* 17 */ 'R',
1725   /* 18 */ 'S',
1726   /* 19 */ 'T',
1727   /* 20 */ 'U',
1728   /* 21 */ 'V',
1729   /* 22 */ 'W',
1730   /* 23 */ 'X',
1731   /* 24 */ 'Y',
1732   /* 25 */ 'Z',
1733   /* 26 */ 'a',
1734   /* 27 */ 'b',
1735   /* 28 */ 'c',
1736   /* 29 */ 'd',
1737   /* 30 */ 'e',
1738   /* 31 */ 'f',
1739   /* 32 */ 'g',
1740   /* 33 */ 'h',
1741   /* 34 */ 'i',
1742   /* 35 */ 'j',
1743   /* 36 */ 'k',
1744   /* 37 */ 'l',
1745   /* 38 */ 'm',
1746   /* 39 */ 'n',
1747   /* 40 */ 'o',
1748   /* 41 */ 'p',
1749   /* 42 */ 'q',
1750   /* 43 */ 'r',
1751   /* 44 */ 's',
1752   /* 45 */ 't',
1753   /* 46 */ 'u',
1754   /* 47 */ 'v',
1755   /* 48 */ 'w',
1756   /* 49 */ 'x',
1757   /* 50 */ 'y',
1758   /* 51 */ 'z',
1759   /* 52 */ '0',
1760   /* 53 */ '1',
1761   /* 54 */ '2',
1762   /* 55 */ '3',
1763   /* 56 */ '4',
1764   /* 57 */ '5',
1765   /* 58 */ '6',
1766   /* 59 */ '7',
1767   /* 60 */ '8',
1768   /* 61 */ '9',
1769   /* 62 */ '+',
1770   /* 63 */ '/'
1771 };
1772
1773 /** The minimum char that's a valid char in Base64-encoded text */
1774 #define UNBASE64_MIN_CHAR (43)
1775 /** The maximum char that's a valid char in Base64-encoded text */
1776 #define UNBASE64_MAX_CHAR (122)
1777 /** Must subtract this from a char's integer value before offsetting
1778  * into unbase64_table
1779  */
1780 #define UNBASE64_TABLE_OFFSET UNBASE64_MIN_CHAR
1781 static const signed char unbase64_table[] = {
1782   /* 43 + */ 62,
1783   /* 44 , */ -1,
1784   /* 45 - */ -1,
1785   /* 46 . */ -1,
1786   /* 47 / */ 63,
1787   /* 48 0 */ 52,
1788   /* 49 1 */ 53,
1789   /* 50 2 */ 54,
1790   /* 51 3 */ 55,
1791   /* 52 4 */ 56,
1792   /* 53 5 */ 57,
1793   /* 54 6 */ 58,
1794   /* 55 7 */ 59,
1795   /* 56 8 */ 60,
1796   /* 57 9 */ 61,
1797   /* 58 : */ -1,
1798   /* 59 ; */ -1,
1799   /* 60 < */ -1,
1800   /* 61 = */ -1,
1801   /* 62 > */ -1,
1802   /* 63 ? */ -1,
1803   /* 64 @ */ -1,
1804   /* 65 A */ 0,
1805   /* 66 B */ 1,
1806   /* 67 C */ 2,
1807   /* 68 D */ 3,
1808   /* 69 E */ 4,
1809   /* 70 F */ 5,
1810   /* 71 G */ 6,
1811   /* 72 H */ 7,
1812   /* 73 I */ 8,
1813   /* 74 J */ 9,
1814   /* 75 K */ 10,
1815   /* 76 L */ 11,
1816   /* 77 M */ 12,
1817   /* 78 N */ 13,
1818   /* 79 O */ 14,
1819   /* 80 P */ 15,
1820   /* 81 Q */ 16,
1821   /* 82 R */ 17,
1822   /* 83 S */ 18,
1823   /* 84 T */ 19,
1824   /* 85 U */ 20,
1825   /* 86 V */ 21,
1826   /* 87 W */ 22,
1827   /* 88 X */ 23,
1828   /* 89 Y */ 24,
1829   /* 90 Z */ 25,
1830   /* 91 [ */ -1,
1831   /* 92 \ */ -1,
1832   /* 93 ] */ -1,
1833   /* 94 ^ */ -1,
1834   /* 95 _ */ -1,
1835   /* 96 ` */ -1,
1836   /* 97 a */ 26,
1837   /* 98 b */ 27,
1838   /* 99 c */ 28,
1839   /* 100 d */ 29,
1840   /* 101 e */ 30,
1841   /* 102 f */ 31,
1842   /* 103 g */ 32,
1843   /* 104 h */ 33,
1844   /* 105 i */ 34,
1845   /* 106 j */ 35,
1846   /* 107 k */ 36,
1847   /* 108 l */ 37,
1848   /* 109 m */ 38,
1849   /* 110 n */ 39,
1850   /* 111 o */ 40,
1851   /* 112 p */ 41,
1852   /* 113 q */ 42,
1853   /* 114 r */ 43,
1854   /* 115 s */ 44,
1855   /* 116 t */ 45,
1856   /* 117 u */ 46,
1857   /* 118 v */ 47,
1858   /* 119 w */ 48,
1859   /* 120 x */ 49,
1860   /* 121 y */ 50,
1861   /* 122 z */ 51
1862 };
1863
1864 /**
1865  * Encodes a string using Base64, as documented in RFC 2045.
1866  *
1867  * @param source the string to encode
1868  * @param start byte index to start encoding
1869  * @param dest string where encoded data should be placed
1870  * @param insert_at where to place encoded data
1871  * @returns #TRUE if encoding was successful, #FALSE if no memory etc.
1872  */
1873 dbus_bool_t
1874 _dbus_string_base64_encode (const DBusString *source,
1875                             int               start,
1876                             DBusString       *dest,
1877                             int               insert_at)
1878 {
1879   int source_len;
1880   int dest_len;
1881   const unsigned char *s;
1882   unsigned char *d;
1883   const unsigned char *triplet_end;
1884   const unsigned char *final_end;
1885   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);  
1886   _dbus_assert (source != dest);
1887   
1888   /* For each 24 bits (3 bytes) of input, we have 4 chars of
1889    * output.
1890    */
1891   source_len = real_source->len - start;
1892   dest_len = (source_len / 3) * 4;
1893   if (source_len % 3 != 0)
1894     dest_len += 4;
1895
1896   if (source_len == 0)
1897     return TRUE;
1898   
1899   if (!open_gap (dest_len, real_dest, insert_at))
1900     return FALSE;
1901
1902   d = real_dest->str + insert_at;
1903   s = real_source->str + start;
1904   final_end = real_source->str + (start + source_len);
1905   triplet_end = final_end - (source_len % 3);
1906   _dbus_assert (triplet_end <= final_end);
1907   _dbus_assert ((final_end - triplet_end) < 3);
1908
1909 #define ENCODE_64(v) (base64_table[ (unsigned char) (v) ])
1910 #define SIX_BITS_MASK (0x3f)
1911   _dbus_assert (SIX_BITS_MASK < _DBUS_N_ELEMENTS (base64_table));
1912   
1913   while (s != triplet_end)
1914     {
1915       unsigned int triplet;
1916
1917       triplet = s[2] | (s[1] << 8) | (s[0] << 16);
1918
1919       /* Encode each 6 bits. */
1920
1921       *d++ = ENCODE_64 (triplet >> 18);
1922       *d++ = ENCODE_64 ((triplet >> 12) & SIX_BITS_MASK);
1923       *d++ = ENCODE_64 ((triplet >> 6) & SIX_BITS_MASK);
1924       *d++ = ENCODE_64 (triplet & SIX_BITS_MASK);
1925       
1926       s += 3;
1927     }
1928
1929   switch (final_end - triplet_end)
1930     {
1931     case 2:
1932       {
1933         unsigned int doublet;
1934         
1935         doublet = s[1] | (s[0] << 8);        
1936
1937         *d++ = ENCODE_64 (doublet >> 12);
1938         *d++ = ENCODE_64 ((doublet >> 6) & SIX_BITS_MASK);
1939         *d++ = ENCODE_64 (doublet & SIX_BITS_MASK);
1940         *d++ = '=';
1941       }
1942       break;
1943     case 1:
1944       {
1945         unsigned int singlet;
1946         
1947         singlet = s[0];
1948
1949         *d++ = ENCODE_64 ((singlet >> 6) & SIX_BITS_MASK);
1950         *d++ = ENCODE_64 (singlet & SIX_BITS_MASK);
1951         *d++ = '=';
1952         *d++ = '=';
1953       }
1954       break;
1955     case 0:
1956       break;
1957     }
1958
1959   _dbus_assert (d == (real_dest->str + (insert_at + dest_len)));
1960
1961   return TRUE;
1962 }
1963
1964
1965 /**
1966  * Decodes a string from Base64, as documented in RFC 2045.
1967  *
1968  * @param source the string to decode
1969  * @param start byte index to start decode
1970  * @param dest string where decoded data should be placed
1971  * @param insert_at where to place decoded data
1972  * @returns #TRUE if decoding was successful, #FALSE if no memory etc.
1973  */
1974 dbus_bool_t
1975 _dbus_string_base64_decode (const DBusString *source,
1976                             int               start,
1977                             DBusString       *dest,
1978                             int               insert_at)
1979 {
1980   int source_len;
1981   const char *s;
1982   const char *end;
1983   DBusString result;
1984   unsigned int triplet = 0;
1985   int sextet_count;
1986   int pad_count;
1987   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
1988   _dbus_assert (source != dest);
1989   
1990   source_len = real_source->len - start;
1991   s = real_source->str + start;
1992   end = real_source->str + source_len;
1993
1994   if (source_len == 0)
1995     return TRUE;
1996
1997   if (!_dbus_string_init (&result, _DBUS_INT_MAX))
1998     return FALSE;
1999
2000   pad_count = 0;
2001   sextet_count = 0;
2002   while (s != end)
2003     {
2004       /* The idea is to just skip anything that isn't
2005        * a base64 char - it's allowed to have whitespace,
2006        * newlines, etc. in here. We also ignore trailing
2007        * base64 chars, though that's suspicious.
2008        */
2009       
2010       if (*s >= UNBASE64_MIN_CHAR &&
2011           *s <= UNBASE64_MAX_CHAR)
2012         {
2013           if (*s == '=')
2014             {
2015               /* '=' is padding, doesn't represent additional data
2016                * but does increment our count.
2017                */
2018               pad_count += 1;
2019               sextet_count += 1;
2020             }
2021           else
2022             {
2023               int val;
2024
2025               val = unbase64_table[(*s) - UNBASE64_TABLE_OFFSET];
2026
2027               if (val >= 0)
2028                 {
2029                   triplet <<= 6;
2030                   triplet |= (unsigned int) val;
2031                   sextet_count += 1;
2032                 }
2033             }
2034
2035           if (sextet_count == 4)
2036             {
2037               /* no pad = 3 bytes, 1 pad = 2 bytes, 2 pad = 1 byte */
2038               if (pad_count < 1)
2039                 _dbus_string_append_byte (&result,
2040                                           triplet >> 16);
2041               
2042               if (pad_count < 2)
2043                 _dbus_string_append_byte (&result,
2044                                           (triplet >> 8) & 0xff);              
2045               
2046               _dbus_string_append_byte (&result,
2047                                         triplet & 0xff);
2048               
2049               sextet_count = 0;
2050               pad_count = 0;
2051               triplet = 0;
2052             }
2053         }
2054       
2055       ++s;
2056     }
2057
2058   if (!_dbus_string_move (&result, 0, dest, insert_at))
2059     {
2060       _dbus_string_free (&result);
2061       return FALSE;
2062     }
2063
2064   _dbus_string_free (&result);
2065
2066   return TRUE;
2067 }
2068
2069 /**
2070  * Checks that the given range of the string
2071  * is valid ASCII. If the given range is not contained
2072  * in the string, returns #FALSE.
2073  *
2074  * @param str the string
2075  * @param start first byte index to check
2076  * @param len number of bytes to check
2077  * @returns #TRUE if the byte range exists and is all valid ASCII
2078  */
2079 dbus_bool_t
2080 _dbus_string_validate_ascii (const DBusString *str,
2081                              int               start,
2082                              int               len)
2083 {
2084   const unsigned char *s;
2085   const unsigned char *end;
2086   DBUS_CONST_STRING_PREAMBLE (str);
2087   _dbus_assert (start >= 0);
2088   _dbus_assert (len >= 0);
2089   
2090   if ((start + len) > real->len)
2091     return FALSE;
2092   
2093   s = real->str + start;
2094   end = s + len;
2095   while (s != end)
2096     {
2097       if (*s == '\0' ||
2098           ((*s & ~0x7f) != 0))
2099         return FALSE;
2100         
2101       ++s;
2102     }
2103   
2104   return TRUE;
2105 }
2106
2107 /**
2108  * Checks that the given range of the string
2109  * is valid UTF-8. If the given range is not contained
2110  * in the string, returns #FALSE. If the string
2111  * contains any nul bytes in the given range, returns
2112  * #FALSE.
2113  *
2114  * @todo right now just calls _dbus_string_validate_ascii()
2115  * 
2116  * @param str the string
2117  * @param start first byte index to check
2118  * @param len number of bytes to check
2119  * @returns #TRUE if the byte range exists and is all valid UTF-8
2120  */
2121 dbus_bool_t
2122 _dbus_string_validate_utf8  (const DBusString *str,
2123                              int               start,
2124                              int               len)
2125 {
2126   /* FIXME actually validate UTF-8 */
2127   return _dbus_string_validate_ascii (str, start, len);
2128 }
2129
2130 /**
2131  * Checks that the given range of the string
2132  * is all nul bytes. If the given range is
2133  * not contained in the string, returns #FALSE.
2134  * 
2135  * @param str the string
2136  * @param start first byte index to check
2137  * @param len number of bytes to check
2138  * @returns #TRUE if the byte range exists and is all nul bytes
2139  */
2140 dbus_bool_t
2141 _dbus_string_validate_nul (const DBusString *str,
2142                            int               start,
2143                            int               len)
2144 {
2145   const unsigned char *s;
2146   const unsigned char *end;
2147   DBUS_CONST_STRING_PREAMBLE (str);
2148   _dbus_assert (start >= 0);
2149   _dbus_assert (len >= 0);
2150   
2151   if ((start + len) > real->len)
2152     return FALSE;
2153   
2154   s = real->str + start;
2155   end = s + len;
2156   while (s != end)
2157     {
2158       if (*s != '\0')
2159         return FALSE;
2160       ++s;
2161     }
2162   
2163   return TRUE;
2164 }
2165
2166 /**
2167  * Clears all allocated bytes in the string to zero.
2168  *
2169  * @param the string
2170  */
2171 void
2172 _dbus_string_zero (DBusString *str)
2173 {
2174   DBUS_STRING_PREAMBLE (str);
2175
2176   memset (real->str, '\0', real->allocated);
2177 }
2178
2179 /** @} */
2180
2181 #ifdef DBUS_BUILD_TESTS
2182 #include "dbus-test.h"
2183 #include <stdio.h>
2184
2185 static void
2186 test_max_len (DBusString *str,
2187               int         max_len)
2188 {
2189   if (max_len > 0)
2190     {
2191       if (!_dbus_string_set_length (str, max_len - 1))
2192         _dbus_assert_not_reached ("setting len to one less than max should have worked");
2193     }
2194
2195   if (!_dbus_string_set_length (str, max_len))
2196     _dbus_assert_not_reached ("setting len to max len should have worked");
2197
2198   if (_dbus_string_set_length (str, max_len + 1))
2199     _dbus_assert_not_reached ("setting len to one more than max len should not have worked");
2200
2201   if (!_dbus_string_set_length (str, 0))
2202     _dbus_assert_not_reached ("setting len to zero should have worked");
2203 }
2204
2205 static void
2206 test_base64_roundtrip (const unsigned char *data,
2207                        int                  len)
2208 {
2209   DBusString orig;
2210   DBusString encoded;
2211   DBusString decoded;
2212
2213   if (len < 0)
2214     len = strlen (data);
2215   
2216   if (!_dbus_string_init (&orig, _DBUS_INT_MAX))
2217     _dbus_assert_not_reached ("could not init string");
2218
2219   if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
2220     _dbus_assert_not_reached ("could not init string");
2221   
2222   if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
2223     _dbus_assert_not_reached ("could not init string");
2224
2225   if (!_dbus_string_append_len (&orig, data, len))
2226     _dbus_assert_not_reached ("couldn't append orig data");
2227
2228   if (!_dbus_string_base64_encode (&orig, 0, &encoded, 0))
2229     _dbus_assert_not_reached ("could not encode");
2230
2231   if (!_dbus_string_base64_decode (&encoded, 0, &decoded, 0))
2232     _dbus_assert_not_reached ("could not decode");
2233
2234   if (!_dbus_string_equal (&orig, &decoded))
2235     {
2236       const char *s;
2237       
2238       printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n",
2239               _dbus_string_get_length (&orig),
2240               _dbus_string_get_length (&encoded),
2241               _dbus_string_get_length (&decoded));
2242       printf ("Original: %s\n", data);
2243       _dbus_string_get_const_data (&decoded, &s);
2244       printf ("Decoded: %s\n", s);
2245       _dbus_assert_not_reached ("original string not the same as string decoded from base64");
2246     }
2247   
2248   _dbus_string_free (&orig);
2249   _dbus_string_free (&encoded);
2250   _dbus_string_free (&decoded);  
2251 }
2252
2253 /**
2254  * @ingroup DBusStringInternals
2255  * Unit test for DBusString.
2256  *
2257  * @todo Need to write tests for _dbus_string_copy() and
2258  * _dbus_string_move() moving to/from each of start/middle/end of a
2259  * string. Also need tests for _dbus_string_move_len ()
2260  * 
2261  * @returns #TRUE on success.
2262  */
2263 dbus_bool_t
2264 _dbus_string_test (void)
2265 {
2266   DBusString str;
2267   DBusString other;
2268   int i, end;
2269   long v;
2270   double d;
2271   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 };
2272   char *s;
2273   dbus_unichar_t ch;
2274   
2275   i = 0;
2276   while (i < _DBUS_N_ELEMENTS (lens))
2277     {
2278       if (!_dbus_string_init (&str, lens[i]))
2279         _dbus_assert_not_reached ("failed to init string");
2280       
2281       test_max_len (&str, lens[i]);
2282       _dbus_string_free (&str);
2283
2284       ++i;
2285     }
2286
2287   /* Test shortening and setting length */
2288   i = 0;
2289   while (i < _DBUS_N_ELEMENTS (lens))
2290     {
2291       int j;
2292       
2293       if (!_dbus_string_init (&str, lens[i]))
2294         _dbus_assert_not_reached ("failed to init string");
2295       
2296       if (!_dbus_string_set_length (&str, lens[i]))
2297         _dbus_assert_not_reached ("failed to set string length");
2298
2299       j = lens[i];
2300       while (j > 0)
2301         {
2302           _dbus_assert (_dbus_string_get_length (&str) == j);
2303           if (j > 0)
2304             {
2305               _dbus_string_shorten (&str, 1);
2306               _dbus_assert (_dbus_string_get_length (&str) == (j - 1));
2307             }
2308           --j;
2309         }
2310       
2311       _dbus_string_free (&str);
2312
2313       ++i;
2314     }
2315
2316   /* Test appending data */
2317   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2318     _dbus_assert_not_reached ("failed to init string");
2319
2320   i = 0;
2321   while (i < 10)
2322     {
2323       if (!_dbus_string_append (&str, "a"))
2324         _dbus_assert_not_reached ("failed to append string to string\n");
2325
2326       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1);
2327
2328       if (!_dbus_string_append_byte (&str, 'b'))
2329         _dbus_assert_not_reached ("failed to append byte to string\n");
2330
2331       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2);
2332                     
2333       ++i;
2334     }
2335
2336   _dbus_string_free (&str);
2337
2338   /* Check steal_data */
2339   
2340   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2341     _dbus_assert_not_reached ("failed to init string");
2342
2343   if (!_dbus_string_append (&str, "Hello World"))
2344     _dbus_assert_not_reached ("could not append to string");
2345
2346   i = _dbus_string_get_length (&str);
2347   
2348   if (!_dbus_string_steal_data (&str, &s))
2349     _dbus_assert_not_reached ("failed to steal data");
2350
2351   _dbus_assert (_dbus_string_get_length (&str) == 0);
2352   _dbus_assert (((int)strlen (s)) == i);
2353
2354   dbus_free (s);
2355
2356   /* Check move */
2357   
2358   if (!_dbus_string_append (&str, "Hello World"))
2359     _dbus_assert_not_reached ("could not append to string");
2360
2361   i = _dbus_string_get_length (&str);
2362
2363   if (!_dbus_string_init (&other, _DBUS_INT_MAX))
2364     _dbus_assert_not_reached ("could not init string");
2365   
2366   if (!_dbus_string_move (&str, 0, &other, 0))
2367     _dbus_assert_not_reached ("could not move");
2368
2369   _dbus_assert (_dbus_string_get_length (&str) == 0);
2370   _dbus_assert (_dbus_string_get_length (&other) == i);
2371
2372   if (!_dbus_string_append (&str, "Hello World"))
2373     _dbus_assert_not_reached ("could not append to string");
2374   
2375   if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other)))
2376     _dbus_assert_not_reached ("could not move");
2377
2378   _dbus_assert (_dbus_string_get_length (&str) == 0);
2379   _dbus_assert (_dbus_string_get_length (&other) == i * 2);
2380
2381     if (!_dbus_string_append (&str, "Hello World"))
2382     _dbus_assert_not_reached ("could not append to string");
2383   
2384   if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2))
2385     _dbus_assert_not_reached ("could not move");
2386
2387   _dbus_assert (_dbus_string_get_length (&str) == 0);
2388   _dbus_assert (_dbus_string_get_length (&other) == i * 3);
2389   
2390   _dbus_string_free (&other);
2391
2392   /* Check copy */
2393   
2394   if (!_dbus_string_append (&str, "Hello World"))
2395     _dbus_assert_not_reached ("could not append to string");
2396
2397   i = _dbus_string_get_length (&str);
2398   
2399   if (!_dbus_string_init (&other, _DBUS_INT_MAX))
2400     _dbus_assert_not_reached ("could not init string");
2401   
2402   if (!_dbus_string_copy (&str, 0, &other, 0))
2403     _dbus_assert_not_reached ("could not copy");
2404
2405   _dbus_assert (_dbus_string_get_length (&str) == i);
2406   _dbus_assert (_dbus_string_get_length (&other) == i);
2407
2408   if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other)))
2409     _dbus_assert_not_reached ("could not copy");
2410
2411   _dbus_assert (_dbus_string_get_length (&str) == i);
2412   _dbus_assert (_dbus_string_get_length (&other) == i * 2);
2413   _dbus_assert (_dbus_string_equal_c_str (&other,
2414                                           "Hello WorldHello World"));
2415
2416   if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2))
2417     _dbus_assert_not_reached ("could not copy");
2418
2419   _dbus_assert (_dbus_string_get_length (&str) == i);
2420   _dbus_assert (_dbus_string_get_length (&other) == i * 3);
2421   _dbus_assert (_dbus_string_equal_c_str (&other,
2422                                           "Hello WorldHello WorldHello World"));
2423   
2424   _dbus_string_free (&str);
2425   _dbus_string_free (&other);
2426
2427   /* Check replace */
2428
2429   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2430     _dbus_assert_not_reached ("failed to init string");
2431   
2432   if (!_dbus_string_append (&str, "Hello World"))
2433     _dbus_assert_not_reached ("could not append to string");
2434
2435   i = _dbus_string_get_length (&str);
2436   
2437   if (!_dbus_string_init (&other, _DBUS_INT_MAX))
2438     _dbus_assert_not_reached ("could not init string");
2439   
2440   if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
2441                                  &other, 0, _dbus_string_get_length (&other)))
2442     _dbus_assert_not_reached ("could not replace");
2443
2444   _dbus_assert (_dbus_string_get_length (&str) == i);
2445   _dbus_assert (_dbus_string_get_length (&other) == i);
2446   _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World"));
2447   
2448   if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
2449                                  &other, 5, 1))
2450     _dbus_assert_not_reached ("could not replace center space");
2451
2452   _dbus_assert (_dbus_string_get_length (&str) == i);
2453   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
2454   _dbus_assert (_dbus_string_equal_c_str (&other,
2455                                           "HelloHello WorldWorld"));
2456
2457   
2458   if (!_dbus_string_replace_len (&str, 1, 1,
2459                                  &other,
2460                                  _dbus_string_get_length (&other) - 1,
2461                                  1))
2462     _dbus_assert_not_reached ("could not replace end character");
2463   
2464   _dbus_assert (_dbus_string_get_length (&str) == i);
2465   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
2466   _dbus_assert (_dbus_string_equal_c_str (&other,
2467                                           "HelloHello WorldWorle"));
2468   
2469   _dbus_string_free (&str);
2470   _dbus_string_free (&other);
2471   
2472   /* Check append/get unichar */
2473   
2474   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2475     _dbus_assert_not_reached ("failed to init string");
2476
2477   ch = 0;
2478   if (!_dbus_string_append_unichar (&str, 0xfffc))
2479     _dbus_assert_not_reached ("failed to append unichar");
2480
2481   _dbus_string_get_unichar (&str, 0, &ch, &i);
2482
2483   _dbus_assert (ch == 0xfffc);
2484   _dbus_assert (i == _dbus_string_get_length (&str));
2485
2486   _dbus_string_free (&str);
2487
2488   /* Check insert/set/get byte */
2489   
2490   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2491     _dbus_assert_not_reached ("failed to init string");
2492
2493   if (!_dbus_string_append (&str, "Hello"))
2494     _dbus_assert_not_reached ("failed to append Hello");
2495
2496   _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H');
2497   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e');
2498   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l');
2499   _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l');
2500   _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o');
2501
2502   _dbus_string_set_byte (&str, 1, 'q');
2503   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q');
2504
2505   if (!_dbus_string_insert_byte (&str, 0, 255))
2506     _dbus_assert_not_reached ("can't insert byte");
2507
2508   if (!_dbus_string_insert_byte (&str, 2, 'Z'))
2509     _dbus_assert_not_reached ("can't insert byte");
2510
2511   if (!_dbus_string_insert_byte (&str, _dbus_string_get_length (&str), 'W'))
2512     _dbus_assert_not_reached ("can't insert byte");
2513   
2514   _dbus_assert (_dbus_string_get_byte (&str, 0) == 255);
2515   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H');
2516   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z');
2517   _dbus_assert (_dbus_string_get_byte (&str, 3) == 'q');
2518   _dbus_assert (_dbus_string_get_byte (&str, 4) == 'l');
2519   _dbus_assert (_dbus_string_get_byte (&str, 5) == 'l');
2520   _dbus_assert (_dbus_string_get_byte (&str, 6) == 'o');
2521   _dbus_assert (_dbus_string_get_byte (&str, 7) == 'W');
2522
2523   _dbus_string_free (&str);
2524   
2525   /* Check append/parse int/double */
2526   
2527   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2528     _dbus_assert_not_reached ("failed to init string");
2529
2530   if (!_dbus_string_append_int (&str, 27))
2531     _dbus_assert_not_reached ("failed to append int");
2532
2533   i = _dbus_string_get_length (&str);
2534
2535   if (!_dbus_string_parse_int (&str, 0, &v, &end))
2536     _dbus_assert_not_reached ("failed to parse int");
2537
2538   _dbus_assert (v == 27);
2539   _dbus_assert (end == i);
2540
2541   _dbus_string_free (&str);
2542   
2543   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2544     _dbus_assert_not_reached ("failed to init string");
2545   
2546   if (!_dbus_string_append_double (&str, 50.3))
2547     _dbus_assert_not_reached ("failed to append float");
2548
2549   i = _dbus_string_get_length (&str);
2550
2551   if (!_dbus_string_parse_double (&str, 0, &d, &end))
2552     _dbus_assert_not_reached ("failed to parse float");
2553
2554   _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6));
2555   _dbus_assert (end == i);
2556
2557   _dbus_string_free (&str);
2558
2559   /* Test find */
2560   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
2561     _dbus_assert_not_reached ("failed to init string");
2562
2563   if (!_dbus_string_append (&str, "Hello"))
2564     _dbus_assert_not_reached ("couldn't append to string");
2565   
2566   if (!_dbus_string_find (&str, 0, "He", &i))
2567     _dbus_assert_not_reached ("didn't find 'He'");
2568   _dbus_assert (i == 0);
2569
2570   if (!_dbus_string_find (&str, 0, "Hello", &i))
2571     _dbus_assert_not_reached ("didn't find 'Hello'");
2572   _dbus_assert (i == 0);
2573   
2574   if (!_dbus_string_find (&str, 0, "ello", &i))
2575     _dbus_assert_not_reached ("didn't find 'ello'");
2576   _dbus_assert (i == 1);
2577
2578   if (!_dbus_string_find (&str, 0, "lo", &i))
2579     _dbus_assert_not_reached ("didn't find 'lo'");
2580   _dbus_assert (i == 3);
2581
2582   if (!_dbus_string_find (&str, 2, "lo", &i))
2583     _dbus_assert_not_reached ("didn't find 'lo'");
2584   _dbus_assert (i == 3);
2585
2586   if (_dbus_string_find (&str, 4, "lo", &i))
2587     _dbus_assert_not_reached ("did find 'lo'");
2588   
2589   if (!_dbus_string_find (&str, 0, "l", &i))
2590     _dbus_assert_not_reached ("didn't find 'l'");
2591   _dbus_assert (i == 2);
2592
2593   if (!_dbus_string_find (&str, 0, "H", &i))
2594     _dbus_assert_not_reached ("didn't find 'H'");
2595   _dbus_assert (i == 0);
2596
2597   if (!_dbus_string_find (&str, 0, "", &i))
2598     _dbus_assert_not_reached ("didn't find ''");
2599   _dbus_assert (i == 0);
2600   
2601   if (_dbus_string_find (&str, 0, "Hello!", NULL))
2602     _dbus_assert_not_reached ("Did find 'Hello!'");
2603
2604   if (_dbus_string_find (&str, 0, "Oh, Hello", NULL))
2605     _dbus_assert_not_reached ("Did find 'Oh, Hello'");
2606   
2607   if (_dbus_string_find (&str, 0, "ill", NULL))
2608     _dbus_assert_not_reached ("Did find 'ill'");
2609
2610   if (_dbus_string_find (&str, 0, "q", NULL))
2611     _dbus_assert_not_reached ("Did find 'q'");
2612
2613   if (!_dbus_string_find_to (&str, 0, 2, "He", NULL))
2614     _dbus_assert_not_reached ("Didn't find 'He'");
2615
2616   if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL))
2617     _dbus_assert_not_reached ("Did find 'Hello'");
2618   
2619   _dbus_string_free (&str);
2620
2621   /* Base 64 */
2622   test_base64_roundtrip ("Hello this is a string\n", -1);
2623   test_base64_roundtrip ("Hello this is a string\n1", -1);
2624   test_base64_roundtrip ("Hello this is a string\n12", -1);
2625   test_base64_roundtrip ("Hello this is a string\n123", -1);
2626   test_base64_roundtrip ("Hello this is a string\n1234", -1);
2627   test_base64_roundtrip ("Hello this is a string\n12345", -1);
2628   test_base64_roundtrip ("", 0);
2629   test_base64_roundtrip ("1", 1);
2630   test_base64_roundtrip ("12", 2);
2631   test_base64_roundtrip ("123", 3);
2632   test_base64_roundtrip ("1234", 4);
2633   test_base64_roundtrip ("12345", 5);
2634   test_base64_roundtrip ("", 1);
2635   test_base64_roundtrip ("1", 2);
2636   test_base64_roundtrip ("12", 3);
2637   test_base64_roundtrip ("123", 4);
2638   test_base64_roundtrip ("1234", 5);
2639   test_base64_roundtrip ("12345", 6);
2640   {
2641     unsigned char buf[512];
2642     i = 0;
2643     while (i < _DBUS_N_ELEMENTS (buf))
2644       {
2645         buf[i] = i;
2646         ++i;
2647       }
2648     i = 0;
2649     while (i < _DBUS_N_ELEMENTS (buf))
2650       {
2651         test_base64_roundtrip (buf, i);
2652         ++i;
2653       }
2654   }
2655   
2656   return TRUE;
2657 }
2658
2659 #endif /* DBUS_BUILD_TESTS */