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