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