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

Generated on Thu Jan 22 16:37:05 2009 for D-Bus by  doxygen 1.5.1