• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List

dbus-marshal-recursive.c

00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-marshal-recursive.c  Marshalling routines for recursive types
00003  *
00004  * Copyright (C) 2004, 2005 Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus-marshal-recursive.h"
00026 #include "dbus-marshal-basic.h"
00027 #include "dbus-signature.h"
00028 #include "dbus-internals.h"
00029 
00036 #define RECURSIVE_MARSHAL_READ_TRACE  0
00037 
00039 #define RECURSIVE_MARSHAL_WRITE_TRACE 0
00040 
00041 static void
00042 free_fixups (DBusList **fixups)
00043 {
00044   DBusList *link;
00045 
00046   link = _dbus_list_get_first_link (fixups);
00047   while (link != NULL)
00048     {
00049       DBusList *next;
00050 
00051       next = _dbus_list_get_next_link (fixups, link);
00052 
00053       dbus_free (link->data);
00054       _dbus_list_free_link (link);
00055 
00056       link = next;
00057     }
00058 
00059   *fixups = NULL;
00060 }
00061 
00062 static void
00063 apply_and_free_fixups (DBusList      **fixups,
00064                        DBusTypeReader *reader)
00065 {
00066   DBusList *link;
00067 
00068 #if RECURSIVE_MARSHAL_WRITE_TRACE
00069   if (*fixups)
00070     _dbus_verbose (" %d FIXUPS to apply\n",
00071                    _dbus_list_get_length (fixups));
00072 #endif
00073 
00074   link = _dbus_list_get_first_link (fixups);
00075   while (link != NULL)
00076     {
00077       DBusList *next;
00078 
00079       next = _dbus_list_get_next_link (fixups, link);
00080 
00081       if (reader)
00082         {
00083           DBusArrayLenFixup *f;
00084 
00085           f = link->data;
00086 
00087 #if RECURSIVE_MARSHAL_WRITE_TRACE
00088           _dbus_verbose (" applying FIXUP to reader %p at pos %d new_len = %d old len %d\n",
00089                          reader, f->len_pos_in_reader, f->new_len,
00090                          _dbus_marshal_read_uint32 (reader->value_str,
00091                                                     f->len_pos_in_reader,
00092                                                     reader->byte_order, NULL));
00093 #endif
00094 
00095           _dbus_marshal_set_uint32 ((DBusString*) reader->value_str,
00096                                     f->len_pos_in_reader,
00097                                     f->new_len,
00098                                     reader->byte_order);
00099         }
00100 
00101       dbus_free (link->data);
00102       _dbus_list_free_link (link);
00103 
00104       link = next;
00105     }
00106 
00107   *fixups = NULL;
00108 }
00109 
00113 struct DBusTypeReaderClass
00114 {
00115   const char *name;       
00116   int         id;         
00117   dbus_bool_t types_only; 
00118   void        (* recurse)          (DBusTypeReader        *sub,
00119                                     DBusTypeReader        *parent); 
00120   dbus_bool_t (* check_finished)   (const DBusTypeReader  *reader); 
00121   void        (* next)             (DBusTypeReader        *reader,
00122                                     int                    current_type); 
00123 };
00124 
00125 static int
00126 element_type_get_alignment (const DBusString *str,
00127                             int               pos)
00128 {
00129   return _dbus_type_get_alignment (_dbus_first_type_in_signature (str, pos));
00130 }
00131 
00132 static void
00133 reader_init (DBusTypeReader    *reader,
00134              int                byte_order,
00135              const DBusString  *type_str,
00136              int                type_pos,
00137              const DBusString  *value_str,
00138              int                value_pos)
00139 {
00140   reader->byte_order = byte_order;
00141   reader->finished = FALSE;
00142   reader->type_str = type_str;
00143   reader->type_pos = type_pos;
00144   reader->value_str = value_str;
00145   reader->value_pos = value_pos;
00146 }
00147 
00148 static void
00149 base_reader_recurse (DBusTypeReader *sub,
00150                      DBusTypeReader *parent)
00151 {
00152   /* point subreader at the same place as parent */
00153   reader_init (sub,
00154                parent->byte_order,
00155                parent->type_str,
00156                parent->type_pos,
00157                parent->value_str,
00158                parent->value_pos);
00159 }
00160 
00161 static void
00162 struct_or_dict_entry_types_only_reader_recurse (DBusTypeReader *sub,
00163                                                 DBusTypeReader *parent)
00164 {
00165   base_reader_recurse (sub, parent);
00166   
00167   _dbus_assert (_dbus_string_get_byte (sub->type_str,
00168                                        sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR ||
00169                 _dbus_string_get_byte (sub->type_str,
00170                                        sub->type_pos) == DBUS_DICT_ENTRY_BEGIN_CHAR);
00171 
00172   sub->type_pos += 1;
00173 }
00174 
00175 static void
00176 struct_or_dict_entry_reader_recurse (DBusTypeReader *sub,
00177                                      DBusTypeReader *parent)
00178 {
00179   struct_or_dict_entry_types_only_reader_recurse (sub, parent);
00180 
00181   /* struct and dict entry have 8 byte alignment */
00182   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
00183 }
00184 
00185 static void
00186 array_types_only_reader_recurse (DBusTypeReader *sub,
00187                                  DBusTypeReader *parent)
00188 {
00189   base_reader_recurse (sub, parent);
00190 
00191   /* point type_pos at the array element type */
00192   sub->type_pos += 1;
00193 
00194   /* Init with values likely to crash things if misused */
00195   sub->u.array.start_pos = _DBUS_INT_MAX;
00196   sub->array_len_offset = 7;
00197 }
00198 
00201 #define ARRAY_READER_LEN_POS(reader) \
00202   ((reader)->u.array.start_pos - ((int)(reader)->array_len_offset) - 4)
00203 
00204 static int
00205 array_reader_get_array_len (const DBusTypeReader *reader)
00206 {
00207   dbus_uint32_t array_len;
00208   int len_pos;
00209 
00210   len_pos = ARRAY_READER_LEN_POS (reader);
00211 
00212   _dbus_assert (_DBUS_ALIGN_VALUE (len_pos, 4) == (unsigned) len_pos);
00213   array_len = _dbus_unpack_uint32 (reader->byte_order,
00214                                    _dbus_string_get_const_data_len (reader->value_str, len_pos, 4));
00215 
00216 #if RECURSIVE_MARSHAL_READ_TRACE
00217   _dbus_verbose ("   reader %p len_pos %d array len %u len_offset %d\n",
00218                  reader, len_pos, array_len, reader->array_len_offset);
00219 #endif
00220 
00221   _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8);
00222 
00223   return array_len;
00224 }
00225 
00226 static void
00227 array_reader_recurse (DBusTypeReader *sub,
00228                       DBusTypeReader *parent)
00229 {
00230   int alignment;
00231   int len_pos;
00232 
00233   array_types_only_reader_recurse (sub, parent);
00234 
00235   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
00236 
00237   len_pos = sub->value_pos;
00238 
00239   sub->value_pos += 4; /* for the length */
00240 
00241   alignment = element_type_get_alignment (sub->type_str,
00242                                           sub->type_pos);
00243 
00244   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
00245 
00246   sub->u.array.start_pos = sub->value_pos;
00247   _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */
00248   sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4);
00249 
00250 #if RECURSIVE_MARSHAL_READ_TRACE
00251   _dbus_verbose ("    type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n",
00252                  sub,
00253                  sub->u.array.start_pos,
00254                  sub->array_len_offset,
00255                  array_reader_get_array_len (sub),
00256                  _dbus_type_to_string (_dbus_first_type_in_signature (sub->type_str,
00257                                                                 sub->type_pos)));
00258 #endif
00259 }
00260 
00261 static void
00262 variant_reader_recurse (DBusTypeReader *sub,
00263                         DBusTypeReader *parent)
00264 {
00265   int sig_len;
00266   int contained_alignment;
00267 
00268   base_reader_recurse (sub, parent);
00269 
00270   /* Variant is 1 byte sig length (without nul), signature with nul,
00271    * padding to 8-boundary, then values
00272    */
00273 
00274   sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
00275 
00276   sub->type_str = sub->value_str;
00277   sub->type_pos = sub->value_pos + 1;
00278 
00279   sub->value_pos = sub->type_pos + sig_len + 1;
00280 
00281   contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (sub->type_str,
00282                                                                            sub->type_pos));
00283   
00284   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment);
00285 
00286 #if RECURSIVE_MARSHAL_READ_TRACE
00287   _dbus_verbose ("    type reader %p variant containing '%s'\n",
00288                  sub,
00289                  _dbus_string_get_const_data_len (sub->type_str,
00290                                                   sub->type_pos, 0));
00291 #endif
00292 }
00293 
00294 static dbus_bool_t
00295 array_reader_check_finished (const DBusTypeReader *reader)
00296 {
00297   int end_pos;
00298 
00299   /* return the array element type if elements remain, and
00300    * TYPE_INVALID otherwise
00301    */
00302 
00303   end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
00304 
00305   _dbus_assert (reader->value_pos <= end_pos);
00306   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
00307 
00308   return reader->value_pos == end_pos;
00309 }
00310 
00311 static void
00312 skip_one_complete_type (const DBusString *type_str,
00313                         int              *type_pos)
00314 {
00315   _dbus_type_signature_next (_dbus_string_get_const_data (type_str),
00316                              type_pos);
00317 }
00318 
00327 void
00328 _dbus_type_signature_next (const char       *type_str,
00329                            int              *type_pos)
00330 {
00331   const unsigned char *p;
00332   const unsigned char *start;
00333 
00334   _dbus_assert (type_str != NULL);
00335   _dbus_assert (type_pos != NULL);
00336   
00337   start = type_str;
00338   p = start + *type_pos;
00339 
00340   _dbus_assert (*p != DBUS_STRUCT_END_CHAR);
00341   _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR);
00342   
00343   while (*p == DBUS_TYPE_ARRAY)
00344     ++p;
00345 
00346   _dbus_assert (*p != DBUS_STRUCT_END_CHAR);
00347   _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR);
00348   
00349   if (*p == DBUS_STRUCT_BEGIN_CHAR)
00350     {
00351       int depth;
00352 
00353       depth = 1;
00354 
00355       while (TRUE)
00356         {
00357           _dbus_assert (*p != DBUS_TYPE_INVALID);
00358 
00359           ++p;
00360 
00361           _dbus_assert (*p != DBUS_TYPE_INVALID);
00362 
00363           if (*p == DBUS_STRUCT_BEGIN_CHAR)
00364             depth += 1;
00365           else if (*p == DBUS_STRUCT_END_CHAR)
00366             {
00367               depth -= 1;
00368               if (depth == 0)
00369                 {
00370                   ++p;
00371                   break;
00372                 }
00373             }
00374         }
00375     }
00376   else if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR)
00377     {
00378       int depth;
00379 
00380       depth = 1;
00381 
00382       while (TRUE)
00383         {
00384           _dbus_assert (*p != DBUS_TYPE_INVALID);
00385 
00386           ++p;
00387 
00388           _dbus_assert (*p != DBUS_TYPE_INVALID);
00389 
00390           if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR)
00391             depth += 1;
00392           else if (*p == DBUS_DICT_ENTRY_END_CHAR)
00393             {
00394               depth -= 1;
00395               if (depth == 0)
00396                 {
00397                   ++p;
00398                   break;
00399                 }
00400             }
00401         }
00402     }
00403   else
00404     {
00405       ++p;
00406     }
00407 
00408   *type_pos = (int) (p - start);
00409 }
00410 
00411 static int
00412 find_len_of_complete_type (const DBusString *type_str,
00413                            int               type_pos)
00414 {
00415   int end;
00416 
00417   end = type_pos;
00418 
00419   skip_one_complete_type (type_str, &end);
00420 
00421   return end - type_pos;
00422 }
00423 
00424 static void
00425 base_reader_next (DBusTypeReader *reader,
00426                   int             current_type)
00427 {
00428   switch (current_type)
00429     {
00430     case DBUS_TYPE_DICT_ENTRY:
00431     case DBUS_TYPE_STRUCT:
00432     case DBUS_TYPE_VARIANT:
00433       /* Scan forward over the entire container contents */
00434       {
00435         DBusTypeReader sub;
00436 
00437         if (reader->klass->types_only && current_type == DBUS_TYPE_VARIANT)
00438           ;
00439         else
00440           {
00441             /* Recurse into the struct or variant */
00442             _dbus_type_reader_recurse (reader, &sub);
00443 
00444             /* Skip everything in this subreader */
00445             while (_dbus_type_reader_next (&sub))
00446               {
00447                 /* nothing */;
00448               }
00449           }
00450         if (!reader->klass->types_only)
00451           reader->value_pos = sub.value_pos;
00452 
00453         /* Now we are at the end of this container; for variants, the
00454          * subreader's type_pos is totally inapplicable (it's in the
00455          * value string) but we know that we increment by one past the
00456          * DBUS_TYPE_VARIANT
00457          */
00458         if (current_type == DBUS_TYPE_VARIANT)
00459           reader->type_pos += 1;
00460         else
00461           reader->type_pos = sub.type_pos;
00462       }
00463       break;
00464 
00465     case DBUS_TYPE_ARRAY:
00466       {
00467         if (!reader->klass->types_only)
00468           _dbus_marshal_skip_array (reader->value_str,
00469                                     _dbus_first_type_in_signature (reader->type_str,
00470                                                                    reader->type_pos + 1),
00471                                     reader->byte_order,
00472                                     &reader->value_pos);
00473 
00474         skip_one_complete_type (reader->type_str, &reader->type_pos);
00475       }
00476       break;
00477 
00478     default:
00479       if (!reader->klass->types_only)
00480         _dbus_marshal_skip_basic (reader->value_str,
00481                                   current_type, reader->byte_order,
00482                                   &reader->value_pos);
00483 
00484       reader->type_pos += 1;
00485       break;
00486     }
00487 }
00488 
00489 static void
00490 struct_reader_next (DBusTypeReader *reader,
00491                     int             current_type)
00492 {
00493   int t;
00494 
00495   base_reader_next (reader, current_type);
00496 
00497   /* for STRUCT containers we return FALSE at the end of the struct,
00498    * for INVALID we return FALSE at the end of the signature.
00499    * In both cases we arrange for get_current_type() to return INVALID
00500    * which is defined to happen iff we're at the end (no more next())
00501    */
00502   t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
00503   if (t == DBUS_STRUCT_END_CHAR)
00504     {
00505       reader->type_pos += 1;
00506       reader->finished = TRUE;
00507     }
00508 }
00509 
00510 static void
00511 dict_entry_reader_next (DBusTypeReader *reader,
00512                         int             current_type)
00513 {
00514   int t;
00515 
00516   base_reader_next (reader, current_type);
00517 
00518   /* for STRUCT containers we return FALSE at the end of the struct,
00519    * for INVALID we return FALSE at the end of the signature.
00520    * In both cases we arrange for get_current_type() to return INVALID
00521    * which is defined to happen iff we're at the end (no more next())
00522    */
00523   t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
00524   if (t == DBUS_DICT_ENTRY_END_CHAR)
00525     {
00526       reader->type_pos += 1;
00527       reader->finished = TRUE;
00528     }
00529 }
00530 
00531 static void
00532 array_types_only_reader_next (DBusTypeReader *reader,
00533                               int             current_type)
00534 {
00535   /* We have one "element" to be iterated over
00536    * in each array, which is its element type.
00537    * So the finished flag indicates whether we've
00538    * iterated over it yet or not.
00539    */
00540   reader->finished = TRUE;
00541 }
00542 
00543 static void
00544 array_reader_next (DBusTypeReader *reader,
00545                    int             current_type)
00546 {
00547   /* Skip one array element */
00548   int end_pos;
00549 
00550   end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
00551 
00552 #if RECURSIVE_MARSHAL_READ_TRACE
00553   _dbus_verbose ("  reader %p array next START start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",
00554                  reader,
00555                  reader->u.array.start_pos,
00556                  end_pos, reader->value_pos,
00557                  _dbus_type_to_string (current_type));
00558 #endif
00559 
00560   _dbus_assert (reader->value_pos < end_pos);
00561   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
00562 
00563   switch (_dbus_first_type_in_signature (reader->type_str,
00564                                          reader->type_pos))
00565     {
00566     case DBUS_TYPE_DICT_ENTRY:
00567     case DBUS_TYPE_STRUCT:
00568     case DBUS_TYPE_VARIANT:
00569       {
00570         DBusTypeReader sub;
00571 
00572         /* Recurse into the struct or variant */
00573         _dbus_type_reader_recurse (reader, &sub);
00574 
00575         /* Skip everything in this element */
00576         while (_dbus_type_reader_next (&sub))
00577           {
00578             /* nothing */;
00579           }
00580 
00581         /* Now we are at the end of this element */
00582         reader->value_pos = sub.value_pos;
00583       }
00584       break;
00585 
00586     case DBUS_TYPE_ARRAY:
00587       {
00588         _dbus_marshal_skip_array (reader->value_str,
00589                                   _dbus_first_type_in_signature (reader->type_str,
00590                                                            reader->type_pos + 1),
00591                                   reader->byte_order,
00592                                   &reader->value_pos);
00593       }
00594       break;
00595 
00596     default:
00597       {
00598         _dbus_marshal_skip_basic (reader->value_str,
00599                                   current_type, reader->byte_order,
00600                                   &reader->value_pos);
00601       }
00602       break;
00603     }
00604 
00605 #if RECURSIVE_MARSHAL_READ_TRACE
00606   _dbus_verbose ("  reader %p array next END start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",
00607                  reader,
00608                  reader->u.array.start_pos,
00609                  end_pos, reader->value_pos,
00610                  _dbus_type_to_string (current_type));
00611 #endif
00612 
00613   _dbus_assert (reader->value_pos <= end_pos);
00614 
00615   if (reader->value_pos == end_pos)
00616     {
00617       skip_one_complete_type (reader->type_str,
00618                               &reader->type_pos);
00619     }
00620 }
00621 
00622 static const DBusTypeReaderClass body_reader_class = {
00623   "body", 0,
00624   FALSE,
00625   NULL, /* body is always toplevel, so doesn't get recursed into */
00626   NULL,
00627   base_reader_next
00628 };
00629 
00630 static const DBusTypeReaderClass body_types_only_reader_class = {
00631   "body types", 1,
00632   TRUE,
00633   NULL, /* body is always toplevel, so doesn't get recursed into */
00634   NULL,
00635   base_reader_next
00636 };
00637 
00638 static const DBusTypeReaderClass struct_reader_class = {
00639   "struct", 2,
00640   FALSE,
00641   struct_or_dict_entry_reader_recurse,
00642   NULL,
00643   struct_reader_next
00644 };
00645 
00646 static const DBusTypeReaderClass struct_types_only_reader_class = {
00647   "struct types", 3,
00648   TRUE,
00649   struct_or_dict_entry_types_only_reader_recurse,
00650   NULL,
00651   struct_reader_next
00652 };
00653 
00654 static const DBusTypeReaderClass dict_entry_reader_class = {
00655   "dict_entry", 4,
00656   FALSE,
00657   struct_or_dict_entry_reader_recurse,
00658   NULL,
00659   dict_entry_reader_next
00660 };
00661 
00662 static const DBusTypeReaderClass dict_entry_types_only_reader_class = {
00663   "dict_entry types", 5,
00664   TRUE,
00665   struct_or_dict_entry_types_only_reader_recurse,
00666   NULL,
00667   dict_entry_reader_next
00668 };
00669 
00670 static const DBusTypeReaderClass array_reader_class = {
00671   "array", 6,
00672   FALSE,
00673   array_reader_recurse,
00674   array_reader_check_finished,
00675   array_reader_next
00676 };
00677 
00678 static const DBusTypeReaderClass array_types_only_reader_class = {
00679   "array types", 7,
00680   TRUE,
00681   array_types_only_reader_recurse,
00682   NULL,
00683   array_types_only_reader_next
00684 };
00685 
00686 static const DBusTypeReaderClass variant_reader_class = {
00687   "variant", 8,
00688   FALSE,
00689   variant_reader_recurse,
00690   NULL,
00691   base_reader_next
00692 };
00693 
00694 #ifndef DBUS_DISABLE_ASSERT
00695 static const DBusTypeReaderClass * const
00696 all_reader_classes[] = {
00697   &body_reader_class,
00698   &body_types_only_reader_class,
00699   &struct_reader_class,
00700   &struct_types_only_reader_class,
00701   &dict_entry_reader_class,
00702   &dict_entry_types_only_reader_class,
00703   &array_reader_class,
00704   &array_types_only_reader_class,
00705   &variant_reader_class
00706 };
00707 #endif
00708 
00719 void
00720 _dbus_type_reader_init (DBusTypeReader    *reader,
00721                         int                byte_order,
00722                         const DBusString  *type_str,
00723                         int                type_pos,
00724                         const DBusString  *value_str,
00725                         int                value_pos)
00726 {
00727   reader->klass = &body_reader_class;
00728 
00729   reader_init (reader, byte_order, type_str, type_pos,
00730                value_str, value_pos);
00731 
00732 #if RECURSIVE_MARSHAL_READ_TRACE
00733   _dbus_verbose ("  type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
00734                  reader, reader->type_pos, reader->value_pos,
00735                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
00736 #endif
00737 }
00738 
00747 void
00748 _dbus_type_reader_init_types_only (DBusTypeReader    *reader,
00749                                    const DBusString  *type_str,
00750                                    int                type_pos)
00751 {
00752   reader->klass = &body_types_only_reader_class;
00753 
00754   reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
00755                type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
00756 
00757 #if RECURSIVE_MARSHAL_READ_TRACE
00758   _dbus_verbose ("  type reader %p init types only type_pos = %d remaining sig '%s'\n",
00759                  reader, reader->type_pos,
00760                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
00761 #endif
00762 }
00763 
00772 int
00773 _dbus_type_reader_get_current_type (const DBusTypeReader *reader)
00774 {
00775   int t;
00776 
00777   if (reader->finished ||
00778       (reader->klass->check_finished &&
00779        (* reader->klass->check_finished) (reader)))
00780     t = DBUS_TYPE_INVALID;
00781   else
00782     t = _dbus_first_type_in_signature (reader->type_str,
00783                                        reader->type_pos);
00784 
00785   _dbus_assert (t != DBUS_STRUCT_END_CHAR);
00786   _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
00787   _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR);
00788   _dbus_assert (t != DBUS_DICT_ENTRY_BEGIN_CHAR);
00789   
00790 #if 0
00791   _dbus_verbose ("  type reader %p current type_pos = %d type = %s\n",
00792                  reader, reader->type_pos,
00793                  _dbus_type_to_string (t));
00794 #endif
00795 
00796   return t;
00797 }
00798 
00807 int
00808 _dbus_type_reader_get_element_type (const DBusTypeReader  *reader)
00809 {
00810   int element_type;
00811 
00812   _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
00813 
00814   element_type = _dbus_first_type_in_signature (reader->type_str,
00815                                           reader->type_pos + 1);
00816 
00817   return element_type;
00818 }
00819 
00824 int
00825 _dbus_type_reader_get_value_pos (const DBusTypeReader  *reader)
00826 {
00827   return reader->value_pos;
00828 }
00829 
00839 void
00840 _dbus_type_reader_read_raw (const DBusTypeReader  *reader,
00841                             const unsigned char  **value_location)
00842 {
00843   _dbus_assert (!reader->klass->types_only);
00844 
00845   *value_location = _dbus_string_get_const_data_len (reader->value_str,
00846                                                      reader->value_pos,
00847                                                      0);
00848 }
00849 
00856 void
00857 _dbus_type_reader_read_basic (const DBusTypeReader    *reader,
00858                               void                    *value)
00859 {
00860   int t;
00861 
00862   _dbus_assert (!reader->klass->types_only);
00863 
00864   t = _dbus_type_reader_get_current_type (reader);
00865 
00866   _dbus_marshal_read_basic (reader->value_str,
00867                             reader->value_pos,
00868                             t, value,
00869                             reader->byte_order,
00870                             NULL);
00871 
00872 
00873 #if RECURSIVE_MARSHAL_READ_TRACE
00874   _dbus_verbose ("  type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",
00875                  reader, reader->type_pos, reader->value_pos,
00876                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
00877 #endif
00878 }
00879 
00886 int
00887 _dbus_type_reader_get_array_length (const DBusTypeReader  *reader)
00888 {
00889   _dbus_assert (!reader->klass->types_only);
00890   _dbus_assert (reader->klass == &array_reader_class);
00891 
00892   return array_reader_get_array_len (reader);
00893 }
00894 
00910 void
00911 _dbus_type_reader_read_fixed_multi (const DBusTypeReader  *reader,
00912                                     void                  *value,
00913                                     int                   *n_elements)
00914 {
00915   int element_type;
00916   int end_pos;
00917   int remaining_len;
00918   int alignment;
00919   int total_len;
00920 
00921   _dbus_assert (!reader->klass->types_only);
00922   _dbus_assert (reader->klass == &array_reader_class);
00923 
00924   element_type = _dbus_first_type_in_signature (reader->type_str,
00925                                                 reader->type_pos);
00926 
00927   _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */
00928   _dbus_assert (dbus_type_is_fixed (element_type));
00929 
00930   alignment = _dbus_type_get_alignment (element_type);
00931 
00932   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
00933 
00934   total_len = array_reader_get_array_len (reader);
00935   end_pos = reader->u.array.start_pos + total_len;
00936   remaining_len = end_pos - reader->value_pos;
00937 
00938 #if RECURSIVE_MARSHAL_READ_TRACE
00939   _dbus_verbose ("end_pos %d total_len %d remaining_len %d value_pos %d\n",
00940                  end_pos, total_len, remaining_len, reader->value_pos);
00941 #endif
00942 
00943   _dbus_assert (remaining_len <= total_len);
00944 
00945   if (remaining_len == 0)
00946     *(const DBusBasicValue**) value = NULL;
00947   else
00948     *(const DBusBasicValue**) value =
00949       (void*) _dbus_string_get_const_data_len (reader->value_str,
00950                                                reader->value_pos,
00951                                                remaining_len);
00952 
00953   *n_elements = remaining_len / alignment;
00954   _dbus_assert ((remaining_len % alignment) == 0);
00955 
00956 #if RECURSIVE_MARSHAL_READ_TRACE
00957   _dbus_verbose ("  type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n",
00958                  reader, reader->type_pos, reader->value_pos,
00959                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
00960 #endif
00961 }
00962 
00975 void
00976 _dbus_type_reader_recurse (DBusTypeReader *reader,
00977                            DBusTypeReader *sub)
00978 {
00979   int t;
00980 
00981   t = _dbus_first_type_in_signature (reader->type_str, reader->type_pos);
00982 
00983   switch (t)
00984     {
00985     case DBUS_TYPE_STRUCT:
00986       if (reader->klass->types_only)
00987         sub->klass = &struct_types_only_reader_class;
00988       else
00989         sub->klass = &struct_reader_class;
00990       break;
00991     case DBUS_TYPE_DICT_ENTRY:
00992       if (reader->klass->types_only)
00993         sub->klass = &dict_entry_types_only_reader_class;
00994       else
00995         sub->klass = &dict_entry_reader_class;
00996       break;
00997     case DBUS_TYPE_ARRAY:
00998       if (reader->klass->types_only)
00999         sub->klass = &array_types_only_reader_class;
01000       else
01001         sub->klass = &array_reader_class;
01002       break;
01003     case DBUS_TYPE_VARIANT:
01004       if (reader->klass->types_only)
01005         _dbus_assert_not_reached ("can't recurse into variant typecode");
01006       else
01007         sub->klass = &variant_reader_class;
01008       break;
01009     default:
01010       _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
01011 #ifndef DBUS_DISABLE_CHECKS
01012       if (t == DBUS_TYPE_INVALID)
01013         _dbus_warn_check_failed ("You can't recurse into an empty array or off the end of a message body\n");
01014 #endif /* DBUS_DISABLE_CHECKS */
01015 
01016       _dbus_assert_not_reached ("don't yet handle recursing into this type");
01017     }
01018 
01019   _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]);
01020 
01021   (* sub->klass->recurse) (sub, reader);
01022 
01023 #if RECURSIVE_MARSHAL_READ_TRACE
01024   _dbus_verbose ("  type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
01025                  sub, sub->type_pos, sub->value_pos,
01026                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
01027 #endif
01028 }
01029 
01038 dbus_bool_t
01039 _dbus_type_reader_next (DBusTypeReader *reader)
01040 {
01041   int t;
01042 
01043   t = _dbus_type_reader_get_current_type (reader);
01044 
01045 #if RECURSIVE_MARSHAL_READ_TRACE
01046   _dbus_verbose ("  type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
01047                  reader, reader->type_pos, reader->value_pos,
01048                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
01049                  _dbus_type_to_string (t));
01050 #endif
01051 
01052   if (t == DBUS_TYPE_INVALID)
01053     return FALSE;
01054 
01055   (* reader->klass->next) (reader, t);
01056 
01057 #if RECURSIVE_MARSHAL_READ_TRACE
01058   _dbus_verbose ("  type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
01059                  reader, reader->type_pos, reader->value_pos,
01060                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
01061                  _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
01062 #endif
01063 
01064   return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
01065 }
01066 
01078 dbus_bool_t
01079 _dbus_type_reader_has_next (const DBusTypeReader *reader)
01080 {
01081   /* Not efficient but works for now. */
01082   DBusTypeReader copy;
01083 
01084   copy = *reader;
01085   return _dbus_type_reader_next (&copy);
01086 }
01087 
01109 void
01110 _dbus_type_reader_get_signature (const DBusTypeReader  *reader,
01111                                  const DBusString     **str_p,
01112                                  int                   *start_p,
01113                                  int                   *len_p)
01114 {
01115   *str_p = reader->type_str;
01116   *start_p = reader->type_pos;
01117   *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);
01118 }
01119 
01120 typedef struct
01121 {
01122   DBusString replacement; 
01123   int padding;            
01124 } ReplacementBlock;
01125 
01126 static dbus_bool_t
01127 replacement_block_init (ReplacementBlock *block,
01128                         DBusTypeReader   *reader)
01129 {
01130   if (!_dbus_string_init (&block->replacement))
01131     return FALSE;
01132 
01133   /* % 8 is the padding to have the same align properties in
01134    * our replacement string as we do at the position being replaced
01135    */
01136   block->padding = reader->value_pos % 8;
01137 
01138   if (!_dbus_string_lengthen (&block->replacement, block->padding))
01139     goto oom;
01140 
01141   return TRUE;
01142 
01143  oom:
01144   _dbus_string_free (&block->replacement);
01145   return FALSE;
01146 }
01147 
01148 static dbus_bool_t
01149 replacement_block_replace (ReplacementBlock     *block,
01150                            DBusTypeReader       *reader,
01151                            const DBusTypeReader *realign_root)
01152 {
01153   DBusTypeWriter writer;
01154   DBusTypeReader realign_reader;
01155   DBusList *fixups;
01156   int orig_len;
01157 
01158   _dbus_assert (realign_root != NULL);
01159 
01160   orig_len = _dbus_string_get_length (&block->replacement);
01161 
01162   realign_reader = *realign_root;
01163 
01164 #if RECURSIVE_MARSHAL_WRITE_TRACE
01165   _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n",
01166                  &writer, _dbus_string_get_length (&block->replacement));
01167 #endif
01168   _dbus_type_writer_init_values_only (&writer,
01169                                       realign_reader.byte_order,
01170                                       realign_reader.type_str,
01171                                       realign_reader.type_pos,
01172                                       &block->replacement,
01173                                       _dbus_string_get_length (&block->replacement));
01174 
01175   _dbus_assert (realign_reader.value_pos <= reader->value_pos);
01176 
01177 #if RECURSIVE_MARSHAL_WRITE_TRACE
01178   _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n",
01179                  realign_reader.value_pos, &writer, reader->value_pos);
01180 #endif
01181   fixups = NULL;
01182   if (!_dbus_type_writer_write_reader_partial (&writer,
01183                                                &realign_reader,
01184                                                reader,
01185                                                block->padding,
01186                                                _dbus_string_get_length (&block->replacement) - block->padding,
01187                                                &fixups))
01188     goto oom;
01189 
01190 #if RECURSIVE_MARSHAL_WRITE_TRACE
01191   _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding,
01192                  _dbus_string_get_length (&block->replacement) - block->padding);
01193   _dbus_verbose_bytes_of_string (&block->replacement, block->padding,
01194                                  _dbus_string_get_length (&block->replacement) - block->padding);
01195   _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n",
01196                  reader->value_pos, reader->value_pos % 8,
01197                  realign_reader.value_pos - reader->value_pos,
01198                  realign_reader.value_pos);
01199   _dbus_verbose_bytes_of_string (reader->value_str,
01200                                  reader->value_pos,
01201                                  realign_reader.value_pos - reader->value_pos);
01202 #endif
01203 
01204   /* Move the replacement into position
01205    * (realign_reader should now be at the end of the block to be replaced)
01206    */
01207   if (!_dbus_string_replace_len (&block->replacement, block->padding,
01208                                  _dbus_string_get_length (&block->replacement) - block->padding,
01209                                  (DBusString*) reader->value_str,
01210                                  reader->value_pos,
01211                                  realign_reader.value_pos - reader->value_pos))
01212     goto oom;
01213 
01214   /* Process our fixups now that we can't have an OOM error */
01215   apply_and_free_fixups (&fixups, reader);
01216 
01217   return TRUE;
01218 
01219  oom:
01220   _dbus_string_set_length (&block->replacement, orig_len);
01221   free_fixups (&fixups);
01222   return FALSE;
01223 }
01224 
01225 static void
01226 replacement_block_free (ReplacementBlock *block)
01227 {
01228   _dbus_string_free (&block->replacement);
01229 }
01230 
01231 /* In the variable-length case, we have to fix alignment after we insert.
01232  * The strategy is as follows:
01233  *
01234  *  - pad a new string to have the same alignment as the
01235  *    start of the current basic value
01236  *  - write the new basic value
01237  *  - copy from the original reader to the new string,
01238  *    which will fix the alignment of types following
01239  *    the new value
01240  *    - this copy has to start at realign_root,
01241  *      but not really write anything until it
01242  *      passes the value being set
01243  *    - as an optimization, we can stop copying
01244  *      when the source and dest values are both
01245  *      on an 8-boundary, since we know all following
01246  *      padding and alignment will be identical
01247  *  - copy the new string back to the original
01248  *    string, replacing the relevant part of the
01249  *    original string
01250  *  - now any arrays in the original string that
01251  *    contained the replaced string may have the
01252  *    wrong length; so we have to fix that
01253  */
01254 static dbus_bool_t
01255 reader_set_basic_variable_length (DBusTypeReader       *reader,
01256                                   int                   current_type,
01257                                   const void           *value,
01258                                   const DBusTypeReader *realign_root)
01259 {
01260   dbus_bool_t retval;
01261   ReplacementBlock block;
01262   DBusTypeWriter writer;
01263 
01264   _dbus_assert (realign_root != NULL);
01265 
01266   retval = FALSE;
01267 
01268   if (!replacement_block_init (&block, reader))
01269     return FALSE;
01270 
01271   /* Write the new basic value */
01272 #if RECURSIVE_MARSHAL_WRITE_TRACE
01273   _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n",
01274                  &writer, _dbus_string_get_length (&block.replacement));
01275 #endif
01276   _dbus_type_writer_init_values_only (&writer,
01277                                       reader->byte_order,
01278                                       reader->type_str,
01279                                       reader->type_pos,
01280                                       &block.replacement,
01281                                       _dbus_string_get_length (&block.replacement));
01282 #if RECURSIVE_MARSHAL_WRITE_TRACE
01283   _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer);
01284 #endif
01285   if (!_dbus_type_writer_write_basic (&writer, current_type, value))
01286     goto out;
01287 
01288   if (!replacement_block_replace (&block,
01289                                   reader,
01290                                   realign_root))
01291     goto out;
01292 
01293   retval = TRUE;
01294 
01295  out:
01296   replacement_block_free (&block);
01297   return retval;
01298 }
01299 
01300 static void
01301 reader_set_basic_fixed_length (DBusTypeReader *reader,
01302                                int             current_type,
01303                                const void     *value)
01304 {
01305   _dbus_marshal_set_basic ((DBusString*) reader->value_str,
01306                            reader->value_pos,
01307                            current_type,
01308                            value,
01309                            reader->byte_order,
01310                            NULL, NULL);
01311 }
01312 
01347 dbus_bool_t
01348 _dbus_type_reader_set_basic (DBusTypeReader       *reader,
01349                              const void           *value,
01350                              const DBusTypeReader *realign_root)
01351 {
01352   int current_type;
01353 
01354   _dbus_assert (!reader->klass->types_only);
01355   _dbus_assert (reader->value_str == realign_root->value_str);
01356   _dbus_assert (reader->value_pos >= realign_root->value_pos);
01357 
01358   current_type = _dbus_type_reader_get_current_type (reader);
01359 
01360 #if RECURSIVE_MARSHAL_WRITE_TRACE
01361   _dbus_verbose ("  SET BASIC type reader %p type_pos = %d value_pos = %d remaining sig '%s' realign_root = %p with value_pos %d current_type = %s\n",
01362                  reader, reader->type_pos, reader->value_pos,
01363                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
01364                  realign_root,
01365                  realign_root ? realign_root->value_pos : -1,
01366                  _dbus_type_to_string (current_type));
01367   _dbus_verbose_bytes_of_string (realign_root->value_str, realign_root->value_pos,
01368                                  _dbus_string_get_length (realign_root->value_str) -
01369                                  realign_root->value_pos);
01370 #endif
01371 
01372   _dbus_assert (dbus_type_is_basic (current_type));
01373 
01374   if (dbus_type_is_fixed (current_type))
01375     {
01376       reader_set_basic_fixed_length (reader, current_type, value);
01377       return TRUE;
01378     }
01379   else
01380     {
01381       _dbus_assert (realign_root != NULL);
01382       return reader_set_basic_variable_length (reader, current_type,
01383                                                value, realign_root);
01384     }
01385 }
01386 
01404 dbus_bool_t
01405 _dbus_type_reader_delete (DBusTypeReader        *reader,
01406                           const DBusTypeReader  *realign_root)
01407 {
01408   dbus_bool_t retval;
01409   ReplacementBlock block;
01410 
01411   _dbus_assert (realign_root != NULL);
01412   _dbus_assert (reader->klass == &array_reader_class);
01413 
01414   retval = FALSE;
01415 
01416   if (!replacement_block_init (&block, reader))
01417     return FALSE;
01418 
01419   if (!replacement_block_replace (&block,
01420                                   reader,
01421                                   realign_root))
01422     goto out;
01423 
01424   retval = TRUE;
01425 
01426  out:
01427   replacement_block_free (&block);
01428   return retval;
01429 }
01430 
01439 dbus_bool_t
01440 _dbus_type_reader_greater_than (const DBusTypeReader  *lhs,
01441                                 const DBusTypeReader  *rhs)
01442 {
01443   _dbus_assert (lhs->value_str == rhs->value_str);
01444 
01445   return lhs->value_pos > rhs->value_pos;
01446 }
01447 
01448 /*
01449  *
01450  *
01451  *         DBusTypeWriter
01452  *
01453  *
01454  *
01455  */
01456 
01477 void
01478 _dbus_type_writer_init (DBusTypeWriter *writer,
01479                         int             byte_order,
01480                         DBusString     *type_str,
01481                         int             type_pos,
01482                         DBusString     *value_str,
01483                         int             value_pos)
01484 {
01485   writer->byte_order = byte_order;
01486   writer->type_str = type_str;
01487   writer->type_pos = type_pos;
01488   writer->value_str = value_str;
01489   writer->value_pos = value_pos;
01490   writer->container_type = DBUS_TYPE_INVALID;
01491   writer->type_pos_is_expectation = FALSE;
01492   writer->enabled = TRUE;
01493 
01494 #if RECURSIVE_MARSHAL_WRITE_TRACE
01495   _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
01496                  writer->type_str ?
01497                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
01498                  "unknown");
01499 #endif
01500 }
01501 
01512 void
01513 _dbus_type_writer_init_types_delayed (DBusTypeWriter *writer,
01514                                       int             byte_order,
01515                                       DBusString     *value_str,
01516                                       int             value_pos)
01517 {
01518   _dbus_type_writer_init (writer, byte_order,
01519                           NULL, 0, value_str, value_pos);
01520 }
01521 
01530 void
01531 _dbus_type_writer_add_types (DBusTypeWriter *writer,
01532                              DBusString     *type_str,
01533                              int             type_pos)
01534 {
01535   if (writer->type_str == NULL) /* keeps us from using this as setter */
01536     {
01537       writer->type_str = type_str;
01538       writer->type_pos = type_pos;
01539     }
01540 }
01541 
01547 void
01548 _dbus_type_writer_remove_types (DBusTypeWriter *writer)
01549 {
01550   writer->type_str = NULL;
01551   writer->type_pos = -1;
01552 }
01553 
01568 void
01569 _dbus_type_writer_init_values_only (DBusTypeWriter   *writer,
01570                                     int               byte_order,
01571                                     const DBusString *type_str,
01572                                     int               type_pos,
01573                                     DBusString       *value_str,
01574                                     int               value_pos)
01575 {
01576   _dbus_type_writer_init (writer, byte_order,
01577                           (DBusString*)type_str, type_pos,
01578                           value_str, value_pos);
01579 
01580   writer->type_pos_is_expectation = TRUE;
01581 }
01582 
01583 static dbus_bool_t
01584 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
01585                                            int             type,
01586                                            const void     *value)
01587 {
01588   if (writer->enabled)
01589     return _dbus_marshal_write_basic (writer->value_str,
01590                                       writer->value_pos,
01591                                       type,
01592                                       value,
01593                                       writer->byte_order,
01594                                       &writer->value_pos);
01595   else
01596     return TRUE;
01597 }
01598 
01599 /* If our parent is an array, things are a little bit complicated.
01600  *
01601  * The parent must have a complete element type, such as
01602  * "i" or "aai" or "(ii)" or "a(ii)". There can't be
01603  * unclosed parens, or an "a" with no following type.
01604  *
01605  * To recurse, the only allowed operation is to recurse into the
01606  * first type in the element type. So for "i" you can't recurse, for
01607  * "ai" you can recurse into the array, for "(ii)" you can recurse
01608  * into the struct.
01609  *
01610  * If you recurse into the array for "ai", then you must specify
01611  * "i" for the element type of the array you recurse into.
01612  *
01613  * While inside an array at any level, we need to avoid writing to
01614  * type_str, since the type only appears once for the whole array,
01615  * it does not appear for each array element.
01616  *
01617  * While inside an array type_pos points to the expected next
01618  * typecode, rather than the next place we could write a typecode.
01619  */
01620 static void
01621 writer_recurse_init_and_check (DBusTypeWriter *writer,
01622                                int             container_type,
01623                                DBusTypeWriter *sub)
01624 {
01625   _dbus_type_writer_init (sub,
01626                           writer->byte_order,
01627                           writer->type_str,
01628                           writer->type_pos,
01629                           writer->value_str,
01630                           writer->value_pos);
01631 
01632   sub->container_type = container_type;
01633 
01634   if (writer->type_pos_is_expectation ||
01635       (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
01636     sub->type_pos_is_expectation = TRUE;
01637   else
01638     sub->type_pos_is_expectation = FALSE;
01639 
01640   sub->enabled = writer->enabled;
01641 
01642 #ifndef DBUS_DISABLE_CHECKS
01643   if (writer->type_pos_is_expectation && writer->type_str)
01644     {
01645       int expected;
01646 
01647       expected = _dbus_first_type_in_signature (writer->type_str, writer->type_pos);
01648 
01649       if (expected != sub->container_type)
01650         {
01651           if (expected != DBUS_TYPE_INVALID)
01652             _dbus_warn_check_failed ("Writing an element of type %s, but the expected type here is %s\n"
01653                                      "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
01654                                      _dbus_type_to_string (sub->container_type),
01655                                      _dbus_type_to_string (expected),
01656                                      _dbus_string_get_const_data (writer->type_str), writer->type_pos);
01657           else
01658             _dbus_warn_check_failed ("Writing an element of type %s, but no value is expected here\n"
01659                                      "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
01660                                      _dbus_type_to_string (sub->container_type),
01661                                      _dbus_string_get_const_data (writer->type_str), writer->type_pos);
01662           
01663           _dbus_assert_not_reached ("bad array element or variant content written");
01664         }
01665     }
01666 #endif /* DBUS_DISABLE_CHECKS */
01667 
01668 #if RECURSIVE_MARSHAL_WRITE_TRACE
01669   _dbus_verbose ("  type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n",
01670                  writer,
01671                  _dbus_type_to_string (writer->container_type),
01672                  writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
01673                  writer->type_str ?
01674                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
01675                  "unknown",
01676                  writer->enabled);
01677   _dbus_verbose ("  type writer %p recurse sub %s   type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
01678                  sub,
01679                  _dbus_type_to_string (sub->container_type),
01680                  sub->type_pos, sub->value_pos,
01681                  sub->type_pos_is_expectation,
01682                  sub->enabled);
01683 #endif
01684 }
01685 
01686 static dbus_bool_t
01687 write_or_verify_typecode (DBusTypeWriter *writer,
01688                           int             typecode)
01689 {
01690   /* A subwriter inside an array or variant will have type_pos
01691    * pointing to the expected typecode; a writer not inside an array
01692    * or variant has type_pos pointing to the next place to insert a
01693    * typecode.
01694    */
01695 #if RECURSIVE_MARSHAL_WRITE_TRACE
01696   _dbus_verbose ("  type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n",
01697                  writer, writer->type_pos,
01698                  writer->type_str ?
01699                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
01700                  "unknown",
01701                  writer->enabled);
01702 #endif
01703 
01704   if (writer->type_str == NULL)
01705     return TRUE;
01706 
01707   if (writer->type_pos_is_expectation)
01708     {
01709 #ifndef DBUS_DISABLE_CHECKS
01710       {
01711         int expected;
01712 
01713         expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
01714 
01715         if (expected != typecode)
01716           {
01717             if (expected != DBUS_TYPE_INVALID)
01718               _dbus_warn_check_failed ("Array or variant type requires that type %s be written, but %s was written.\n"
01719                                        "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
01720                                        _dbus_type_to_string (expected), _dbus_type_to_string (typecode),
01721                                        _dbus_string_get_const_data (writer->type_str), writer->type_pos);
01722             else
01723               _dbus_warn_check_failed ("Array or variant type wasn't expecting any more values to be written into it, but a value %s was written.\n"
01724                                        "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
01725                                        _dbus_type_to_string (typecode),
01726                                        _dbus_string_get_const_data (writer->type_str), writer->type_pos);
01727             _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
01728           }
01729       }
01730 #endif /* DBUS_DISABLE_CHECKS */
01731 
01732       /* if immediately inside an array we'd always be appending an element,
01733        * so the expected type doesn't change; if inside a struct or something
01734        * below an array, we need to move through said struct or something.
01735        */
01736       if (writer->container_type != DBUS_TYPE_ARRAY)
01737         writer->type_pos += 1;
01738     }
01739   else
01740     {
01741       if (!_dbus_string_insert_byte (writer->type_str,
01742                                      writer->type_pos,
01743                                      typecode))
01744         return FALSE;
01745 
01746       writer->type_pos += 1;
01747     }
01748 
01749 #if RECURSIVE_MARSHAL_WRITE_TRACE
01750   _dbus_verbose ("  type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
01751                  writer, writer->type_pos,
01752                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
01753 #endif
01754 
01755   return TRUE;
01756 }
01757 
01758 static dbus_bool_t
01759 writer_recurse_struct_or_dict_entry (DBusTypeWriter   *writer,
01760                                      int               begin_char,
01761                                      const DBusString *contained_type,
01762                                      int               contained_type_start,
01763                                      int               contained_type_len,
01764                                      DBusTypeWriter   *sub)
01765 {
01766   /* FIXME right now contained_type is ignored; we could probably
01767    * almost trivially fix the code so if it's present we
01768    * write it out and then set type_pos_is_expectation
01769    */
01770 
01771   /* Ensure that we'll be able to add alignment padding and the typecode */
01772   if (writer->enabled)
01773     {
01774       if (!_dbus_string_alloc_space (sub->value_str, 8))
01775         return FALSE;
01776     }
01777 
01778   if (!write_or_verify_typecode (sub, begin_char))
01779     _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
01780 
01781   if (writer->enabled)
01782     {
01783       if (!_dbus_string_insert_bytes (sub->value_str,
01784                                       sub->value_pos,
01785                                       _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
01786                                       '\0'))
01787         _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
01788       sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
01789     }
01790 
01791   return TRUE;
01792 }
01793 
01794 
01795 static dbus_bool_t
01796 writer_recurse_array (DBusTypeWriter   *writer,
01797                       const DBusString *contained_type,
01798                       int               contained_type_start,
01799                       int               contained_type_len,
01800                       DBusTypeWriter   *sub,
01801                       dbus_bool_t       is_array_append)
01802 {
01803   dbus_uint32_t value = 0;
01804   int alignment;
01805   int aligned;
01806 
01807 #ifndef DBUS_DISABLE_CHECKS
01808   if (writer->container_type == DBUS_TYPE_ARRAY &&
01809       writer->type_str)
01810     {
01811       if (!_dbus_string_equal_substring (contained_type,
01812                                          contained_type_start,
01813                                          contained_type_len,
01814                                          writer->type_str,
01815                                          writer->u.array.element_type_pos + 1))
01816         {
01817           _dbus_warn_check_failed ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
01818                                    _dbus_string_get_const_data_len (contained_type,
01819                                                                     contained_type_start,
01820                                                                     contained_type_len));
01821           _dbus_assert_not_reached ("incompatible type for child array");
01822         }
01823     }
01824 #endif /* DBUS_DISABLE_CHECKS */
01825 
01826   if (writer->enabled && !is_array_append)
01827     {
01828       /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding
01829        * before array values
01830        */
01831       if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4))
01832         return FALSE;
01833     }
01834 
01835   if (writer->type_str != NULL)
01836     {
01837       sub->type_pos += 1; /* move to point to the element type, since type_pos
01838                            * should be the expected type for further writes
01839                            */
01840       sub->u.array.element_type_pos = sub->type_pos;
01841     }
01842 
01843   if (!writer->type_pos_is_expectation)
01844     {
01845       /* sub is a toplevel/outermost array so we need to write the type data */
01846 
01847       /* alloc space for array typecode, element signature */
01848       if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len))
01849         return FALSE;
01850 
01851       if (!_dbus_string_insert_byte (writer->type_str,
01852                                      writer->type_pos,
01853                                      DBUS_TYPE_ARRAY))
01854         _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
01855 
01856       if (!_dbus_string_copy_len (contained_type,
01857                                   contained_type_start, contained_type_len,
01858                                   sub->type_str,
01859                                   sub->u.array.element_type_pos))
01860         _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
01861     }
01862 
01863   if (writer->type_str != NULL)
01864     {
01865       /* If the parent is an array, we hold type_pos pointing at the array element type;
01866        * otherwise advance it to reflect the array value we just recursed into
01867        */
01868       if (writer->container_type != DBUS_TYPE_ARRAY)
01869         writer->type_pos += 1 + contained_type_len;
01870       else
01871         _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
01872     }
01873 
01874   if (writer->enabled)
01875     {
01876       /* Write (or jump over, if is_array_append) the length */
01877       sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
01878 
01879       if (is_array_append)
01880         {
01881           sub->value_pos += 4;
01882         }
01883       else
01884         {
01885           if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
01886                                                           &value))
01887             _dbus_assert_not_reached ("should not have failed to insert array len");
01888         }
01889 
01890       _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
01891 
01892       /* Write alignment padding for array elements
01893        * Note that we write the padding *even for empty arrays*
01894        * to avoid wonky special cases
01895        */
01896       alignment = element_type_get_alignment (contained_type, contained_type_start);
01897 
01898       aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
01899       if (aligned != sub->value_pos)
01900         {
01901           if (!is_array_append)
01902             {
01903               if (!_dbus_string_insert_bytes (sub->value_str,
01904                                               sub->value_pos,
01905                                               aligned - sub->value_pos,
01906                                               '\0'))
01907                 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
01908             }
01909 
01910           sub->value_pos = aligned;
01911         }
01912 
01913       sub->u.array.start_pos = sub->value_pos;
01914 
01915       if (is_array_append)
01916         {
01917           dbus_uint32_t len;
01918 
01919           _dbus_assert (_DBUS_ALIGN_VALUE (sub->u.array.len_pos, 4) ==
01920                         (unsigned) sub->u.array.len_pos);
01921           len = _dbus_unpack_uint32 (sub->byte_order,
01922                                      _dbus_string_get_const_data_len (sub->value_str,
01923                                                                       sub->u.array.len_pos,
01924                                                                       4));
01925 
01926           sub->value_pos += len;
01927         }
01928     }
01929   else
01930     {
01931       /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */
01932       sub->u.array.len_pos = -1;
01933       sub->u.array.start_pos = sub->value_pos;
01934     }
01935 
01936   _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
01937   _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos);
01938 
01939 #if RECURSIVE_MARSHAL_WRITE_TRACE
01940       _dbus_verbose ("  type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub,
01941                      sub->type_str ?
01942                      _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) :
01943                      "unknown",
01944                      sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos);
01945 #endif
01946 
01947   return TRUE;
01948 }
01949 
01950 /* Variant value will normally have:
01951  *   1 byte signature length not including nul
01952  *   signature typecodes (nul terminated)
01953  *   padding to alignment of contained type
01954  *   body according to signature
01955  *
01956  * The signature string can only have a single type
01957  * in it but that type may be complex/recursive.
01958  *
01959  * So a typical variant type with the integer 3 will have these
01960  * octets:
01961  *   0x1 'i' '\0' [1 byte padding to alignment boundary] 0x0 0x0 0x0 0x3
01962  *
01963  * The main world of hurt for writing out a variant is that the type
01964  * string is the same string as the value string. Which means
01965  * inserting to the type string will move the value_pos; and it means
01966  * that inserting to the type string could break type alignment.
01967  */
01968 static dbus_bool_t
01969 writer_recurse_variant (DBusTypeWriter   *writer,
01970                         const DBusString *contained_type,
01971                         int               contained_type_start,
01972                         int               contained_type_len,
01973                         DBusTypeWriter   *sub)
01974 {
01975   int contained_alignment;
01976   
01977   if (writer->enabled)
01978     {
01979       /* Allocate space for the worst case, which is 1 byte sig
01980        * length, nul byte at end of sig, and 7 bytes padding to
01981        * 8-boundary.
01982        */
01983       if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
01984         return FALSE;
01985     }
01986 
01987   /* write VARIANT typecode to the parent's type string */
01988   if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
01989     return FALSE;
01990 
01991   /* If not enabled, mark that we have no type_str anymore ... */
01992 
01993   if (!writer->enabled)
01994     {
01995       sub->type_str = NULL;
01996       sub->type_pos = -1;
01997 
01998       return TRUE;
01999     }
02000 
02001   /* If we're enabled then continue ... */
02002 
02003   if (!_dbus_string_insert_byte (sub->value_str,
02004                                  sub->value_pos,
02005                                  contained_type_len))
02006     _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
02007 
02008   sub->value_pos += 1;
02009 
02010   /* Here we switch over to the expected type sig we're about to write */
02011   sub->type_str = sub->value_str;
02012   sub->type_pos = sub->value_pos;
02013 
02014   if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len,
02015                               sub->value_str, sub->value_pos))
02016     _dbus_assert_not_reached ("should not have failed to insert variant type sig");
02017 
02018   sub->value_pos += contained_type_len;
02019 
02020   if (!_dbus_string_insert_byte (sub->value_str,
02021                                  sub->value_pos,
02022                                  DBUS_TYPE_INVALID))
02023     _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
02024 
02025   sub->value_pos += 1;
02026 
02027   contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (contained_type, contained_type_start));
02028   
02029   if (!_dbus_string_insert_bytes (sub->value_str,
02030                                   sub->value_pos,
02031                                   _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment) - sub->value_pos,
02032                                   '\0'))
02033     _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
02034   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment);
02035 
02036   return TRUE;
02037 }
02038 
02039 static dbus_bool_t
02040 _dbus_type_writer_recurse_contained_len (DBusTypeWriter   *writer,
02041                                          int               container_type,
02042                                          const DBusString *contained_type,
02043                                          int               contained_type_start,
02044                                          int               contained_type_len,
02045                                          DBusTypeWriter   *sub,
02046                                          dbus_bool_t       is_array_append)
02047 {
02048   writer_recurse_init_and_check (writer, container_type, sub);
02049 
02050   switch (container_type)
02051     {
02052     case DBUS_TYPE_STRUCT:
02053       return writer_recurse_struct_or_dict_entry (writer,
02054                                                   DBUS_STRUCT_BEGIN_CHAR,
02055                                                   contained_type,
02056                                                   contained_type_start, contained_type_len,
02057                                                   sub);
02058       break;
02059     case DBUS_TYPE_DICT_ENTRY:
02060       return writer_recurse_struct_or_dict_entry (writer,
02061                                                   DBUS_DICT_ENTRY_BEGIN_CHAR,
02062                                                   contained_type,
02063                                                   contained_type_start, contained_type_len,
02064                                                   sub);
02065       break;
02066     case DBUS_TYPE_ARRAY:
02067       return writer_recurse_array (writer,
02068                                    contained_type, contained_type_start, contained_type_len,
02069                                    sub, is_array_append);
02070       break;
02071     case DBUS_TYPE_VARIANT:
02072       return writer_recurse_variant (writer,
02073                                      contained_type, contained_type_start, contained_type_len,
02074                                      sub);
02075       break;
02076     default:
02077       _dbus_assert_not_reached ("tried to recurse into type that doesn't support that");
02078       return FALSE;
02079       break;
02080     }
02081 }
02082 
02093 dbus_bool_t
02094 _dbus_type_writer_recurse (DBusTypeWriter   *writer,
02095                            int               container_type,
02096                            const DBusString *contained_type,
02097                            int               contained_type_start,
02098                            DBusTypeWriter   *sub)
02099 {
02100   int contained_type_len;
02101 
02102   if (contained_type)
02103     contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
02104   else
02105     contained_type_len = 0;
02106 
02107   return _dbus_type_writer_recurse_contained_len (writer, container_type,
02108                                                   contained_type,
02109                                                   contained_type_start,
02110                                                   contained_type_len,
02111                                                   sub,
02112                                                   FALSE);
02113 }
02114 
02127 dbus_bool_t
02128 _dbus_type_writer_append_array (DBusTypeWriter   *writer,
02129                                 const DBusString *contained_type,
02130                                 int               contained_type_start,
02131                                 DBusTypeWriter   *sub)
02132 {
02133   int contained_type_len;
02134 
02135   if (contained_type)
02136     contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
02137   else
02138     contained_type_len = 0;
02139 
02140   return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY,
02141                                                   contained_type,
02142                                                   contained_type_start,
02143                                                   contained_type_len,
02144                                                   sub,
02145                                                   TRUE);
02146 }
02147 
02148 static int
02149 writer_get_array_len (DBusTypeWriter *writer)
02150 {
02151   _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
02152   return writer->value_pos - writer->u.array.start_pos;
02153 }
02154 
02163 dbus_bool_t
02164 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
02165                              DBusTypeWriter *sub)
02166 {
02167   /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
02168   _dbus_assert (!writer->type_pos_is_expectation ||
02169                 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
02170 
02171 #if RECURSIVE_MARSHAL_WRITE_TRACE
02172   _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
02173                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
02174                  _dbus_type_to_string (writer->container_type));
02175   _dbus_verbose ("  type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
02176                  sub, sub->type_pos, sub->value_pos,
02177                  sub->type_pos_is_expectation,
02178                  _dbus_type_to_string (sub->container_type));
02179 #endif
02180 
02181   if (sub->container_type == DBUS_TYPE_STRUCT)
02182     {
02183       if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
02184         return FALSE;
02185     }
02186   else if (sub->container_type == DBUS_TYPE_DICT_ENTRY)
02187     {
02188       if (!write_or_verify_typecode (sub, DBUS_DICT_ENTRY_END_CHAR))
02189         return FALSE;
02190     }
02191   else if (sub->container_type == DBUS_TYPE_ARRAY)
02192     {
02193       if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */
02194         {
02195           dbus_uint32_t len;
02196 
02197           /* Set the array length */
02198           len = writer_get_array_len (sub);
02199           _dbus_marshal_set_uint32 (sub->value_str,
02200                                     sub->u.array.len_pos,
02201                                     len,
02202                                     sub->byte_order);
02203 #if RECURSIVE_MARSHAL_WRITE_TRACE
02204           _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",
02205                          len, sub->u.array.len_pos);
02206 #endif
02207         }
02208 #if RECURSIVE_MARSHAL_WRITE_TRACE
02209       else
02210         {
02211           _dbus_verbose ("    not filling in sub array len because we were disabled when we passed the len\n");
02212         }
02213 #endif
02214     }
02215 
02216   /* Now get type_pos right for the parent writer. Here are the cases:
02217    *
02218    * Cases !writer->type_pos_is_expectation:
02219    *   (in these cases we want to update to the new insertion point)
02220    *
02221    * - if we recursed into a STRUCT then we didn't know in advance
02222    *   what the types in the struct would be; so we have to fill in
02223    *   that information now.
02224    *       writer->type_pos = sub->type_pos
02225    *
02226    * - if we recursed into anything else, we knew the full array
02227    *   type, or knew the single typecode marking VARIANT, so
02228    *   writer->type_pos is already correct.
02229    *       writer->type_pos should remain as-is
02230    *
02231    * - note that the parent is never an ARRAY or VARIANT, if it were
02232    *   then type_pos_is_expectation would be TRUE. The parent
02233    *   is thus known to be a toplevel or STRUCT.
02234    *
02235    * Cases where writer->type_pos_is_expectation:
02236    *   (in these cases we want to update to next expected type to write)
02237    *
02238    * - we recursed from STRUCT into STRUCT and we didn't increment
02239    *   type_pos in the parent just to stay consistent with the
02240    *   !writer->type_pos_is_expectation case (though we could
02241    *   special-case this in recurse_struct instead if we wanted)
02242    *       writer->type_pos = sub->type_pos
02243    *
02244    * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
02245    *   for parent should have been incremented already
02246    *       writer->type_pos should remain as-is
02247    *
02248    * - we recursed from ARRAY into a sub-element, so type_pos in the
02249    *   parent is the element type and should remain the element type
02250    *   for the benefit of the next child element
02251    *       writer->type_pos should remain as-is
02252    *
02253    * - we recursed from VARIANT into its value, so type_pos in the
02254    *   parent makes no difference since there's only one value
02255    *   and we just finished writing it and won't use type_pos again
02256    *       writer->type_pos should remain as-is
02257    *
02258    *
02259    * For all these, DICT_ENTRY is the same as STRUCT
02260    */
02261   if (writer->type_str != NULL)
02262     {
02263       if ((sub->container_type == DBUS_TYPE_STRUCT ||
02264            sub->container_type == DBUS_TYPE_DICT_ENTRY) &&
02265           (writer->container_type == DBUS_TYPE_STRUCT ||
02266            writer->container_type == DBUS_TYPE_DICT_ENTRY ||
02267            writer->container_type == DBUS_TYPE_INVALID))
02268         {
02269           /* Advance the parent to the next struct field */
02270           writer->type_pos = sub->type_pos;
02271         }
02272     }
02273 
02274   writer->value_pos = sub->value_pos;
02275 
02276 #if RECURSIVE_MARSHAL_WRITE_TRACE
02277   _dbus_verbose ("  type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
02278                  writer, writer->type_pos, writer->value_pos,
02279                  writer->type_str ?
02280                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
02281                  "unknown");
02282 #endif
02283 
02284   return TRUE;
02285 }
02286 
02295 dbus_bool_t
02296 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
02297                                int             type,
02298                                const void     *value)
02299 {
02300   dbus_bool_t retval;
02301 
02302   /* First ensure that our type realloc will succeed */
02303   if (!writer->type_pos_is_expectation && writer->type_str != NULL)
02304     {
02305       if (!_dbus_string_alloc_space (writer->type_str, 1))
02306         return FALSE;
02307     }
02308 
02309   retval = FALSE;
02310 
02311   if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
02312     goto out;
02313 
02314   if (!write_or_verify_typecode (writer, type))
02315     _dbus_assert_not_reached ("failed to write typecode after prealloc");
02316 
02317   retval = TRUE;
02318 
02319  out:
02320 #if RECURSIVE_MARSHAL_WRITE_TRACE
02321   _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
02322                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
02323                  writer->enabled);
02324 #endif
02325 
02326   return retval;
02327 }
02328 
02343 dbus_bool_t
02344 _dbus_type_writer_write_fixed_multi (DBusTypeWriter        *writer,
02345                                      int                    element_type,
02346                                      const void            *value,
02347                                      int                    n_elements)
02348 {
02349   _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
02350   _dbus_assert (dbus_type_is_fixed (element_type));
02351   _dbus_assert (writer->type_pos_is_expectation);
02352   _dbus_assert (n_elements >= 0);
02353 
02354 #if RECURSIVE_MARSHAL_WRITE_TRACE
02355   _dbus_verbose ("  type writer %p entering fixed multi type_pos = %d value_pos = %d n_elements %d\n",
02356                  writer, writer->type_pos, writer->value_pos, n_elements);
02357 #endif
02358 
02359   if (!write_or_verify_typecode (writer, element_type))
02360     _dbus_assert_not_reached ("OOM should not happen if only verifying typecode");
02361 
02362   if (writer->enabled)
02363     {
02364       if (!_dbus_marshal_write_fixed_multi (writer->value_str,
02365                                             writer->value_pos,
02366                                             element_type,
02367                                             value,
02368                                             n_elements,
02369                                             writer->byte_order,
02370                                             &writer->value_pos))
02371         return FALSE;
02372     }
02373 
02374 #if RECURSIVE_MARSHAL_WRITE_TRACE
02375   _dbus_verbose ("  type writer %p fixed multi written new type_pos = %d new value_pos = %d n_elements %d\n",
02376                  writer, writer->type_pos, writer->value_pos, n_elements);
02377 #endif
02378 
02379   return TRUE;
02380 }
02381 
02382 static void
02383 enable_if_after (DBusTypeWriter       *writer,
02384                  DBusTypeReader       *reader,
02385                  const DBusTypeReader *start_after)
02386 {
02387   if (start_after)
02388     {
02389       if (!writer->enabled && _dbus_type_reader_greater_than (reader, start_after))
02390         {
02391           _dbus_type_writer_set_enabled (writer, TRUE);
02392 #if RECURSIVE_MARSHAL_WRITE_TRACE
02393           _dbus_verbose ("ENABLING writer %p at %d because reader at value_pos %d is after reader at value_pos %d\n",
02394                          writer, writer->value_pos, reader->value_pos, start_after->value_pos);
02395 #endif
02396         }
02397 
02398       _dbus_assert ((!writer->enabled && !_dbus_type_reader_greater_than (reader, start_after)) ||
02399                     (writer->enabled && _dbus_type_reader_greater_than (reader, start_after)));
02400     }
02401 }
02402 
02403 static dbus_bool_t
02404 append_fixup (DBusList               **fixups,
02405               const DBusArrayLenFixup *fixup)
02406 {
02407   DBusArrayLenFixup *f;
02408 
02409   f = dbus_new (DBusArrayLenFixup, 1);
02410   if (f == NULL)
02411     return FALSE;
02412 
02413   *f = *fixup;
02414 
02415   if (!_dbus_list_append (fixups, f))
02416     {
02417       dbus_free (f);
02418       return FALSE;
02419     }
02420 
02421   _dbus_assert (f->len_pos_in_reader == fixup->len_pos_in_reader);
02422   _dbus_assert (f->new_len == fixup->new_len);
02423 
02424   return TRUE;
02425 }
02426 
02427 /* This loop is trivial if you ignore all the start_after nonsense,
02428  * so if you're trying to figure it out, start by ignoring that
02429  */
02430 static dbus_bool_t
02431 writer_write_reader_helper (DBusTypeWriter       *writer,
02432                             DBusTypeReader       *reader,
02433                             const DBusTypeReader *start_after,
02434                             int                   start_after_new_pos,
02435                             int                   start_after_new_len,
02436                             DBusList            **fixups,
02437                             dbus_bool_t           inside_start_after)
02438 {
02439   int current_type;
02440 
02441   while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
02442     {
02443       if (dbus_type_is_container (current_type))
02444         {
02445           DBusTypeReader subreader;
02446           DBusTypeWriter subwriter;
02447           const DBusString *sig_str;
02448           int sig_start;
02449           int sig_len;
02450           dbus_bool_t enabled_at_recurse;
02451           dbus_bool_t past_start_after;
02452           int reader_array_len_pos;
02453           int reader_array_start_pos;
02454           dbus_bool_t this_is_start_after;
02455 
02456           /* type_pos is checked since e.g. in a struct the struct
02457            * and its first field have the same value_pos.
02458            * type_str will differ in reader/start_after for variants
02459            * where type_str is inside the value_str
02460            */
02461           if (!inside_start_after && start_after &&
02462               reader->value_pos == start_after->value_pos &&
02463               reader->type_str == start_after->type_str &&
02464               reader->type_pos == start_after->type_pos)
02465             this_is_start_after = TRUE;
02466           else
02467             this_is_start_after = FALSE;
02468 
02469           _dbus_type_reader_recurse (reader, &subreader);
02470 
02471           if (current_type == DBUS_TYPE_ARRAY)
02472             {
02473               reader_array_len_pos = ARRAY_READER_LEN_POS (&subreader);
02474               reader_array_start_pos = subreader.u.array.start_pos;
02475             }
02476           else
02477             {
02478               /* quiet gcc */
02479               reader_array_len_pos = -1;
02480               reader_array_start_pos = -1;
02481             }
02482 
02483           _dbus_type_reader_get_signature (&subreader, &sig_str,
02484                                            &sig_start, &sig_len);
02485 
02486 #if RECURSIVE_MARSHAL_WRITE_TRACE
02487           _dbus_verbose ("about to recurse into %s reader at %d subreader at %d writer at %d start_after reader at %d write target len %d inside_start_after = %d this_is_start_after = %d\n",
02488                          _dbus_type_to_string (current_type),
02489                          reader->value_pos,
02490                          subreader.value_pos,
02491                          writer->value_pos,
02492                          start_after ? start_after->value_pos : -1,
02493                          _dbus_string_get_length (writer->value_str),
02494                          inside_start_after, this_is_start_after);
02495 #endif
02496 
02497           if (!inside_start_after && !this_is_start_after)
02498             enable_if_after (writer, &subreader, start_after);
02499           enabled_at_recurse = writer->enabled;
02500           if (!_dbus_type_writer_recurse_contained_len (writer, current_type,
02501                                                         sig_str, sig_start, sig_len,
02502                                                         &subwriter, FALSE))
02503             goto oom;
02504 
02505 #if RECURSIVE_MARSHAL_WRITE_TRACE
02506           _dbus_verbose ("recursed into subwriter at %d write target len %d\n",
02507                          subwriter.value_pos,
02508                          _dbus_string_get_length (subwriter.value_str));
02509 #endif
02510 
02511           if (!writer_write_reader_helper (&subwriter, &subreader, start_after,
02512                                            start_after_new_pos, start_after_new_len,
02513                                            fixups,
02514                                            inside_start_after ||
02515                                            this_is_start_after))
02516             goto oom;
02517 
02518 #if RECURSIVE_MARSHAL_WRITE_TRACE
02519           _dbus_verbose ("about to unrecurse from %s subreader at %d writer at %d subwriter at %d  write target len %d\n",
02520                          _dbus_type_to_string (current_type),
02521                          subreader.value_pos,
02522                          writer->value_pos,
02523                          subwriter.value_pos,
02524                          _dbus_string_get_length (writer->value_str));
02525 #endif
02526 
02527           if (!inside_start_after && !this_is_start_after)
02528             enable_if_after (writer, &subreader, start_after);
02529           past_start_after = writer->enabled;
02530           if (!_dbus_type_writer_unrecurse (writer, &subwriter))
02531             goto oom;
02532 
02533           /* If we weren't enabled when we recursed, we didn't
02534            * write an array len; if we passed start_after
02535            * somewhere inside the array, then we need to generate
02536            * a fixup.
02537            */
02538           if (start_after != NULL &&
02539               !enabled_at_recurse && past_start_after &&
02540               current_type == DBUS_TYPE_ARRAY &&
02541               fixups != NULL)
02542             {
02543               DBusArrayLenFixup fixup;
02544               int bytes_written_after_start_after;
02545               int bytes_before_start_after;
02546               int old_len;
02547 
02548               /* this subwriter access is moderately unkosher since we
02549                * already unrecursed, but it works as long as unrecurse
02550                * doesn't break us on purpose
02551                */
02552               bytes_written_after_start_after = writer_get_array_len (&subwriter);
02553 
02554               bytes_before_start_after =
02555                 start_after->value_pos - reader_array_start_pos;
02556 
02557               fixup.len_pos_in_reader = reader_array_len_pos;
02558               fixup.new_len =
02559                 bytes_before_start_after +
02560                 start_after_new_len +
02561                 bytes_written_after_start_after;
02562 
02563               _dbus_assert (_DBUS_ALIGN_VALUE (fixup.len_pos_in_reader, 4) ==
02564                             (unsigned) fixup.len_pos_in_reader);
02565 
02566               old_len = _dbus_unpack_uint32 (reader->byte_order,
02567                                              _dbus_string_get_const_data_len (reader->value_str,
02568                                                                               fixup.len_pos_in_reader, 4));
02569 
02570               if (old_len != fixup.new_len && !append_fixup (fixups, &fixup))
02571                 goto oom;
02572 
02573 #if RECURSIVE_MARSHAL_WRITE_TRACE
02574               _dbus_verbose ("Generated fixup len_pos_in_reader = %d new_len = %d reader_array_start_pos = %d start_after->value_pos = %d bytes_before_start_after = %d start_after_new_len = %d bytes_written_after_start_after = %d\n",
02575                              fixup.len_pos_in_reader,
02576                              fixup.new_len,
02577                              reader_array_start_pos,
02578                              start_after->value_pos,
02579                              bytes_before_start_after,
02580                              start_after_new_len,
02581                              bytes_written_after_start_after);
02582 #endif
02583             }
02584         }
02585       else
02586         {
02587           DBusBasicValue val;
02588 
02589           _dbus_assert (dbus_type_is_basic (current_type));
02590 
02591 #if RECURSIVE_MARSHAL_WRITE_TRACE
02592           _dbus_verbose ("Reading basic value %s at %d\n",
02593                          _dbus_type_to_string (current_type),
02594                          reader->value_pos);
02595 #endif
02596 
02597           _dbus_type_reader_read_basic (reader, &val);
02598 
02599 #if RECURSIVE_MARSHAL_WRITE_TRACE
02600           _dbus_verbose ("Writing basic value %s at %d write target len %d inside_start_after = %d\n",
02601                          _dbus_type_to_string (current_type),
02602                          writer->value_pos,
02603                          _dbus_string_get_length (writer->value_str),
02604                          inside_start_after);
02605 #endif
02606           if (!inside_start_after)
02607             enable_if_after (writer, reader, start_after);
02608           if (!_dbus_type_writer_write_basic (writer, current_type, &val))
02609             goto oom;
02610 #if RECURSIVE_MARSHAL_WRITE_TRACE
02611           _dbus_verbose ("Wrote basic value %s, new value_pos %d write target len %d\n",
02612                          _dbus_type_to_string (current_type),
02613                          writer->value_pos,
02614                          _dbus_string_get_length (writer->value_str));
02615 #endif
02616         }
02617 
02618       _dbus_type_reader_next (reader);
02619     }
02620 
02621   return TRUE;
02622 
02623  oom:
02624   if (fixups)
02625     apply_and_free_fixups (fixups, NULL); /* NULL for reader to apply to */
02626 
02627   return FALSE;
02628 }
02629 
02661 dbus_bool_t
02662 _dbus_type_writer_write_reader_partial (DBusTypeWriter       *writer,
02663                                         DBusTypeReader       *reader,
02664                                         const DBusTypeReader *start_after,
02665                                         int                   start_after_new_pos,
02666                                         int                   start_after_new_len,
02667                                         DBusList            **fixups)
02668 {
02669   DBusTypeWriter orig;
02670   int orig_type_len;
02671   int orig_value_len;
02672   int new_bytes;
02673   int orig_enabled;
02674 
02675   orig = *writer;
02676   orig_type_len = _dbus_string_get_length (writer->type_str);
02677   orig_value_len = _dbus_string_get_length (writer->value_str);
02678   orig_enabled = writer->enabled;
02679 
02680   if (start_after)
02681     _dbus_type_writer_set_enabled (writer, FALSE);
02682 
02683   if (!writer_write_reader_helper (writer, reader, start_after,
02684                                    start_after_new_pos,
02685                                    start_after_new_len,
02686                                    fixups, FALSE))
02687     goto oom;
02688 
02689   _dbus_type_writer_set_enabled (writer, orig_enabled);
02690   return TRUE;
02691 
02692  oom:
02693   if (!writer->type_pos_is_expectation)
02694     {
02695       new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len;
02696       _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes);
02697     }
02698   new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len;
02699   _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes);
02700 
02701   *writer = orig;
02702 
02703   return FALSE;
02704 }
02705 
02715 dbus_bool_t
02716 _dbus_type_writer_write_reader (DBusTypeWriter       *writer,
02717                                 DBusTypeReader       *reader)
02718 {
02719   return _dbus_type_writer_write_reader_partial (writer, reader, NULL, 0, 0, NULL);
02720 }
02721 
02731 void
02732 _dbus_type_writer_set_enabled (DBusTypeWriter   *writer,
02733                                dbus_bool_t       enabled)
02734 {
02735   writer->enabled = enabled != FALSE;
02736 }
02737  /* end of DBusMarshal group */
02739 
02740 /* tests in dbus-marshal-recursive-util.c */

Generated on Tue Dec 21 2010 for D-Bus by  doxygen 1.7.1