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