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