D-Bus  1.6.30
dbus-string.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-string.c String utility class (internal to D-Bus implementation)
00003  * 
00004  * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
00005  * Copyright (C) 2006 Ralf Habacker <ralf.habacker@freenet.de>
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 #include "dbus-internals.h"
00027 #include "dbus-string.h"
00028 /* we allow a system header here, for speed/convenience */
00029 #include <string.h>
00030 /* for vsnprintf */
00031 #include <stdio.h>
00032 #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1
00033 #include "dbus-string-private.h"
00034 #include "dbus-marshal-basic.h" /* probably should be removed by moving the usage of DBUS_TYPE
00035                                  * into the marshaling-related files
00036                                  */
00037 /* for DBUS_VA_COPY */
00038 #include "dbus-sysdeps.h"
00039 
00078 static void
00079 fixup_alignment (DBusRealString *real)
00080 {
00081   unsigned char *aligned;
00082   unsigned char *real_block;
00083   unsigned int old_align_offset;
00084 
00085   /* we have to have extra space in real->allocated for the align offset and nul byte */
00086   _dbus_assert (real->len <= real->allocated - _DBUS_STRING_ALLOCATION_PADDING);
00087   
00088   old_align_offset = real->align_offset;
00089   real_block = real->str - old_align_offset;
00090   
00091   aligned = _DBUS_ALIGN_ADDRESS (real_block, 8);
00092 
00093   real->align_offset = aligned - real_block;
00094   real->str = aligned;
00095   
00096   if (old_align_offset != real->align_offset)
00097     {
00098       /* Here comes the suck */
00099       memmove (real_block + real->align_offset,
00100                real_block + old_align_offset,
00101                real->len + 1);
00102     }
00103 
00104   _dbus_assert (real->align_offset < 8);
00105   _dbus_assert (_DBUS_ALIGN_ADDRESS (real->str, 8) == real->str);
00106 }
00107 
00108 static void
00109 undo_alignment (DBusRealString *real)
00110 {
00111   if (real->align_offset != 0)
00112     {
00113       memmove (real->str - real->align_offset,
00114                real->str,
00115                real->len + 1);
00116 
00117       real->str = real->str - real->align_offset;
00118       real->align_offset = 0;
00119     }
00120 }
00121 
00131 dbus_bool_t
00132 _dbus_string_init_preallocated (DBusString *str,
00133                                 int         allocate_size)
00134 {
00135   DBusRealString *real;
00136   
00137   _dbus_assert (str != NULL);
00138 
00139   _dbus_assert (sizeof (DBusString) == sizeof (DBusRealString));
00140   
00141   real = (DBusRealString*) str;
00142 
00143   /* It's very important not to touch anything
00144    * other than real->str if we're going to fail,
00145    * since we also use this function to reset
00146    * an existing string, e.g. in _dbus_string_steal_data()
00147    */
00148   
00149   real->str = dbus_malloc (_DBUS_STRING_ALLOCATION_PADDING + allocate_size);
00150   if (real->str == NULL)
00151     return FALSE;  
00152   
00153   real->allocated = _DBUS_STRING_ALLOCATION_PADDING + allocate_size;
00154   real->len = 0;
00155   real->str[real->len] = '\0';
00156   
00157   real->constant = FALSE;
00158   real->locked = FALSE;
00159   real->invalid = FALSE;
00160   real->align_offset = 0;
00161   
00162   fixup_alignment (real);
00163   
00164   return TRUE;
00165 }
00166 
00174 dbus_bool_t
00175 _dbus_string_init (DBusString *str)
00176 {
00177   return _dbus_string_init_preallocated (str, 0);
00178 }
00179 
00189 void
00190 _dbus_string_init_const (DBusString *str,
00191                          const char *value)
00192 {
00193   _dbus_assert (value != NULL);
00194   
00195   _dbus_string_init_const_len (str, value,
00196                                strlen (value));
00197 }
00198 
00209 void
00210 _dbus_string_init_const_len (DBusString *str,
00211                              const char *value,
00212                              int         len)
00213 {
00214   DBusRealString *real;
00215   
00216   _dbus_assert (str != NULL);
00217   _dbus_assert (len == 0 || value != NULL);
00218   _dbus_assert (len <= _DBUS_STRING_MAX_LENGTH);
00219   _dbus_assert (len >= 0);
00220   
00221   real = (DBusRealString*) str;
00222   
00223   real->str = (unsigned char*) value;
00224   real->len = len;
00225   real->allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING; /* a lie, just to avoid special-case assertions... */
00226   real->constant = TRUE;
00227   real->locked = TRUE;
00228   real->invalid = FALSE;
00229   real->align_offset = 0;
00230 
00231   /* We don't require const strings to be 8-byte aligned as the
00232    * memory is coming from elsewhere.
00233    */
00234 }
00235 
00241 void
00242 _dbus_string_free (DBusString *str)
00243 {
00244   DBusRealString *real = (DBusRealString*) str;
00245   DBUS_GENERIC_STRING_PREAMBLE (real);
00246   
00247   if (real->constant)
00248     return;
00249 
00250   /* so it's safe if @p str returned by a failed
00251    * _dbus_string_init call
00252    * Bug: https://bugs.freedesktop.org/show_bug.cgi?id=65959
00253    */
00254   if (real->str == NULL)
00255     return;
00256 
00257   dbus_free (real->str - real->align_offset);
00258 
00259   real->invalid = TRUE;
00260 }
00261 
00262 static dbus_bool_t
00263 compact (DBusRealString *real,
00264          int             max_waste)
00265 {
00266   unsigned char *new_str;
00267   int new_allocated;
00268   int waste;
00269 
00270   waste = real->allocated - (real->len + _DBUS_STRING_ALLOCATION_PADDING);
00271 
00272   if (waste <= max_waste)
00273     return TRUE;
00274 
00275   new_allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING;
00276 
00277   new_str = dbus_realloc (real->str - real->align_offset, new_allocated);
00278   if (_DBUS_UNLIKELY (new_str == NULL))
00279     return FALSE;
00280 
00281   real->str = new_str + real->align_offset;
00282   real->allocated = new_allocated;
00283   fixup_alignment (real);
00284 
00285   return TRUE;
00286 }
00287 
00288 #ifdef DBUS_BUILD_TESTS
00289 /* Not using this feature at the moment,
00290  * so marked DBUS_BUILD_TESTS-only
00291  */
00301 void
00302 _dbus_string_lock (DBusString *str)
00303 {  
00304   DBUS_LOCKED_STRING_PREAMBLE (str); /* can lock multiple times */
00305 
00306   real->locked = TRUE;
00307 
00308   /* Try to realloc to avoid excess memory usage, since
00309    * we know we won't change the string further
00310    */
00311 #define MAX_WASTE 48
00312   compact (real, MAX_WASTE);
00313 }
00314 #endif /* DBUS_BUILD_TESTS */
00315 
00316 static dbus_bool_t
00317 reallocate_for_length (DBusRealString *real,
00318                        int             new_length)
00319 {
00320   int new_allocated;
00321   unsigned char *new_str;
00322 
00323   /* at least double our old allocation to avoid O(n), avoiding
00324    * overflow
00325    */
00326   if (real->allocated > (_DBUS_STRING_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING) / 2)
00327     new_allocated = _DBUS_STRING_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING;
00328   else
00329     new_allocated = real->allocated * 2;
00330 
00331   /* if you change the code just above here, run the tests without
00332    * the following assert-only hack before you commit
00333    */
00334   /* This is keyed off asserts in addition to tests so when you
00335    * disable asserts to profile, you don't get this destroyer
00336    * of profiles.
00337    */
00338 #ifdef DBUS_DISABLE_ASSERT
00339 #else
00340 #ifdef DBUS_BUILD_TESTS
00341   new_allocated = 0; /* ensure a realloc every time so that we go
00342                       * through all malloc failure codepaths
00343                       */
00344 #endif /* DBUS_BUILD_TESTS */
00345 #endif /* !DBUS_DISABLE_ASSERT */
00346 
00347   /* But be sure we always alloc at least space for the new length */
00348   new_allocated = MAX (new_allocated,
00349                        new_length + _DBUS_STRING_ALLOCATION_PADDING);
00350 
00351   _dbus_assert (new_allocated >= real->allocated); /* code relies on this */
00352   new_str = dbus_realloc (real->str - real->align_offset, new_allocated);
00353   if (_DBUS_UNLIKELY (new_str == NULL))
00354     return FALSE;
00355 
00356   real->str = new_str + real->align_offset;
00357   real->allocated = new_allocated;
00358   fixup_alignment (real);
00359 
00360   return TRUE;
00361 }
00362 
00374 dbus_bool_t
00375 _dbus_string_compact (DBusString *str,
00376                       int         max_waste)
00377 {
00378   DBUS_STRING_PREAMBLE (str);
00379 
00380   return compact (real, max_waste);
00381 }
00382 
00383 static dbus_bool_t
00384 set_length (DBusRealString *real,
00385             int             new_length)
00386 {
00387   /* Note, we are setting the length not including nul termination */
00388 
00389   /* exceeding max length is the same as failure to allocate memory */
00390   if (_DBUS_UNLIKELY (new_length > _DBUS_STRING_MAX_LENGTH))
00391     return FALSE;
00392   else if (new_length > (real->allocated - _DBUS_STRING_ALLOCATION_PADDING) &&
00393            _DBUS_UNLIKELY (!reallocate_for_length (real, new_length)))
00394     return FALSE;
00395   else
00396     {
00397       real->len = new_length;
00398       real->str[new_length] = '\0';
00399       return TRUE;
00400     }
00401 }
00402 
00403 static dbus_bool_t
00404 open_gap (int             len,
00405           DBusRealString *dest,
00406           int             insert_at)
00407 {
00408   if (len == 0)
00409     return TRUE;
00410 
00411   if (len > _DBUS_STRING_MAX_LENGTH - dest->len)
00412     return FALSE; /* detected overflow of dest->len + len below */
00413   
00414   if (!set_length (dest, dest->len + len))
00415     return FALSE;
00416 
00417   memmove (dest->str + insert_at + len, 
00418            dest->str + insert_at,
00419            dest->len - len - insert_at);
00420 
00421   return TRUE;
00422 }
00423 
00424 #ifndef _dbus_string_get_data
00425 
00436 char*
00437 _dbus_string_get_data (DBusString *str)
00438 {
00439   DBUS_STRING_PREAMBLE (str);
00440   
00441   return (char*) real->str;
00442 }
00443 #endif /* _dbus_string_get_data */
00444 
00445 /* only do the function if we don't have the macro */
00446 #ifndef _dbus_string_get_const_data
00447 
00453 const char*
00454 _dbus_string_get_const_data (const DBusString  *str)
00455 {
00456   DBUS_CONST_STRING_PREAMBLE (str);
00457   
00458   return (const char*) real->str;
00459 }
00460 #endif /* _dbus_string_get_const_data */
00461 
00475 char*
00476 _dbus_string_get_data_len (DBusString *str,
00477                            int         start,
00478                            int         len)
00479 {
00480   DBUS_STRING_PREAMBLE (str);
00481   _dbus_assert (start >= 0);
00482   _dbus_assert (len >= 0);
00483   _dbus_assert (start <= real->len);
00484   _dbus_assert (len <= real->len - start);
00485   
00486   return (char*) real->str + start;
00487 }
00488 
00489 /* only do the function if we don't have the macro */
00490 #ifndef _dbus_string_get_const_data_len
00491 
00499 const char*
00500 _dbus_string_get_const_data_len (const DBusString  *str,
00501                                  int                start,
00502                                  int                len)
00503 {
00504   DBUS_CONST_STRING_PREAMBLE (str);
00505   _dbus_assert (start >= 0);
00506   _dbus_assert (len >= 0);
00507   _dbus_assert (start <= real->len);
00508   _dbus_assert (len <= real->len - start);
00509   
00510   return (const char*) real->str + start;
00511 }
00512 #endif /* _dbus_string_get_const_data_len */
00513 
00514 /* only do the function if we don't have the macro */
00515 #ifndef _dbus_string_set_byte
00516 
00523 void
00524 _dbus_string_set_byte (DBusString    *str,
00525                        int            i,
00526                        unsigned char  byte)
00527 {
00528   DBUS_STRING_PREAMBLE (str);
00529   _dbus_assert (i < real->len);
00530   _dbus_assert (i >= 0);
00531   
00532   real->str[i] = byte;
00533 }
00534 #endif /* _dbus_string_set_byte */
00535 
00536 /* only have the function if we didn't create a macro */
00537 #ifndef _dbus_string_get_byte
00538 
00547 unsigned char
00548 _dbus_string_get_byte (const DBusString  *str,
00549                        int                start)
00550 {
00551   DBUS_CONST_STRING_PREAMBLE (str);
00552   _dbus_assert (start <= real->len);
00553   _dbus_assert (start >= 0);
00554   
00555   return real->str[start];
00556 }
00557 #endif /* _dbus_string_get_byte */
00558 
00569 dbus_bool_t
00570 _dbus_string_insert_bytes (DBusString   *str,
00571                            int           i,
00572                            int           n_bytes,
00573                            unsigned char byte)
00574 {
00575   DBUS_STRING_PREAMBLE (str);
00576   _dbus_assert (i <= real->len);
00577   _dbus_assert (i >= 0);
00578   _dbus_assert (n_bytes >= 0);
00579 
00580   if (n_bytes == 0)
00581     return TRUE;
00582   
00583   if (!open_gap (n_bytes, real, i))
00584     return FALSE;
00585   
00586   memset (real->str + i, byte, n_bytes);
00587 
00588   return TRUE;
00589 }
00590 
00599 dbus_bool_t
00600 _dbus_string_insert_byte (DBusString   *str,
00601                            int           i,
00602                            unsigned char byte)
00603 {
00604   DBUS_STRING_PREAMBLE (str);
00605   _dbus_assert (i <= real->len);
00606   _dbus_assert (i >= 0);
00607   
00608   if (!open_gap (1, real, i))
00609     return FALSE;
00610 
00611   real->str[i] = byte;
00612 
00613   return TRUE;
00614 }
00615 
00626 dbus_bool_t
00627 _dbus_string_steal_data (DBusString        *str,
00628                          char             **data_return)
00629 {
00630   DBUS_STRING_PREAMBLE (str);
00631   _dbus_assert (data_return != NULL);
00632 
00633   undo_alignment (real);
00634   
00635   *data_return = (char*) real->str;
00636 
00637   /* reset the string */
00638   if (!_dbus_string_init (str))
00639     {
00640       /* hrm, put it back then */
00641       real->str = (unsigned char*) *data_return;
00642       *data_return = NULL;
00643       fixup_alignment (real);
00644       return FALSE;
00645     }
00646 
00647   return TRUE;
00648 }
00649 
00657 dbus_bool_t
00658 _dbus_string_copy_data (const DBusString  *str,
00659                         char             **data_return)
00660 {
00661   DBUS_CONST_STRING_PREAMBLE (str);
00662   _dbus_assert (data_return != NULL);
00663   
00664   *data_return = dbus_malloc (real->len + 1);
00665   if (*data_return == NULL)
00666     return FALSE;
00667 
00668   memcpy (*data_return, real->str, real->len + 1);
00669 
00670   return TRUE;
00671 }
00672 
00682 void
00683 _dbus_string_copy_to_buffer (const DBusString  *str,
00684                              char              *buffer,
00685                              int                avail_len)
00686 {
00687   DBUS_CONST_STRING_PREAMBLE (str);
00688 
00689   _dbus_assert (avail_len >= 0);
00690   _dbus_assert (avail_len >= real->len);
00691   
00692   memcpy (buffer, real->str, real->len);
00693 }
00694 
00704 void
00705 _dbus_string_copy_to_buffer_with_nul (const DBusString  *str,
00706                                       char              *buffer,
00707                                       int                avail_len)
00708 {
00709   DBUS_CONST_STRING_PREAMBLE (str);
00710 
00711   _dbus_assert (avail_len >= 0);
00712   _dbus_assert (avail_len > real->len);
00713   
00714   memcpy (buffer, real->str, real->len+1);
00715 }
00716 
00717 /* Only have the function if we don't have the macro */
00718 #ifndef _dbus_string_get_length
00719 
00724 int
00725 _dbus_string_get_length (const DBusString  *str)
00726 {
00727   DBUS_CONST_STRING_PREAMBLE (str);
00728   
00729   return real->len;
00730 }
00731 #endif /* !_dbus_string_get_length */
00732 
00745 dbus_bool_t
00746 _dbus_string_lengthen (DBusString *str,
00747                        int         additional_length)
00748 {
00749   DBUS_STRING_PREAMBLE (str);  
00750   _dbus_assert (additional_length >= 0);
00751 
00752   if (_DBUS_UNLIKELY (additional_length > _DBUS_STRING_MAX_LENGTH - real->len))
00753     return FALSE; /* would overflow */
00754   
00755   return set_length (real,
00756                      real->len + additional_length);
00757 }
00758 
00765 void
00766 _dbus_string_shorten (DBusString *str,
00767                       int         length_to_remove)
00768 {
00769   DBUS_STRING_PREAMBLE (str);
00770   _dbus_assert (length_to_remove >= 0);
00771   _dbus_assert (length_to_remove <= real->len);
00772 
00773   set_length (real,
00774               real->len - length_to_remove);
00775 }
00776 
00787 dbus_bool_t
00788 _dbus_string_set_length (DBusString *str,
00789                          int         length)
00790 {
00791   DBUS_STRING_PREAMBLE (str);
00792   _dbus_assert (length >= 0);
00793 
00794   return set_length (real, length);
00795 }
00796 
00797 static dbus_bool_t
00798 align_insert_point_then_open_gap (DBusString *str,
00799                                   int        *insert_at_p,
00800                                   int         alignment,
00801                                   int         gap_size)
00802 {
00803   unsigned long new_len; /* ulong to avoid _DBUS_ALIGN_VALUE overflow */
00804   unsigned long gap_pos;
00805   int insert_at;
00806   int delta;
00807   DBUS_STRING_PREAMBLE (str);
00808   _dbus_assert (alignment >= 1);
00809   _dbus_assert (alignment <= 8); /* it has to be a bug if > 8 */
00810 
00811   insert_at = *insert_at_p;
00812 
00813   _dbus_assert (insert_at <= real->len);
00814   
00815   gap_pos = _DBUS_ALIGN_VALUE (insert_at, alignment);
00816   new_len = real->len + (gap_pos - insert_at) + gap_size;
00817   
00818   if (_DBUS_UNLIKELY (new_len > (unsigned long) _DBUS_STRING_MAX_LENGTH))
00819     return FALSE;
00820   
00821   delta = new_len - real->len;
00822   _dbus_assert (delta >= 0);
00823 
00824   if (delta == 0) /* only happens if gap_size == 0 and insert_at is aligned already */
00825     {
00826       _dbus_assert (((unsigned long) *insert_at_p) == gap_pos);
00827       return TRUE;
00828     }
00829 
00830   if (_DBUS_UNLIKELY (!open_gap (new_len - real->len,
00831                                  real, insert_at)))
00832     return FALSE;
00833 
00834   /* nul the padding if we had to add any padding */
00835   if (gap_size < delta)
00836     {
00837       memset (&real->str[insert_at], '\0',
00838               gap_pos - insert_at);
00839     }
00840 
00841   *insert_at_p = gap_pos;
00842   
00843   return TRUE;
00844 }
00845 
00846 static dbus_bool_t
00847 align_length_then_lengthen (DBusString *str,
00848                             int         alignment,
00849                             int         then_lengthen_by)
00850 {
00851   int insert_at;
00852 
00853   insert_at = _dbus_string_get_length (str);
00854   
00855   return align_insert_point_then_open_gap (str,
00856                                            &insert_at,
00857                                            alignment, then_lengthen_by);
00858 }
00859 
00868 dbus_bool_t
00869 _dbus_string_align_length (DBusString *str,
00870                            int         alignment)
00871 {
00872   return align_length_then_lengthen (str, alignment, 0);
00873 }
00874 
00884 dbus_bool_t
00885 _dbus_string_alloc_space (DBusString        *str,
00886                           int                extra_bytes)
00887 {
00888   if (!_dbus_string_lengthen (str, extra_bytes))
00889     return FALSE;
00890   _dbus_string_shorten (str, extra_bytes);
00891 
00892   return TRUE;
00893 }
00894 
00895 static dbus_bool_t
00896 append (DBusRealString *real,
00897         const char     *buffer,
00898         int             buffer_len)
00899 {
00900   if (buffer_len == 0)
00901     return TRUE;
00902 
00903   if (!_dbus_string_lengthen ((DBusString*)real, buffer_len))
00904     return FALSE;
00905 
00906   memcpy (real->str + (real->len - buffer_len),
00907           buffer,
00908           buffer_len);
00909 
00910   return TRUE;
00911 }
00912 
00920 dbus_bool_t
00921 _dbus_string_append (DBusString *str,
00922                      const char *buffer)
00923 {
00924   unsigned long buffer_len;
00925   
00926   DBUS_STRING_PREAMBLE (str);
00927   _dbus_assert (buffer != NULL);
00928   
00929   buffer_len = strlen (buffer);
00930   if (buffer_len > (unsigned long) _DBUS_STRING_MAX_LENGTH)
00931     return FALSE;
00932   
00933   return append (real, buffer, buffer_len);
00934 }
00935 
00937 #define ASSIGN_2_OCTETS(p, octets) \
00938   *((dbus_uint16_t*)(p)) = *((dbus_uint16_t*)(octets));
00939 
00941 #define ASSIGN_4_OCTETS(p, octets) \
00942   *((dbus_uint32_t*)(p)) = *((dbus_uint32_t*)(octets));
00943 
00944 #ifdef DBUS_HAVE_INT64
00945 
00946 #define ASSIGN_8_OCTETS(p, octets) \
00947   *((dbus_uint64_t*)(p)) = *((dbus_uint64_t*)(octets));
00948 #else
00949 
00950 #define ASSIGN_8_OCTETS(p, octets)              \
00951 do {                                            \
00952   unsigned char *b;                             \
00953                                                 \
00954   b = p;                                        \
00955                                                 \
00956   *b++ = octets[0];                             \
00957   *b++ = octets[1];                             \
00958   *b++ = octets[2];                             \
00959   *b++ = octets[3];                             \
00960   *b++ = octets[4];                             \
00961   *b++ = octets[5];                             \
00962   *b++ = octets[6];                             \
00963   *b++ = octets[7];                             \
00964   _dbus_assert (b == p + 8);                    \
00965 } while (0)
00966 #endif /* DBUS_HAVE_INT64 */
00967 
00977 dbus_bool_t
00978 _dbus_string_insert_2_aligned (DBusString         *str,
00979                                int                 insert_at,
00980                                const unsigned char octets[4])
00981 {
00982   DBUS_STRING_PREAMBLE (str);
00983   
00984   if (!align_insert_point_then_open_gap (str, &insert_at, 2, 2))
00985     return FALSE;
00986 
00987   ASSIGN_2_OCTETS (real->str + insert_at, octets);
00988 
00989   return TRUE;
00990 }
00991 
01001 dbus_bool_t
01002 _dbus_string_insert_4_aligned (DBusString         *str,
01003                                int                 insert_at,
01004                                const unsigned char octets[4])
01005 {
01006   DBUS_STRING_PREAMBLE (str);
01007   
01008   if (!align_insert_point_then_open_gap (str, &insert_at, 4, 4))
01009     return FALSE;
01010 
01011   ASSIGN_4_OCTETS (real->str + insert_at, octets);
01012 
01013   return TRUE;
01014 }
01015 
01025 dbus_bool_t
01026 _dbus_string_insert_8_aligned (DBusString         *str,
01027                                int                 insert_at,
01028                                const unsigned char octets[8])
01029 {
01030   DBUS_STRING_PREAMBLE (str);
01031   
01032   if (!align_insert_point_then_open_gap (str, &insert_at, 8, 8))
01033     return FALSE;
01034 
01035   _dbus_assert (_DBUS_ALIGN_VALUE (insert_at, 8) == (unsigned) insert_at);
01036   
01037   ASSIGN_8_OCTETS (real->str + insert_at, octets);
01038 
01039   return TRUE;
01040 }
01041 
01042 
01053 dbus_bool_t
01054 _dbus_string_insert_alignment (DBusString        *str,
01055                                int               *insert_at,
01056                                int                alignment)
01057 {
01058   DBUS_STRING_PREAMBLE (str);
01059   
01060   if (!align_insert_point_then_open_gap (str, insert_at, alignment, 0))
01061     return FALSE;
01062 
01063   _dbus_assert (_DBUS_ALIGN_VALUE (*insert_at, alignment) == (unsigned) *insert_at);
01064 
01065   return TRUE;
01066 }
01067 
01077 dbus_bool_t
01078 _dbus_string_append_printf_valist  (DBusString        *str,
01079                                     const char        *format,
01080                                     va_list            args)
01081 {
01082   int len;
01083   va_list args_copy;
01084 
01085   DBUS_STRING_PREAMBLE (str);
01086 
01087   DBUS_VA_COPY (args_copy, args);
01088 
01089   /* Measure the message length without terminating nul */
01090   len = _dbus_printf_string_upper_bound (format, args);
01091 
01092   if (len < 0)
01093     return FALSE;
01094 
01095   if (!_dbus_string_lengthen (str, len))
01096     {
01097       /* don't leak the copy */
01098       va_end (args_copy);
01099       return FALSE;
01100     }
01101   
01102   vsprintf ((char*) (real->str + (real->len - len)),
01103             format, args_copy);
01104 
01105   va_end (args_copy);
01106 
01107   return TRUE;
01108 }
01109 
01118 dbus_bool_t
01119 _dbus_string_append_printf (DBusString        *str,
01120                             const char        *format,
01121                             ...)
01122 {
01123   va_list args;
01124   dbus_bool_t retval;
01125   
01126   va_start (args, format);
01127   retval = _dbus_string_append_printf_valist (str, format, args);
01128   va_end (args);
01129 
01130   return retval;
01131 }
01132 
01141 dbus_bool_t
01142 _dbus_string_append_len (DBusString *str,
01143                          const char *buffer,
01144                          int         len)
01145 {
01146   DBUS_STRING_PREAMBLE (str);
01147   _dbus_assert (buffer != NULL);
01148   _dbus_assert (len >= 0);
01149 
01150   return append (real, buffer, len);
01151 }
01152 
01161 dbus_bool_t
01162 _dbus_string_append_byte (DBusString    *str,
01163                           unsigned char  byte)
01164 {
01165   DBUS_STRING_PREAMBLE (str);
01166 
01167   if (!set_length (real, real->len + 1))
01168     return FALSE;
01169 
01170   real->str[real->len-1] = byte;
01171 
01172   return TRUE;
01173 }
01174 
01175 static void
01176 delete (DBusRealString *real,
01177         int             start,
01178         int             len)
01179 {
01180   if (len == 0)
01181     return;
01182   
01183   memmove (real->str + start, real->str + start + len, real->len - (start + len));
01184   real->len -= len;
01185   real->str[real->len] = '\0';
01186 }
01187 
01197 void
01198 _dbus_string_delete (DBusString       *str,
01199                      int               start,
01200                      int               len)
01201 {
01202   DBUS_STRING_PREAMBLE (str);
01203   _dbus_assert (start >= 0);
01204   _dbus_assert (len >= 0);
01205   _dbus_assert (start <= real->len);
01206   _dbus_assert (len <= real->len - start);
01207   
01208   delete (real, start, len);
01209 }
01210 
01211 static dbus_bool_t
01212 copy (DBusRealString *source,
01213       int             start,
01214       int             len,
01215       DBusRealString *dest,
01216       int             insert_at)
01217 {
01218   if (len == 0)
01219     return TRUE;
01220 
01221   if (!open_gap (len, dest, insert_at))
01222     return FALSE;
01223   
01224   memmove (dest->str + insert_at,
01225            source->str + start,
01226            len);
01227 
01228   return TRUE;
01229 }
01230 
01240 #define DBUS_STRING_COPY_PREAMBLE(source, start, dest, insert_at)       \
01241   DBusRealString *real_source = (DBusRealString*) source;               \
01242   DBusRealString *real_dest = (DBusRealString*) dest;                   \
01243   _dbus_assert ((source) != (dest));                                    \
01244   DBUS_GENERIC_STRING_PREAMBLE (real_source);                           \
01245   DBUS_GENERIC_STRING_PREAMBLE (real_dest);                             \
01246   _dbus_assert (!real_dest->constant);                                  \
01247   _dbus_assert (!real_dest->locked);                                    \
01248   _dbus_assert ((start) >= 0);                                          \
01249   _dbus_assert ((start) <= real_source->len);                           \
01250   _dbus_assert ((insert_at) >= 0);                                      \
01251   _dbus_assert ((insert_at) <= real_dest->len)
01252 
01263 dbus_bool_t
01264 _dbus_string_move (DBusString       *source,
01265                    int               start,
01266                    DBusString       *dest,
01267                    int               insert_at)
01268 {
01269   DBusRealString *real_source = (DBusRealString*) source;
01270   _dbus_assert (start <= real_source->len);
01271   
01272   return _dbus_string_move_len (source, start,
01273                                 real_source->len - start,
01274                                 dest, insert_at);
01275 }
01276 
01287 dbus_bool_t
01288 _dbus_string_copy (const DBusString *source,
01289                    int               start,
01290                    DBusString       *dest,
01291                    int               insert_at)
01292 {
01293   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
01294 
01295   return copy (real_source, start,
01296                real_source->len - start,
01297                real_dest,
01298                insert_at);
01299 }
01300 
01312 dbus_bool_t
01313 _dbus_string_move_len (DBusString       *source,
01314                        int               start,
01315                        int               len,
01316                        DBusString       *dest,
01317                        int               insert_at)
01318 
01319 {
01320   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
01321   _dbus_assert (len >= 0);
01322   _dbus_assert ((start + len) <= real_source->len);
01323 
01324 
01325   if (len == 0)
01326     {
01327       return TRUE;
01328     }
01329   else if (start == 0 &&
01330            len == real_source->len &&
01331            real_dest->len == 0)
01332     {
01333       /* Short-circuit moving an entire existing string to an empty string
01334        * by just swapping the buffers.
01335        */
01336       /* we assume ->constant doesn't matter as you can't have
01337        * a constant string involved in a move.
01338        */
01339 #define ASSIGN_DATA(a, b) do {                  \
01340         (a)->str = (b)->str;                    \
01341         (a)->len = (b)->len;                    \
01342         (a)->allocated = (b)->allocated;        \
01343         (a)->align_offset = (b)->align_offset;  \
01344       } while (0)
01345       
01346       DBusRealString tmp;
01347 
01348       ASSIGN_DATA (&tmp, real_source);
01349       ASSIGN_DATA (real_source, real_dest);
01350       ASSIGN_DATA (real_dest, &tmp);
01351 
01352       return TRUE;
01353     }
01354   else
01355     {
01356       if (!copy (real_source, start, len,
01357                  real_dest,
01358                  insert_at))
01359         return FALSE;
01360       
01361       delete (real_source, start,
01362               len);
01363       
01364       return TRUE;
01365     }
01366 }
01367 
01379 dbus_bool_t
01380 _dbus_string_copy_len (const DBusString *source,
01381                        int               start,
01382                        int               len,
01383                        DBusString       *dest,
01384                        int               insert_at)
01385 {
01386   DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
01387   _dbus_assert (len >= 0);
01388   _dbus_assert (start <= real_source->len);
01389   _dbus_assert (len <= real_source->len - start);
01390   
01391   return copy (real_source, start, len,
01392                real_dest,
01393                insert_at);
01394 }
01395 
01408 dbus_bool_t
01409 _dbus_string_replace_len (const DBusString *source,
01410                           int               start,
01411                           int               len,
01412                           DBusString       *dest,
01413                           int               replace_at,
01414                           int               replace_len)
01415 {
01416   DBUS_STRING_COPY_PREAMBLE (source, start, dest, replace_at);
01417   _dbus_assert (len >= 0);
01418   _dbus_assert (start <= real_source->len);
01419   _dbus_assert (len <= real_source->len - start);
01420   _dbus_assert (replace_at >= 0);
01421   _dbus_assert (replace_at <= real_dest->len);
01422   _dbus_assert (replace_len <= real_dest->len - replace_at);
01423 
01424   if (len == replace_len)
01425     {
01426       memmove (real_dest->str + replace_at,
01427                real_source->str + start, len);
01428     }
01429   else if (len < replace_len)
01430     {
01431       memmove (real_dest->str + replace_at,
01432                real_source->str + start, len);
01433       delete (real_dest, replace_at + len,
01434               replace_len - len);
01435     }
01436   else
01437     {
01438       int diff;
01439 
01440       _dbus_assert (len > replace_len);
01441 
01442       diff = len - replace_len;
01443 
01444       /* First of all we check if destination string can be enlarged as
01445        * required, then we overwrite previous bytes
01446        */
01447 
01448       if (!copy (real_source, start + replace_len, diff,
01449                  real_dest, replace_at + replace_len))
01450         return FALSE;
01451 
01452       memmove (real_dest->str + replace_at,
01453                real_source->str + start, replace_len);
01454     }
01455 
01456   return TRUE;
01457 }
01458 
01471 dbus_bool_t
01472 _dbus_string_split_on_byte (DBusString        *source,
01473                             unsigned char      byte,
01474                             DBusString        *tail)
01475 {
01476   int byte_position;
01477   char byte_string[2] = "";
01478   int head_length;
01479   int tail_length;
01480 
01481   byte_string[0] = (char) byte;
01482 
01483   if (!_dbus_string_find (source, 0, byte_string, &byte_position))
01484     return FALSE;
01485 
01486   head_length = byte_position;
01487   tail_length = _dbus_string_get_length (source) - head_length - 1;
01488 
01489   if (!_dbus_string_move_len (source, byte_position + 1, tail_length,
01490                               tail, 0))
01491     return FALSE;
01492 
01493   /* remove the trailing delimiter byte from the head now.
01494    */
01495   if (!_dbus_string_set_length (source, head_length))
01496     return FALSE;
01497 
01498   return TRUE;
01499 }
01500 
01501 /* Unicode macros and utf8_validate() from GLib Owen Taylor, Havoc
01502  * Pennington, and Tom Tromey are the authors and authorized relicense.
01503  */
01504 
01510 #define UTF8_COMPUTE(Char, Mask, Len)                                         \
01511   if (Char < 128)                                                             \
01512     {                                                                         \
01513       Len = 1;                                                                \
01514       Mask = 0x7f;                                                            \
01515     }                                                                         \
01516   else if ((Char & 0xe0) == 0xc0)                                             \
01517     {                                                                         \
01518       Len = 2;                                                                \
01519       Mask = 0x1f;                                                            \
01520     }                                                                         \
01521   else if ((Char & 0xf0) == 0xe0)                                             \
01522     {                                                                         \
01523       Len = 3;                                                                \
01524       Mask = 0x0f;                                                            \
01525     }                                                                         \
01526   else if ((Char & 0xf8) == 0xf0)                                             \
01527     {                                                                         \
01528       Len = 4;                                                                \
01529       Mask = 0x07;                                                            \
01530     }                                                                         \
01531   else if ((Char & 0xfc) == 0xf8)                                             \
01532     {                                                                         \
01533       Len = 5;                                                                \
01534       Mask = 0x03;                                                            \
01535     }                                                                         \
01536   else if ((Char & 0xfe) == 0xfc)                                             \
01537     {                                                                         \
01538       Len = 6;                                                                \
01539       Mask = 0x01;                                                            \
01540     }                                                                         \
01541   else                                                                        \
01542     {                                                                         \
01543       Len = 0;                                                               \
01544       Mask = 0;                                                               \
01545     }
01546 
01551 #define UTF8_LENGTH(Char)              \
01552   ((Char) < 0x80 ? 1 :                 \
01553    ((Char) < 0x800 ? 2 :               \
01554     ((Char) < 0x10000 ? 3 :            \
01555      ((Char) < 0x200000 ? 4 :          \
01556       ((Char) < 0x4000000 ? 5 : 6)))))
01557    
01567 #define UTF8_GET(Result, Chars, Count, Mask, Len)                             \
01568   (Result) = (Chars)[0] & (Mask);                                             \
01569   for ((Count) = 1; (Count) < (Len); ++(Count))                               \
01570     {                                                                         \
01571       if (((Chars)[(Count)] & 0xc0) != 0x80)                                  \
01572         {                                                                     \
01573           (Result) = -1;                                                      \
01574           break;                                                              \
01575         }                                                                     \
01576       (Result) <<= 6;                                                         \
01577       (Result) |= ((Chars)[(Count)] & 0x3f);                                  \
01578     }
01579 
01590 #define UNICODE_VALID(Char)                   \
01591     ((Char) < 0x110000 &&                     \
01592      (((Char) & 0xFFFFF800) != 0xD800))
01593 
01608 dbus_bool_t
01609 _dbus_string_find (const DBusString *str,
01610                    int               start,
01611                    const char       *substr,
01612                    int              *found)
01613 {
01614   return _dbus_string_find_to (str, start,
01615                                ((const DBusRealString*)str)->len,
01616                                substr, found);
01617 }
01618 
01631 dbus_bool_t
01632 _dbus_string_find_eol (const DBusString *str,
01633                        int               start,
01634                        int              *found,
01635                        int              *found_len)
01636 {
01637   int i;
01638 
01639   DBUS_CONST_STRING_PREAMBLE (str);
01640   _dbus_assert (start <= real->len);
01641   _dbus_assert (start >= 0);
01642   
01643   i = start;
01644   while (i < real->len)
01645     {
01646       if (real->str[i] == '\r') 
01647         {
01648           if ((i+1) < real->len && real->str[i+1] == '\n') /* "\r\n" */
01649             {
01650               if (found) 
01651                 *found = i;
01652               if (found_len)
01653                 *found_len = 2;
01654               return TRUE;
01655             } 
01656           else /* only "\r" */
01657             {
01658               if (found) 
01659                 *found = i;
01660               if (found_len)
01661                 *found_len = 1;
01662               return TRUE;
01663             }
01664         } 
01665       else if (real->str[i] == '\n')  /* only "\n" */
01666         {
01667           if (found) 
01668             *found = i;
01669           if (found_len)
01670             *found_len = 1;
01671           return TRUE;
01672         }
01673       ++i;
01674     }
01675 
01676   if (found)
01677     *found = real->len;
01678 
01679   if (found_len)
01680     *found_len = 0;
01681   
01682   return FALSE;
01683 }
01684 
01701 dbus_bool_t
01702 _dbus_string_find_to (const DBusString *str,
01703                       int               start,
01704                       int               end,
01705                       const char       *substr,
01706                       int              *found)
01707 {
01708   int i;
01709   DBUS_CONST_STRING_PREAMBLE (str);
01710   _dbus_assert (substr != NULL);
01711   _dbus_assert (start <= real->len);
01712   _dbus_assert (start >= 0);
01713   _dbus_assert (substr != NULL);
01714   _dbus_assert (end <= real->len);
01715   _dbus_assert (start <= end);
01716 
01717   /* we always "find" an empty string */
01718   if (*substr == '\0')
01719     {
01720       if (found)
01721         *found = start;
01722       return TRUE;
01723     }
01724 
01725   i = start;
01726   while (i < end)
01727     {
01728       if (real->str[i] == substr[0])
01729         {
01730           int j = i + 1;
01731           
01732           while (j < end)
01733             {
01734               if (substr[j - i] == '\0')
01735                 break;
01736               else if (real->str[j] != substr[j - i])
01737                 break;
01738               
01739               ++j;
01740             }
01741 
01742           if (substr[j - i] == '\0')
01743             {
01744               if (found)
01745                 *found = i;
01746               return TRUE;
01747             }
01748         }
01749       
01750       ++i;
01751     }
01752 
01753   if (found)
01754     *found = end;
01755   
01756   return FALSE;  
01757 }
01758 
01769 dbus_bool_t
01770 _dbus_string_find_blank (const DBusString *str,
01771                          int               start,
01772                          int              *found)
01773 {
01774   int i;
01775   DBUS_CONST_STRING_PREAMBLE (str);
01776   _dbus_assert (start <= real->len);
01777   _dbus_assert (start >= 0);
01778   
01779   i = start;
01780   while (i < real->len)
01781     {
01782       if (real->str[i] == ' ' ||
01783           real->str[i] == '\t')
01784         {
01785           if (found)
01786             *found = i;
01787           return TRUE;
01788         }
01789       
01790       ++i;
01791     }
01792 
01793   if (found)
01794     *found = real->len;
01795   
01796   return FALSE;
01797 }
01798 
01807 void
01808 _dbus_string_skip_blank (const DBusString *str,
01809                          int               start,
01810                          int              *end)
01811 {
01812   int i;
01813   DBUS_CONST_STRING_PREAMBLE (str);
01814   _dbus_assert (start <= real->len);
01815   _dbus_assert (start >= 0);
01816   
01817   i = start;
01818   while (i < real->len)
01819     {
01820       if (!DBUS_IS_ASCII_BLANK (real->str[i]))
01821         break;
01822       
01823       ++i;
01824     }
01825 
01826   _dbus_assert (i == real->len || !DBUS_IS_ASCII_WHITE (real->str[i]));
01827   
01828   if (end)
01829     *end = i;
01830 }
01831 
01832 
01841 void
01842 _dbus_string_skip_white (const DBusString *str,
01843                          int               start,
01844                          int              *end)
01845 {
01846   int i;
01847   DBUS_CONST_STRING_PREAMBLE (str);
01848   _dbus_assert (start <= real->len);
01849   _dbus_assert (start >= 0);
01850   
01851   i = start;
01852   while (i < real->len)
01853     {
01854       if (!DBUS_IS_ASCII_WHITE (real->str[i]))
01855         break;
01856       
01857       ++i;
01858     }
01859 
01860   _dbus_assert (i == real->len || !(DBUS_IS_ASCII_WHITE (real->str[i])));
01861   
01862   if (end)
01863     *end = i;
01864 }
01865 
01874 void
01875 _dbus_string_skip_white_reverse (const DBusString *str,
01876                                  int               end,
01877                                  int              *start)
01878 {
01879   int i;
01880   DBUS_CONST_STRING_PREAMBLE (str);
01881   _dbus_assert (end <= real->len);
01882   _dbus_assert (end >= 0);
01883   
01884   i = end;
01885   while (i > 0)
01886     {
01887       if (!DBUS_IS_ASCII_WHITE (real->str[i-1]))
01888         break;
01889       --i;
01890     }
01891 
01892   _dbus_assert (i >= 0 && (i == 0 || !(DBUS_IS_ASCII_WHITE (real->str[i-1]))));
01893   
01894   if (start)
01895     *start = i;
01896 }
01897 
01913 dbus_bool_t
01914 _dbus_string_pop_line (DBusString *source,
01915                        DBusString *dest)
01916 {
01917   int eol, eol_len;
01918   
01919   _dbus_string_set_length (dest, 0);
01920   
01921   eol = 0;
01922   eol_len = 0;
01923   if (!_dbus_string_find_eol (source, 0, &eol, &eol_len))
01924     {
01925       _dbus_assert (eol == _dbus_string_get_length (source));
01926       if (eol == 0)
01927         {
01928           /* If there's no newline and source has zero length, we're done */
01929           return FALSE;
01930         }
01931       /* otherwise, the last line of the file has no eol characters */
01932     }
01933 
01934   /* remember eol can be 0 if it's an empty line, but eol_len should not be zero also
01935    * since find_eol returned TRUE
01936    */
01937   
01938   if (!_dbus_string_move_len (source, 0, eol + eol_len, dest, 0))
01939     return FALSE;
01940   
01941   /* remove line ending */
01942   if (!_dbus_string_set_length (dest, eol))
01943     {
01944       _dbus_assert_not_reached ("out of memory when shortening a string");
01945       return FALSE;
01946     }
01947 
01948   return TRUE;
01949 }
01950 
01951 #ifdef DBUS_BUILD_TESTS
01952 
01958 void
01959 _dbus_string_delete_first_word (DBusString *str)
01960 {
01961   int i;
01962   
01963   if (_dbus_string_find_blank (str, 0, &i))
01964     _dbus_string_skip_blank (str, i, &i);
01965 
01966   _dbus_string_delete (str, 0, i);
01967 }
01968 #endif
01969 
01970 #ifdef DBUS_BUILD_TESTS
01971 
01976 void
01977 _dbus_string_delete_leading_blanks (DBusString *str)
01978 {
01979   int i;
01980   
01981   _dbus_string_skip_blank (str, 0, &i);
01982 
01983   if (i > 0)
01984     _dbus_string_delete (str, 0, i);
01985 }
01986 #endif
01987 
01993 void
01994 _dbus_string_chop_white(DBusString *str)
01995 {
01996   int i;
01997   
01998   _dbus_string_skip_white (str, 0, &i);
01999 
02000   if (i > 0)
02001     _dbus_string_delete (str, 0, i);
02002   
02003   _dbus_string_skip_white_reverse (str, _dbus_string_get_length (str), &i);
02004 
02005   _dbus_string_set_length (str, i);
02006 }
02007 
02017 dbus_bool_t
02018 _dbus_string_equal (const DBusString *a,
02019                     const DBusString *b)
02020 {
02021   const unsigned char *ap;
02022   const unsigned char *bp;
02023   const unsigned char *a_end;
02024   const DBusRealString *real_a = (const DBusRealString*) a;
02025   const DBusRealString *real_b = (const DBusRealString*) b;
02026   DBUS_GENERIC_STRING_PREAMBLE (real_a);
02027   DBUS_GENERIC_STRING_PREAMBLE (real_b);
02028 
02029   if (real_a->len != real_b->len)
02030     return FALSE;
02031 
02032   ap = real_a->str;
02033   bp = real_b->str;
02034   a_end = real_a->str + real_a->len;
02035   while (ap != a_end)
02036     {
02037       if (*ap != *bp)
02038         return FALSE;
02039       
02040       ++ap;
02041       ++bp;
02042     }
02043 
02044   return TRUE;
02045 }
02046 
02060 dbus_bool_t
02061 _dbus_string_equal_len (const DBusString *a,
02062                         const DBusString *b,
02063                         int               len)
02064 {
02065   const unsigned char *ap;
02066   const unsigned char *bp;
02067   const unsigned char *a_end;
02068   const DBusRealString *real_a = (const DBusRealString*) a;
02069   const DBusRealString *real_b = (const DBusRealString*) b;
02070   DBUS_GENERIC_STRING_PREAMBLE (real_a);
02071   DBUS_GENERIC_STRING_PREAMBLE (real_b);
02072 
02073   if (real_a->len != real_b->len &&
02074       (real_a->len < len || real_b->len < len))
02075     return FALSE;
02076 
02077   ap = real_a->str;
02078   bp = real_b->str;
02079   a_end = real_a->str + MIN (real_a->len, len);
02080   while (ap != a_end)
02081     {
02082       if (*ap != *bp)
02083         return FALSE;
02084       
02085       ++ap;
02086       ++bp;
02087     }
02088 
02089   return TRUE;
02090 }
02091 
02108 dbus_bool_t
02109 _dbus_string_equal_substring (const DBusString  *a,
02110                               int                a_start,
02111                               int                a_len,
02112                               const DBusString  *b,
02113                               int                b_start)
02114 {
02115   const unsigned char *ap;
02116   const unsigned char *bp;
02117   const unsigned char *a_end;
02118   const DBusRealString *real_a = (const DBusRealString*) a;
02119   const DBusRealString *real_b = (const DBusRealString*) b;
02120   DBUS_GENERIC_STRING_PREAMBLE (real_a);
02121   DBUS_GENERIC_STRING_PREAMBLE (real_b);
02122   _dbus_assert (a_start >= 0);
02123   _dbus_assert (a_len >= 0);
02124   _dbus_assert (a_start <= real_a->len);
02125   _dbus_assert (a_len <= real_a->len - a_start);
02126   _dbus_assert (b_start >= 0);
02127   _dbus_assert (b_start <= real_b->len);
02128   
02129   if (a_len > real_b->len - b_start)
02130     return FALSE;
02131 
02132   ap = real_a->str + a_start;
02133   bp = real_b->str + b_start;
02134   a_end = ap + a_len;
02135   while (ap != a_end)
02136     {
02137       if (*ap != *bp)
02138         return FALSE;
02139       
02140       ++ap;
02141       ++bp;
02142     }
02143 
02144   _dbus_assert (bp <= (real_b->str + real_b->len));
02145   
02146   return TRUE;
02147 }
02148 
02156 dbus_bool_t
02157 _dbus_string_equal_c_str (const DBusString *a,
02158                           const char       *c_str)
02159 {
02160   const unsigned char *ap;
02161   const unsigned char *bp;
02162   const unsigned char *a_end;
02163   const DBusRealString *real_a = (const DBusRealString*) a;
02164   DBUS_GENERIC_STRING_PREAMBLE (real_a);
02165   _dbus_assert (c_str != NULL);
02166   
02167   ap = real_a->str;
02168   bp = (const unsigned char*) c_str;
02169   a_end = real_a->str + real_a->len;
02170   while (ap != a_end && *bp)
02171     {
02172       if (*ap != *bp)
02173         return FALSE;
02174       
02175       ++ap;
02176       ++bp;
02177     }
02178 
02179   if (ap != a_end || *bp)
02180     return FALSE;
02181   
02182   return TRUE;
02183 }
02184 
02192 dbus_bool_t
02193 _dbus_string_starts_with_c_str (const DBusString *a,
02194                                 const char       *c_str)
02195 {
02196   const unsigned char *ap;
02197   const unsigned char *bp;
02198   const unsigned char *a_end;
02199   const DBusRealString *real_a = (const DBusRealString*) a;
02200   DBUS_GENERIC_STRING_PREAMBLE (real_a);
02201   _dbus_assert (c_str != NULL);
02202   
02203   ap = real_a->str;
02204   bp = (const unsigned char*) c_str;
02205   a_end = real_a->str + real_a->len;
02206   while (ap != a_end && *bp)
02207     {
02208       if (*ap != *bp)
02209         return FALSE;
02210       
02211       ++ap;
02212       ++bp;
02213     }
02214 
02215   if (*bp == '\0')
02216     return TRUE;
02217   else
02218     return FALSE;
02219 }
02220 
02229 dbus_bool_t
02230 _dbus_string_append_byte_as_hex (DBusString *str,
02231                                  unsigned char byte)
02232 {
02233   const char hexdigits[16] = {
02234     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
02235     'a', 'b', 'c', 'd', 'e', 'f'
02236   };
02237 
02238   if (!_dbus_string_append_byte (str,
02239                                  hexdigits[(byte >> 4)]))
02240     return FALSE;
02241   
02242   if (!_dbus_string_append_byte (str,
02243                                  hexdigits[(byte & 0x0f)]))
02244     {
02245       _dbus_string_set_length (str,
02246                                _dbus_string_get_length (str) - 1);
02247       return FALSE;
02248     }
02249 
02250   return TRUE;
02251 }
02252 
02263 dbus_bool_t
02264 _dbus_string_hex_encode (const DBusString *source,
02265                          int               start,
02266                          DBusString       *dest,
02267                          int               insert_at)
02268 {
02269   DBusString result;
02270   const unsigned char *p;
02271   const unsigned char *end;
02272   dbus_bool_t retval;
02273   
02274   _dbus_assert (start <= _dbus_string_get_length (source));
02275 
02276   if (!_dbus_string_init (&result))
02277     return FALSE;
02278 
02279   retval = FALSE;
02280   
02281   p = (const unsigned char*) _dbus_string_get_const_data (source);
02282   end = p + _dbus_string_get_length (source);
02283   p += start;
02284   
02285   while (p != end)
02286     {
02287       if (!_dbus_string_append_byte_as_hex (&result, *p))
02288         goto out;
02289       
02290       ++p;
02291     }
02292 
02293   if (!_dbus_string_move (&result, 0, dest, insert_at))
02294     goto out;
02295 
02296   retval = TRUE;
02297 
02298  out:
02299   _dbus_string_free (&result);
02300   return retval;
02301 }
02302 
02313 dbus_bool_t
02314 _dbus_string_hex_decode (const DBusString *source,
02315                          int               start,
02316                          int              *end_return,
02317                          DBusString       *dest,
02318                          int               insert_at)
02319 {
02320   DBusString result;
02321   const unsigned char *p;
02322   const unsigned char *end;
02323   dbus_bool_t retval;
02324   dbus_bool_t high_bits;
02325   
02326   _dbus_assert (start <= _dbus_string_get_length (source));
02327 
02328   if (!_dbus_string_init (&result))
02329     return FALSE;
02330 
02331   retval = FALSE;
02332 
02333   high_bits = TRUE;
02334   p = (const unsigned char*) _dbus_string_get_const_data (source);
02335   end = p + _dbus_string_get_length (source);
02336   p += start;
02337   
02338   while (p != end)
02339     {
02340       unsigned int val;
02341 
02342       switch (*p)
02343         {
02344         case '0':
02345           val = 0;
02346           break;
02347         case '1':
02348           val = 1;
02349           break;
02350         case '2':
02351           val = 2;
02352           break;
02353         case '3':
02354           val = 3;
02355           break;
02356         case '4':
02357           val = 4;
02358           break;
02359         case '5':
02360           val = 5;
02361           break;
02362         case '6':
02363           val = 6;
02364           break;
02365         case '7':
02366           val = 7;
02367           break;
02368         case '8':
02369           val = 8;
02370           break;
02371         case '9':
02372           val = 9;
02373           break;
02374         case 'a':
02375         case 'A':
02376           val = 10;
02377           break;
02378         case 'b':
02379         case 'B':
02380           val = 11;
02381           break;
02382         case 'c':
02383         case 'C':
02384           val = 12;
02385           break;
02386         case 'd':
02387         case 'D':
02388           val = 13;
02389           break;
02390         case 'e':
02391         case 'E':
02392           val = 14;
02393           break;
02394         case 'f':
02395         case 'F':
02396           val = 15;
02397           break;
02398         default:
02399           goto done;
02400         }
02401 
02402       if (high_bits)
02403         {
02404           if (!_dbus_string_append_byte (&result,
02405                                          val << 4))
02406             goto out;
02407         }
02408       else
02409         {
02410           int len;
02411           unsigned char b;
02412 
02413           len = _dbus_string_get_length (&result);
02414           
02415           b = _dbus_string_get_byte (&result, len - 1);
02416 
02417           b |= val;
02418 
02419           _dbus_string_set_byte (&result, len - 1, b);
02420         }
02421 
02422       high_bits = !high_bits;
02423 
02424       ++p;
02425     }
02426 
02427  done:
02428   if (!_dbus_string_move (&result, 0, dest, insert_at))
02429     goto out;
02430 
02431   if (end_return)
02432     *end_return = p - (const unsigned char*) _dbus_string_get_const_data (source);
02433 
02434   retval = TRUE;
02435   
02436  out:
02437   _dbus_string_free (&result);  
02438   return retval;
02439 }
02440 
02454 dbus_bool_t
02455 _dbus_string_validate_ascii (const DBusString *str,
02456                              int               start,
02457                              int               len)
02458 {
02459   const unsigned char *s;
02460   const unsigned char *end;
02461   DBUS_CONST_STRING_PREAMBLE (str);
02462   _dbus_assert (start >= 0);
02463   _dbus_assert (start <= real->len);
02464   _dbus_assert (len >= 0);
02465   
02466   if (len > real->len - start)
02467     return FALSE;
02468   
02469   s = real->str + start;
02470   end = s + len;
02471   while (s != end)
02472     {
02473       if (_DBUS_UNLIKELY (!_DBUS_ISASCII (*s)))
02474         return FALSE;
02475         
02476       ++s;
02477     }
02478   
02479   return TRUE;
02480 }
02481 
02489 void
02490 _dbus_string_tolower_ascii (const DBusString *str,
02491                             int               start,
02492                             int               len)
02493 {
02494   unsigned char *s;
02495   unsigned char *end;
02496   DBUS_STRING_PREAMBLE (str);
02497   _dbus_assert (start >= 0);
02498   _dbus_assert (start <= real->len);
02499   _dbus_assert (len >= 0);
02500   _dbus_assert (len <= real->len - start);
02501 
02502   s = real->str + start;
02503   end = s + len;
02504 
02505   while (s != end)
02506     {
02507       if (*s >= 'A' && *s <= 'Z')
02508           *s += 'a' - 'A';
02509       ++s;
02510     }
02511 }
02512 
02520 void
02521 _dbus_string_toupper_ascii (const DBusString *str,
02522                             int               start,
02523                             int               len)
02524 {
02525   unsigned char *s;
02526   unsigned char *end;
02527   DBUS_STRING_PREAMBLE (str);
02528   _dbus_assert (start >= 0);
02529   _dbus_assert (start <= real->len);
02530   _dbus_assert (len >= 0);
02531   _dbus_assert (len <= real->len - start);
02532 
02533   s = real->str + start;
02534   end = s + len;
02535 
02536   while (s != end)
02537     {
02538       if (*s >= 'a' && *s <= 'z')
02539           *s += 'A' - 'a';
02540       ++s;
02541     }
02542 }
02543 
02559 dbus_bool_t
02560 _dbus_string_validate_utf8  (const DBusString *str,
02561                              int               start,
02562                              int               len)
02563 {
02564   const unsigned char *p;
02565   const unsigned char *end;
02566   DBUS_CONST_STRING_PREAMBLE (str);
02567   _dbus_assert (start >= 0);
02568   _dbus_assert (start <= real->len);
02569   _dbus_assert (len >= 0);
02570 
02571   /* we are doing _DBUS_UNLIKELY() here which might be
02572    * dubious in a generic library like GLib, but in D-Bus
02573    * we know we're validating messages and that it would
02574    * only be evil/broken apps that would have invalid
02575    * UTF-8. Also, this function seems to be a performance
02576    * bottleneck in profiles.
02577    */
02578   
02579   if (_DBUS_UNLIKELY (len > real->len - start))
02580     return FALSE;
02581   
02582   p = real->str + start;
02583   end = p + len;
02584   
02585   while (p < end)
02586     {
02587       int i, mask, char_len;
02588       dbus_unichar_t result;
02589 
02590       /* nul bytes considered invalid */
02591       if (*p == '\0')
02592         break;
02593       
02594       /* Special-case ASCII; this makes us go a lot faster in
02595        * D-Bus profiles where we are typically validating
02596        * function names and such. We have to know that
02597        * all following checks will pass for ASCII though,
02598        * comments follow ...
02599        */      
02600       if (*p < 128)
02601         {
02602           ++p;
02603           continue;
02604         }
02605       
02606       UTF8_COMPUTE (*p, mask, char_len);
02607 
02608       if (_DBUS_UNLIKELY (char_len == 0))  /* ASCII: char_len == 1 */
02609         break;
02610 
02611       /* check that the expected number of bytes exists in the remaining length */
02612       if (_DBUS_UNLIKELY ((end - p) < char_len)) /* ASCII: p < end and char_len == 1 */
02613         break;
02614         
02615       UTF8_GET (result, p, i, mask, char_len);
02616 
02617       /* Check for overlong UTF-8 */
02618       if (_DBUS_UNLIKELY (UTF8_LENGTH (result) != char_len)) /* ASCII: UTF8_LENGTH == 1 */
02619         break;
02620 #if 0
02621       /* The UNICODE_VALID check below will catch this */
02622       if (_DBUS_UNLIKELY (result == (dbus_unichar_t)-1)) /* ASCII: result = ascii value */
02623         break;
02624 #endif
02625 
02626       if (_DBUS_UNLIKELY (!UNICODE_VALID (result))) /* ASCII: always valid */
02627         break;
02628 
02629       /* UNICODE_VALID should have caught it */
02630       _dbus_assert (result != (dbus_unichar_t)-1);
02631       
02632       p += char_len;
02633     }
02634 
02635   /* See that we covered the entire length if a length was
02636    * passed in
02637    */
02638   if (_DBUS_UNLIKELY (p != end))
02639     return FALSE;
02640   else
02641     return TRUE;
02642 }
02643 
02657 dbus_bool_t
02658 _dbus_string_validate_nul (const DBusString *str,
02659                            int               start,
02660                            int               len)
02661 {
02662   const unsigned char *s;
02663   const unsigned char *end;
02664   DBUS_CONST_STRING_PREAMBLE (str);
02665   _dbus_assert (start >= 0);
02666   _dbus_assert (len >= 0);
02667   _dbus_assert (start <= real->len);
02668   
02669   if (len > real->len - start)
02670     return FALSE;
02671   
02672   s = real->str + start;
02673   end = s + len;
02674   while (s != end)
02675     {
02676       if (_DBUS_UNLIKELY (*s != '\0'))
02677         return FALSE;
02678       ++s;
02679     }
02680   
02681   return TRUE;
02682 }
02683 
02689 void
02690 _dbus_string_zero (DBusString *str)
02691 {
02692   DBUS_STRING_PREAMBLE (str);
02693 
02694   memset (real->str - real->align_offset, '\0', real->allocated);
02695 }
02698 /* tests are in dbus-string-util.c */