dbus-marshal-recursive.c

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

Generated on Tue Apr 15 15:53:58 2008 for D-Bus by  doxygen 1.5.1