2002-12-11 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-string.h"
25 /* we allow a system header here, for speed/convenience */
26 #include <string.h>
27
28 /**
29  * @defgroup DBusString string class
30  * @ingroup  DBusInternals
31  * @brief DBusString data structure
32  *
33  * Types and functions related to DBusString. DBusString is intended
34  * to be a string class that makes it hard to mess up security issues
35  * (and just in general harder to write buggy code).  It should be
36  * used (or extended and then used) rather than the libc stuff in
37  * string.h.  The string class is a bit inconvenient at spots because
38  * it handles out-of-memory failures and tries to be extra-robust.
39  * 
40  * A DBusString has a maximum length set at initialization time; this
41  * can be used to ensure that a buffer doesn't get too big.  The
42  * _dbus_string_lengthen() method checks for overflow, and for max
43  * length being exceeded.
44  * 
45  * Try to avoid conversion to a plain C string, i.e. add methods on
46  * the string object instead, only convert to C string when passing
47  * things out to the public API. In particular, no sprintf, strcpy,
48  * strcat, any of that should be used. The GString feature of
49  * accepting negative numbers for "length of string" is also absent,
50  * because it could keep us from detecting bogus huge lengths. i.e. if
51  * we passed in some bogus huge length it would be taken to mean
52  * "current length of string" instead of "broken crack"
53  */
54
55 /**
56  * @defgroup DBusStringInternals DBusString implementation details
57  * @ingroup  DBusInternals
58  * @brief DBusString implementation details
59  *
60  * The guts of DBusString.
61  *
62  * @{
63  */
64
65 /**
66  * @brief Internals of DBusString.
67  * 
68  * DBusString internals. DBusString is an opaque objects, it must be
69  * used via accessor functions.
70  */
71 typedef struct
72 {
73   unsigned char *str;            /**< String data, plus nul termination */
74   int            len;            /**< Length without nul */
75   int            allocated;      /**< Allocated size of data */
76   int            max_length;     /**< Max length of this string. */
77   unsigned int   constant : 1;   /**< String data is not owned by DBusString */
78   unsigned int   locked : 1;     /**< DBusString has been locked and can't be changed */
79   unsigned int   invalid : 1;    /**< DBusString is invalid (e.g. already freed) */
80 } DBusRealString;
81
82 /**
83  * Checks a bunch of assertions about a string object
84  *
85  * @param real the DBusRealString
86  */
87 #define DBUS_GENERIC_STRING_PREAMBLE(real) _dbus_assert ((real) != NULL); _dbus_assert (!(real)->invalid); _dbus_assert ((real)->len >= 0); _dbus_assert ((real)->allocated >= 0); _dbus_assert ((real)->max_length >= 0); _dbus_assert ((real)->len <= (real)->allocated); _dbus_assert ((real)->len <= (real)->max_length)
88
89 /**
90  * Checks assertions about a string object that needs to be
91  * modifiable - may not be locked or const. Also declares
92  * the "real" variable pointing to DBusRealString. 
93  * @param str the string
94  */
95 #define DBUS_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \
96   DBUS_GENERIC_STRING_PREAMBLE (real);                                          \
97   _dbus_assert (!(real)->constant);                                             \
98   _dbus_assert (!(real)->locked)
99
100 /**
101  * Checks assertions about a string object that may be locked but
102  * can't be const. i.e. a string object that we can free.  Also
103  * declares the "real" variable pointing to DBusRealString.
104  *
105  * @param str the string
106  */
107 #define DBUS_LOCKED_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \
108   DBUS_GENERIC_STRING_PREAMBLE (real);                                                 \
109   _dbus_assert (!(real)->constant)
110
111 /**
112  * Checks assertions about a string that may be const or locked.  Also
113  * declares the "real" variable pointing to DBusRealString.
114  * @param str the string.
115  */
116 #define DBUS_CONST_STRING_PREAMBLE(str) const DBusRealString *real = (DBusRealString*) str; \
117   DBUS_GENERIC_STRING_PREAMBLE (real)
118
119 /** @} */
120
121 /**
122  * @addtogroup DBusString
123  * @{
124  */
125
126 /**
127  * Initializes a string. The maximum length may be _DBUS_INT_MAX for
128  * no maximum. The string starts life with zero length.
129  * The string must eventually be freed with _dbus_string_free().
130  *
131  * @param str memory to hold the string
132  * @param max_length the maximum size of the string
133  * @returns #TRUE on success
134  */
135 dbus_bool_t
136 _dbus_string_init (DBusString *str,
137                    int         max_length)
138 {
139   DBusRealString *real;
140   
141   _dbus_assert (str != NULL);
142   _dbus_assert (max_length >= 0);
143
144   _dbus_assert (sizeof (DBusString) == sizeof (DBusRealString));
145   
146   real = (DBusRealString*) str;
147
148   /* It's very important not to touch anything
149    * other than real->str if we're going to fail,
150    * since we also use this function to reset
151    * an existing string, e.g. in _dbus_string_steal_data()
152    */
153   
154 #define INITIAL_ALLOC 2
155   
156   real->str = dbus_malloc (INITIAL_ALLOC);
157   if (real->str == NULL)
158     return FALSE;
159
160   real->allocated = INITIAL_ALLOC;
161   real->len = 0;
162   real->str[real->len] = '\0';
163   
164   real->max_length = max_length;
165   real->constant = FALSE;
166   real->locked = FALSE;
167   real->invalid = FALSE;
168
169   return TRUE;
170 }
171
172 /**
173  * Initializes a constant string. The value parameter is not copied
174  * (should be static), and the string may never be modified.
175  * It is safe but not necessary to call _dbus_string_free()
176  * on a const string.
177  * 
178  * @param str memory to use for the string
179  * @param value a string to be stored in str (not copied!!!)
180  */
181 void
182 _dbus_string_init_const (DBusString *str,
183                          const char *value)
184 {
185   DBusRealString *real;
186   
187   _dbus_assert (str != NULL);
188   _dbus_assert (value != NULL);
189
190   real = (DBusRealString*) str;
191   
192   real->str = (char*) value;
193   real->len = strlen (real->str);
194   real->allocated = real->len;
195   real->max_length = real->len;
196   real->constant = TRUE;
197   real->invalid = FALSE;
198 }
199
200 /**
201  * Frees a string created by _dbus_string_init().
202  *
203  * @param str memory where the string is stored.
204  */
205 void
206 _dbus_string_free (DBusString *str)
207 {
208   DBUS_LOCKED_STRING_PREAMBLE (str);
209   
210   if (real->constant)
211     return;
212   
213   dbus_free (real->str);
214
215   real->invalid = TRUE;
216 }
217
218 /**
219  * Locks a string such that any attempts to change the string
220  * will result in aborting the program. Also, if the string
221  * is wasting a lot of memory (allocation is larger than what
222  * the string is really using), _dbus_string_lock() will realloc
223  * the string's data to "compact" it.
224  *
225  * @param str the string to lock.
226  */
227 void
228 _dbus_string_lock (DBusString *str)
229 {  
230   DBUS_LOCKED_STRING_PREAMBLE (str); /* can lock multiple times */
231
232   real->locked = TRUE;
233
234   /* Try to realloc to avoid excess memory usage, since
235    * we know we won't change the string further
236    */
237 #define MAX_WASTE 24
238   if (real->allocated > (real->len + MAX_WASTE))
239     {
240       char *new_str;
241       int new_allocated;
242
243       new_allocated = real->len + 1;
244
245       new_str = dbus_realloc (real->str, new_allocated);
246       if (new_str != NULL)
247         {
248           real->str = new_str;
249           real->allocated = new_allocated;
250         }
251     }
252 }
253
254 /**
255  * Gets the raw character buffer from the string.  The returned buffer
256  * will be nul-terminated, but note that strings may contain binary
257  * data so there may be extra nul characters prior to the termination.
258  * This function should be little-used, extend DBusString or add
259  * stuff to dbus-sysdeps.c instead. It's an error to use this
260  * function on a const string.
261  *
262  * @param str the string
263  * @param data_return place to store the returned data
264  */
265 void
266 _dbus_string_get_data (DBusString        *str,
267                        char             **data_return)
268 {
269   DBUS_STRING_PREAMBLE (str);
270   _dbus_assert (data_return != NULL);
271   
272   *data_return = real->str;
273 }
274
275 /**
276  * Gets the raw character buffer from a const string. 
277  *
278  * @param str the string
279  * @param data_return location to store returned data
280  */
281 void
282 _dbus_string_get_const_data (const DBusString  *str,
283                              const char       **data_return)
284 {
285   DBUS_CONST_STRING_PREAMBLE (str);
286   _dbus_assert (data_return != NULL);
287   
288   *data_return = real->str;
289 }
290
291 /**
292  * Gets a sub-portion of the raw character buffer from the
293  * string. The "len" field is required simply for error
294  * checking, to be sure you don't try to use more
295  * string than exists. The nul termination of the
296  * returned buffer remains at the end of the entire
297  * string, not at start + len.
298  *
299  * @param str the string
300  * @param data_return location to return the buffer
301  * @param start byte offset to return
302  * @param len length of segment to return
303  */
304 void
305 _dbus_string_get_data_len (DBusString *str,
306                            char      **data_return,
307                            int         start,
308                            int         len)
309 {
310   DBUS_STRING_PREAMBLE (str);
311   _dbus_assert (data_return != NULL);
312   _dbus_assert (start >= 0);
313   _dbus_assert (len >= 0);
314   _dbus_assert ((start + len) <= real->len);
315   
316   *data_return = real->str + start;
317 }
318
319 /**
320  * const version of _dbus_string_get_data_len().
321  *
322  * @param str the string
323  * @param data_return location to return the buffer
324  * @param start byte offset to return
325  * @param len length of segment to return
326  */
327 void
328 _dbus_string_get_const_data_len (const DBusString  *str,
329                                  const char       **data_return,
330                                  int                start,
331                                  int                len)
332 {
333   DBUS_CONST_STRING_PREAMBLE (str);
334   _dbus_assert (data_return != NULL);
335   _dbus_assert (start >= 0);
336   _dbus_assert (len >= 0);
337   _dbus_assert ((start + len) <= real->len);
338   
339   *data_return = real->str + start;
340 }
341
342 /**
343  * Like _dbus_string_get_data(), but removes the
344  * gotten data from the original string. The caller
345  * must free the data returned. This function may
346  * fail due to lack of memory, and return #FALSE.
347  *
348  * @param str the string
349  * @param data_return location to return the buffer
350  * @returns #TRUE on success
351  */
352 dbus_bool_t
353 _dbus_string_steal_data (DBusString        *str,
354                          char             **data_return)
355 {
356   DBUS_STRING_PREAMBLE (str);
357   _dbus_assert (data_return != NULL);
358   
359   *data_return = real->str;
360
361   /* reset the string */
362   if (!_dbus_string_init (str, real->max_length))
363     {
364       /* hrm, put it back then */
365       real->str = *data_return;
366       *data_return = NULL;
367       return FALSE;
368     }
369
370   return TRUE;
371 }
372
373 /**
374  * Like _dbus_string_get_data_len(), but removes the gotten data from
375  * the original string. The caller must free the data returned. This
376  * function may fail due to lack of memory, and return #FALSE.
377  * The returned string is nul-terminated and has length len.
378  *
379  * @param str the string
380  * @param data_return location to return the buffer
381  * @param start the start of segment to steal
382  * @param len the length of segment to steal
383  * @returns #TRUE on success
384  */
385 dbus_bool_t
386 _dbus_string_steal_data_len (DBusString        *str,
387                              char             **data_return,
388                              int                start,
389                              int                len)
390 {
391   DBusString dest;
392   
393   DBUS_STRING_PREAMBLE (str);
394   _dbus_assert (data_return != NULL);
395   _dbus_assert (start >= 0);
396   _dbus_assert (len >= 0);
397   _dbus_assert ((start + len) <= real->len);
398
399   if (!_dbus_string_init (&dest, real->max_length))
400     return FALSE;
401
402   if (!_dbus_string_move_len (str, start, len, &dest, 0))
403     {
404       _dbus_string_free (&dest);
405       return FALSE;
406     }
407   
408   if (!_dbus_string_steal_data (&dest, data_return))
409     {
410       _dbus_string_free (&dest);
411       return FALSE;
412     }
413
414   _dbus_string_free (&dest);
415   return TRUE;
416 }
417
418 /**
419  * Gets the length of a string (not including nul termination).
420  *
421  * @returns the length.
422  */
423 int
424 _dbus_string_get_length (const DBusString  *str)
425 {
426   DBUS_CONST_STRING_PREAMBLE (str);
427   
428   return real->len;
429 }
430
431 static dbus_bool_t
432 set_length (DBusRealString *real,
433             int             new_length)
434 {
435   /* Note, we are setting the length without nul termination */
436
437   /* exceeding max length is the same as failure to allocate memory */
438   if (new_length > real->max_length)
439     return FALSE;
440   
441   while (new_length >= real->allocated)
442     {
443       int new_allocated;
444       char *new_str;
445       
446       new_allocated = 2 + real->allocated * 2;
447       if (new_allocated < real->allocated)
448         return FALSE; /* overflow */
449         
450       new_str = dbus_realloc (real->str, new_allocated);
451       if (new_str == NULL)
452         return FALSE;
453
454       real->str = new_str;
455       real->allocated = new_allocated;
456     }
457
458   real->len = new_length;
459   real->str[real->len] = '\0';
460
461   return TRUE;
462 }
463
464 /**
465  * Makes a string longer by the given number of bytes.  Checks whether
466  * adding additional_length to the current length would overflow an
467  * integer, and checks for exceeding a string's max length.
468  * The new bytes are not initialized, other than nul-terminating
469  * the end of the string. The uninitialized bytes may contain
470  * unexpected nul bytes or other junk.
471  *
472  * @param str a string
473  * @param additional_length length to add to the string.
474  * @returns #TRUE on success.
475  */
476 dbus_bool_t
477 _dbus_string_lengthen (DBusString *str,
478                        int         additional_length)
479 {
480   DBUS_STRING_PREAMBLE (str);  
481   _dbus_assert (additional_length >= 0);
482   
483   if ((real->len + additional_length) < real->len)
484     return FALSE; /* overflow */
485   
486   return set_length (real,
487                      real->len + additional_length);
488 }
489
490 /**
491  * Makes a string shorter by the given number of bytes.
492  *
493  * @param str a string
494  * @param length_to_remove length to remove from the string.
495  */
496 void
497 _dbus_string_shorten (DBusString *str,
498                       int         length_to_remove)
499 {
500   DBUS_STRING_PREAMBLE (str);
501   _dbus_assert (length_to_remove >= 0);
502   _dbus_assert (length_to_remove <= real->len);
503
504   set_length (real,
505               real->len - length_to_remove);
506 }
507
508 /**
509  * Sets the length of a string. Can be used to truncate or lengthen
510  * the string. If the string is lengthened, the function may fail and
511  * return #FALSE. Newly-added bytes are not initialized, as with
512  * _dbus_string_lengthen().
513  *
514  * @param str a string
515  * @param length new length of the string.
516  * @returns #FALSE on failure.
517  */
518 dbus_bool_t
519 _dbus_string_set_length (DBusString *str,
520                          int         length)
521 {
522   DBUS_STRING_PREAMBLE (str);
523   _dbus_assert (length >= 0);
524
525   return set_length (real, length);
526 }
527
528 static dbus_bool_t
529 append (DBusRealString *real,
530         const char     *buffer,
531         int             buffer_len)
532 {
533   if (buffer_len == 0)
534     return TRUE;
535
536   if (!_dbus_string_lengthen ((DBusString*)real, buffer_len))
537     return FALSE;
538
539   memcpy (real->str + (real->len - buffer_len),
540           buffer,
541           buffer_len);
542
543   return TRUE;
544 }
545
546 /**
547  * Appends a nul-terminated C-style string to a DBusString.
548  *
549  * @param str the DBusString
550  * @param buffer the nul-terminated characters to append
551  * @returns #FALSE if not enough memory.
552  */
553 dbus_bool_t
554 _dbus_string_append (DBusString *str,
555                      const char *buffer)
556 {
557   int buffer_len;
558   
559   DBUS_STRING_PREAMBLE (str);
560   _dbus_assert (buffer != NULL);
561   
562   buffer_len = strlen (buffer);
563
564   return append (real, buffer, buffer_len);
565 }
566
567 /**
568  * Appends block of bytes with the given length to a DBusString.
569  *
570  * @param str the DBusString
571  * @param buffer the bytes to append
572  * @param len the number of bytes to append
573  * @returns #FALSE if not enough memory.
574  */
575 dbus_bool_t
576 _dbus_string_append_len (DBusString *str,
577                          const char *buffer,
578                          int         len)
579 {
580   DBUS_STRING_PREAMBLE (str);
581   _dbus_assert (buffer != NULL);
582   _dbus_assert (len >= 0);
583
584   return append (real, buffer, len);
585 }
586
587 /**
588  * Appends a single byte to the string, returning #FALSE
589  * if not enough memory.
590  *
591  * @param str the string
592  * @param byte the byte to append
593  * @returns #TRUE on success
594  */
595 dbus_bool_t
596 _dbus_string_append_byte (DBusString    *str,
597                           unsigned char  byte)
598 {
599   DBUS_STRING_PREAMBLE (str);
600
601   if (!set_length (real, real->len + 1))
602     return FALSE;
603
604   real->str[real->len-1] = byte;
605
606   return TRUE;
607 }
608
609 /**
610  * Appends a single Unicode character, encoding the character
611  * in UTF-8 format.
612  *
613  * @param str the string
614  * @param ch the Unicode character
615  */
616 dbus_bool_t
617 _dbus_string_append_unichar (DBusString    *str,
618                              dbus_unichar_t ch)
619 {
620   int len;
621   int first;
622   int i;
623   char *out;
624   
625   DBUS_STRING_PREAMBLE (str);
626
627   /* this code is from GLib but is pretty standard I think */
628   
629   len = 0;
630   
631   if (ch < 0x80)
632     {
633       first = 0;
634       len = 1;
635     }
636   else if (ch < 0x800)
637     {
638       first = 0xc0;
639       len = 2;
640     }
641   else if (ch < 0x10000)
642     {
643       first = 0xe0;
644       len = 3;
645     }
646    else if (ch < 0x200000)
647     {
648       first = 0xf0;
649       len = 4;
650     }
651   else if (ch < 0x4000000)
652     {
653       first = 0xf8;
654       len = 5;
655     }
656   else
657     {
658       first = 0xfc;
659       len = 6;
660     }
661
662   if (!set_length (real, real->len + len))
663     return FALSE;
664
665   out = real->str + (real->len - len);
666   
667   for (i = len - 1; i > 0; --i)
668     {
669       out[i] = (ch & 0x3f) | 0x80;
670       ch >>= 6;
671     }
672   out[0] = ch | first;
673
674   return TRUE;
675 }
676
677 static void
678 delete (DBusRealString *real,
679         int             start,
680         int             len)
681 {
682   if (len == 0)
683     return;
684   
685   memmove (real->str + start, real->str + start + len, real->len - (start + len));
686   real->len -= len;
687   real->str[real->len] = '\0';
688 }
689
690 /**
691  * Deletes a segment of a DBusString with length len starting at
692  * start. (Hint: to clear an entire string, setting length to 0
693  * with _dbus_string_set_length() is easier.)
694  *
695  * @param str the DBusString
696  * @param start where to start deleting
697  * @param len the number of bytes to delete
698  */
699 void
700 _dbus_string_delete (DBusString       *str,
701                      int               start,
702                      int               len)
703 {
704   DBUS_STRING_PREAMBLE (str);
705   _dbus_assert (start >= 0);
706   _dbus_assert (len >= 0);
707   _dbus_assert ((start + len) <= real->len);
708
709   delete (real, start, len);
710 }
711
712 static dbus_bool_t
713 copy (DBusRealString *source,
714       int             start,
715       int             len,
716       DBusRealString *dest,
717       int             insert_at)
718 {
719   if (len == 0)
720     return TRUE;
721
722   if (!set_length (dest, dest->len + len))
723     return FALSE;
724
725   memmove (dest->str + insert_at + len, 
726            dest->str + insert_at,
727            dest->len - len);
728
729   memcpy (dest->str + insert_at,
730           source->str + start,
731           len);
732
733   return TRUE;
734 }
735
736 /**
737  * Checks assertions for two strings we're copying a segment between,
738  * and declares real_source/real_dest variables.
739  *
740  * @param source the source string
741  * @param start the starting offset
742  * @param dest the dest string
743  * @param insert_at where the copied segment is inserted
744  */
745 #define DBUS_STRING_COPY_PREAMBLE(source, start, dest, insert_at)       \
746   DBusRealString *real_source = (DBusRealString*) source;               \
747   DBusRealString *real_dest = (DBusRealString*) dest;                   \
748   _dbus_assert ((source) != (dest));                                    \
749   DBUS_GENERIC_STRING_PREAMBLE (real_source);                           \
750   DBUS_GENERIC_STRING_PREAMBLE (real_dest);                             \
751   _dbus_assert (!real_source->constant);                                \
752   _dbus_assert (!real_source->locked);                                  \
753   _dbus_assert (!real_dest->constant);                                  \
754   _dbus_assert (!real_dest->locked);                                    \
755   _dbus_assert ((start) >= 0);                                          \
756   _dbus_assert ((start) <= real_source->len);                           \
757   _dbus_assert ((insert_at) >= 0);                                      \
758   _dbus_assert ((insert_at) <= real_dest->len)
759
760 /**
761  * Moves the end of one string into another string. Both strings
762  * must be initialized, valid strings.
763  *
764  * @param source the source string
765  * @param start where to chop off the source string
766  * @param dest the destination string
767  * @param insert_at where to move the chopped-off part of source string
768  * @returns #FALSE if not enough memory
769  */
770 dbus_bool_t
771 _dbus_string_move (DBusString       *source,
772                    int               start,
773                    DBusString       *dest,
774                    int               insert_at)
775 {
776   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
777   
778   if (!copy (real_source, start,
779              real_source->len - start,
780              real_dest,
781              insert_at))
782     return FALSE;
783
784   delete (real_source, start,
785           real_source->len - start);
786
787   return TRUE;
788 }
789
790 /**
791  * Like _dbus_string_move(), but does not delete the section
792  * of the source string that's copied to the dest string.
793  *
794  * @param source the source string
795  * @param start where to start copying the source string
796  * @param dest the destination string
797  * @param insert_at where to place the copied part of source string
798  * @returns #FALSE if not enough memory
799  */
800 dbus_bool_t
801 _dbus_string_copy (const DBusString *source,
802                    int               start,
803                    DBusString       *dest,
804                    int               insert_at)
805 {
806   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
807
808   return copy (real_source, start,
809                real_source->len - start,
810                real_dest,
811                insert_at);
812 }
813
814 /**
815  * Like _dbus_string_move(), but can move a segment from
816  * the middle of the source string.
817  * 
818  * @param source the source string
819  * @param start first byte of source string to move
820  * @param len length of segment to move
821  * @param dest the destination string
822  * @param insert_at where to move the bytes from the source string
823  * @returns #FALSE if not enough memory
824  */
825 dbus_bool_t
826 _dbus_string_move_len (DBusString       *source,
827                        int               start,
828                        int               len,
829                        DBusString       *dest,
830                        int               insert_at)
831
832 {
833   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
834   _dbus_assert (len >= 0);
835   _dbus_assert ((start + len) <= real_source->len);
836
837   if (!copy (real_source, start, len,
838              real_dest,
839              insert_at))
840     return FALSE;
841
842   delete (real_source, start,
843           real_source->len - start);
844
845   return TRUE;
846 }
847
848 /**
849  * Like _dbus_string_copy(), but can copy a segment from the middle of
850  * the source string.
851  *
852  * @param source the source string
853  * @param start where to start copying the source string
854  * @param len length of segment to copy
855  * @param dest the destination string
856  * @param insert_at where to place the copied segment of source string
857  * @returns #FALSE if not enough memory
858  */
859 dbus_bool_t
860 _dbus_string_copy_len (const DBusString *source,
861                        int               start,
862                        int               len,
863                        DBusString       *dest,
864                        int               insert_at)
865 {
866   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
867   _dbus_assert (len >= 0);
868   _dbus_assert ((start + len) <= real_source->len);
869   
870   return copy (real_source, start, len,
871                real_dest,
872                insert_at);
873 }
874
875 /* Unicode macros from GLib */
876
877 /** computes length and mask of a unicode character
878  * @param Char the char
879  * @param Mask the mask variable to assign to
880  * @param Len the length variable to assign to
881  */
882 #define UTF8_COMPUTE(Char, Mask, Len)                                         \
883   if (Char < 128)                                                             \
884     {                                                                         \
885       Len = 1;                                                                \
886       Mask = 0x7f;                                                            \
887     }                                                                         \
888   else if ((Char & 0xe0) == 0xc0)                                             \
889     {                                                                         \
890       Len = 2;                                                                \
891       Mask = 0x1f;                                                            \
892     }                                                                         \
893   else if ((Char & 0xf0) == 0xe0)                                             \
894     {                                                                         \
895       Len = 3;                                                                \
896       Mask = 0x0f;                                                            \
897     }                                                                         \
898   else if ((Char & 0xf8) == 0xf0)                                             \
899     {                                                                         \
900       Len = 4;                                                                \
901       Mask = 0x07;                                                            \
902     }                                                                         \
903   else if ((Char & 0xfc) == 0xf8)                                             \
904     {                                                                         \
905       Len = 5;                                                                \
906       Mask = 0x03;                                                            \
907     }                                                                         \
908   else if ((Char & 0xfe) == 0xfc)                                             \
909     {                                                                         \
910       Len = 6;                                                                \
911       Mask = 0x01;                                                            \
912     }                                                                         \
913   else                                                                        \
914     Len = -1;
915
916 /**
917  * computes length of a unicode character in UTF-8
918  * @param Char the char
919  */
920 #define UTF8_LENGTH(Char)              \
921   ((Char) < 0x80 ? 1 :                 \
922    ((Char) < 0x800 ? 2 :               \
923     ((Char) < 0x10000 ? 3 :            \
924      ((Char) < 0x200000 ? 4 :          \
925       ((Char) < 0x4000000 ? 5 : 6)))))
926    
927 /**
928  * Gets a UTF-8 value.
929  *
930  * @param Result variable for extracted unicode char.
931  * @param Chars the bytes to decode
932  * @param Count counter variable
933  * @param Mask mask for this char
934  * @param Len length for this char in bytes
935  */
936 #define UTF8_GET(Result, Chars, Count, Mask, Len)                             \
937   (Result) = (Chars)[0] & (Mask);                                             \
938   for ((Count) = 1; (Count) < (Len); ++(Count))                               \
939     {                                                                         \
940       if (((Chars)[(Count)] & 0xc0) != 0x80)                                  \
941         {                                                                     \
942           (Result) = -1;                                                      \
943           break;                                                              \
944         }                                                                     \
945       (Result) <<= 6;                                                         \
946       (Result) |= ((Chars)[(Count)] & 0x3f);                                  \
947     }
948
949 /**
950  * Check whether a unicode char is in a valid range.
951  *
952  * @param Char the character
953  */
954 #define UNICODE_VALID(Char)                   \
955     ((Char) < 0x110000 &&                     \
956      ((Char) < 0xD800 || (Char) >= 0xE000) && \
957      (Char) != 0xFFFE && (Char) != 0xFFFF)   
958
959 /**
960  * Gets a unicode character from a UTF-8 string. Does no validation;
961  * you must verify that the string is valid UTF-8 in advance and must
962  * pass in the start of a character.
963  *
964  * @param str the string
965  * @param start the start of the UTF-8 character.
966  * @param ch_return location to return the character
967  * @param end_return location to return the byte index of next character
968  * @returns #TRUE on success, #FALSE otherwise.
969  */
970 void
971 _dbus_string_get_unichar (const DBusString *str,
972                           int               start,
973                           dbus_unichar_t   *ch_return,
974                           int              *end_return)
975 {
976   int i, mask, len;
977   dbus_unichar_t result;
978   unsigned char c;
979   unsigned char *p;
980   DBUS_CONST_STRING_PREAMBLE (str);
981
982   if (ch_return)
983     *ch_return = 0;
984   if (end_return)
985     *end_return = real->len;
986   
987   mask = 0;
988   p = real->str + start;
989   c = *p;
990   
991   UTF8_COMPUTE (c, mask, len);
992   if (len == -1)
993     return;
994   UTF8_GET (result, p, i, mask, len);
995
996   if (result == (dbus_unichar_t)-1)
997     return;
998
999   if (ch_return)
1000     *ch_return = result;
1001   if (end_return)
1002     *end_return = start + len;
1003 }
1004
1005 /** @} */
1006
1007 #ifdef DBUS_BUILD_TESTS
1008 #include "dbus-test.h"
1009 #include <stdio.h>
1010
1011 static void
1012 test_max_len (DBusString *str,
1013               int         max_len)
1014 {
1015   if (max_len > 0)
1016     {
1017       if (!_dbus_string_set_length (str, max_len - 1))
1018         _dbus_assert_not_reached ("setting len to one less than max should have worked");
1019     }
1020
1021   if (!_dbus_string_set_length (str, max_len))
1022     _dbus_assert_not_reached ("setting len to max len should have worked");
1023
1024   if (_dbus_string_set_length (str, max_len + 1))
1025     _dbus_assert_not_reached ("setting len to one more than max len should not have worked");
1026
1027   if (!_dbus_string_set_length (str, 0))
1028     _dbus_assert_not_reached ("setting len to zero should have worked");
1029 }
1030
1031 /**
1032  * @ingroup DBusStringInternals
1033  * Unit test for DBusString.
1034  *
1035  * @todo Need to write tests for _dbus_string_copy() and
1036  * _dbus_string_move() moving to/from each of start/middle/end of a
1037  * string.
1038  * 
1039  * @returns #TRUE on success.
1040  */
1041 dbus_bool_t
1042 _dbus_string_test (void)
1043 {
1044   DBusString str;
1045   DBusString other;
1046   int i, end;
1047   long v;
1048   double d;
1049   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 };
1050   char *s;
1051   dbus_unichar_t ch;
1052   
1053   i = 0;
1054   while (i < _DBUS_N_ELEMENTS (lens))
1055     {
1056       if (!_dbus_string_init (&str, lens[i]))
1057         _dbus_assert_not_reached ("failed to init string");
1058       
1059       test_max_len (&str, lens[i]);
1060       _dbus_string_free (&str);
1061
1062       ++i;
1063     }
1064
1065   /* Test shortening and setting length */
1066   i = 0;
1067   while (i < _DBUS_N_ELEMENTS (lens))
1068     {
1069       int j;
1070       
1071       if (!_dbus_string_init (&str, lens[i]))
1072         _dbus_assert_not_reached ("failed to init string");
1073       
1074       if (!_dbus_string_set_length (&str, lens[i]))
1075         _dbus_assert_not_reached ("failed to set string length");
1076
1077       j = lens[i];
1078       while (j > 0)
1079         {
1080           _dbus_assert (_dbus_string_get_length (&str) == j);
1081           if (j > 0)
1082             {
1083               _dbus_string_shorten (&str, 1);
1084               _dbus_assert (_dbus_string_get_length (&str) == (j - 1));
1085             }
1086           --j;
1087         }
1088       
1089       _dbus_string_free (&str);
1090
1091       ++i;
1092     }
1093
1094   /* Test appending data */
1095   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
1096     _dbus_assert_not_reached ("failed to init string");
1097
1098   i = 0;
1099   while (i < 10)
1100     {
1101       if (!_dbus_string_append (&str, "a"))
1102         _dbus_assert_not_reached ("failed to append string to string\n");
1103
1104       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1);
1105
1106       if (!_dbus_string_append_byte (&str, 'b'))
1107         _dbus_assert_not_reached ("failed to append byte to string\n");
1108
1109       _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2);
1110                     
1111       ++i;
1112     }
1113
1114   _dbus_string_free (&str);
1115
1116   /* Check steal_data */
1117   
1118   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
1119     _dbus_assert_not_reached ("failed to init string");
1120
1121   if (!_dbus_string_append (&str, "Hello World"))
1122     _dbus_assert_not_reached ("could not append to string");
1123
1124   i = _dbus_string_get_length (&str);
1125   
1126   if (!_dbus_string_steal_data (&str, &s))
1127     _dbus_assert_not_reached ("failed to steal data");
1128
1129   _dbus_assert (_dbus_string_get_length (&str) == 0);
1130   _dbus_assert (((int)strlen (s)) == i);
1131
1132   dbus_free (s);
1133
1134   /* Check move */
1135   
1136   if (!_dbus_string_append (&str, "Hello World"))
1137     _dbus_assert_not_reached ("could not append to string");
1138
1139   i = _dbus_string_get_length (&str);
1140
1141   if (!_dbus_string_init (&other, _DBUS_INT_MAX))
1142     _dbus_assert_not_reached ("could not init string");
1143   
1144   if (!_dbus_string_move (&str, 0, &other, 0))
1145     _dbus_assert_not_reached ("could not move");
1146
1147   _dbus_assert (_dbus_string_get_length (&str) == 0);
1148   _dbus_assert (_dbus_string_get_length (&other) == i);
1149
1150   _dbus_string_free (&other);
1151
1152   /* Check copy */
1153   
1154   if (!_dbus_string_append (&str, "Hello World"))
1155     _dbus_assert_not_reached ("could not append to string");
1156
1157   i = _dbus_string_get_length (&str);
1158   
1159   if (!_dbus_string_init (&other, _DBUS_INT_MAX))
1160     _dbus_assert_not_reached ("could not init string");
1161   
1162   if (!_dbus_string_copy (&str, 0, &other, 0))
1163     _dbus_assert_not_reached ("could not copy");
1164
1165   _dbus_assert (_dbus_string_get_length (&str) == i);
1166   _dbus_assert (_dbus_string_get_length (&other) == i);
1167   
1168   _dbus_string_free (&str);
1169   _dbus_string_free (&other);
1170
1171   /* Check append/get unichar */
1172   
1173   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
1174     _dbus_assert_not_reached ("failed to init string");
1175
1176   ch = 0;
1177   if (!_dbus_string_append_unichar (&str, 0xfffc))
1178     _dbus_assert_not_reached ("failed to append unichar");
1179
1180   _dbus_string_get_unichar (&str, 0, &ch, &i);
1181
1182   _dbus_assert (ch == 0xfffc);
1183   _dbus_assert (i == _dbus_string_get_length (&str));
1184
1185   _dbus_string_free (&str);
1186   
1187   /* Check append/parse int/double */
1188   
1189   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
1190     _dbus_assert_not_reached ("failed to init string");
1191
1192   if (!_dbus_string_append_int (&str, 27))
1193     _dbus_assert_not_reached ("failed to append int");
1194
1195   i = _dbus_string_get_length (&str);
1196
1197   if (!_dbus_string_parse_int (&str, 0, &v, &end))
1198     _dbus_assert_not_reached ("failed to parse int");
1199
1200   _dbus_assert (v == 27);
1201   _dbus_assert (end == i);
1202     
1203   _dbus_string_set_length (&str, 0);
1204
1205   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
1206     _dbus_assert_not_reached ("failed to init string");
1207   
1208   if (!_dbus_string_append_double (&str, 50.3))
1209     _dbus_assert_not_reached ("failed to append float");
1210
1211   i = _dbus_string_get_length (&str);
1212
1213   if (!_dbus_string_parse_double (&str, 0, &d, &end))
1214     _dbus_assert_not_reached ("failed to parse float");
1215
1216   _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6));
1217   _dbus_assert (end == i);
1218
1219   _dbus_string_free (&str);
1220
1221   return TRUE;
1222 }
1223
1224 #endif /* DBUS_BUILD_TESTS */