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 static const DBusTypeReaderClass * const
00694 all_reader_classes[] = {
00695   &body_reader_class,
00696   &body_types_only_reader_class,
00697   &struct_reader_class,
00698   &struct_types_only_reader_class,
00699   &dict_entry_reader_class,
00700   &dict_entry_types_only_reader_class,
00701   &array_reader_class,
00702   &array_types_only_reader_class,
00703   &variant_reader_class
00704 };
00705 
00716 void
00717 _dbus_type_reader_init (DBusTypeReader    *reader,
00718                         int                byte_order,
00719                         const DBusString  *type_str,
00720                         int                type_pos,
00721                         const DBusString  *value_str,
00722                         int                value_pos)
00723 {
00724   reader->klass = &body_reader_class;
00725 
00726   reader_init (reader, byte_order, type_str, type_pos,
00727                value_str, value_pos);
00728 
00729 #if RECURSIVE_MARSHAL_READ_TRACE
00730   _dbus_verbose ("  type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
00731                  reader, reader->type_pos, reader->value_pos,
00732                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
00733 #endif
00734 }
00735 
00744 void
00745 _dbus_type_reader_init_types_only (DBusTypeReader    *reader,
00746                                    const DBusString  *type_str,
00747                                    int                type_pos)
00748 {
00749   reader->klass = &body_types_only_reader_class;
00750 
00751   reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
00752                type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
00753 
00754 #if RECURSIVE_MARSHAL_READ_TRACE
00755   _dbus_verbose ("  type reader %p init types only type_pos = %d remaining sig '%s'\n",
00756                  reader, reader->type_pos,
00757                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
00758 #endif
00759 }
00760 
00769 int
00770 _dbus_type_reader_get_current_type (const DBusTypeReader *reader)
00771 {
00772   int t;
00773 
00774   if (reader->finished ||
00775       (reader->klass->check_finished &&
00776        (* reader->klass->check_finished) (reader)))
00777     t = DBUS_TYPE_INVALID;
00778   else
00779     t = _dbus_first_type_in_signature (reader->type_str,
00780                                        reader->type_pos);
00781 
00782   _dbus_assert (t != DBUS_STRUCT_END_CHAR);
00783   _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
00784   _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR);
00785   _dbus_assert (t != DBUS_DICT_ENTRY_BEGIN_CHAR);
00786   
00787 #if 0
00788   _dbus_verbose ("  type reader %p current type_pos = %d type = %s\n",
00789                  reader, reader->type_pos,
00790                  _dbus_type_to_string (t));
00791 #endif
00792 
00793   return t;
00794 }
00795 
00804 int
00805 _dbus_type_reader_get_element_type (const DBusTypeReader  *reader)
00806 {
00807   int element_type;
00808 
00809   _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
00810 
00811   element_type = _dbus_first_type_in_signature (reader->type_str,
00812                                           reader->type_pos + 1);
00813 
00814   return element_type;
00815 }
00816 
00821 int
00822 _dbus_type_reader_get_value_pos (const DBusTypeReader  *reader)
00823 {
00824   return reader->value_pos;
00825 }
00826 
00836 void
00837 _dbus_type_reader_read_raw (const DBusTypeReader  *reader,
00838                             const unsigned char  **value_location)
00839 {
00840   _dbus_assert (!reader->klass->types_only);
00841 
00842   *value_location = _dbus_string_get_const_data_len (reader->value_str,
00843                                                      reader->value_pos,
00844                                                      0);
00845 }
00846 
00853 void
00854 _dbus_type_reader_read_basic (const DBusTypeReader    *reader,
00855                               void                    *value)
00856 {
00857   int t;
00858 
00859   _dbus_assert (!reader->klass->types_only);
00860 
00861   t = _dbus_type_reader_get_current_type (reader);
00862 
00863   _dbus_marshal_read_basic (reader->value_str,
00864                             reader->value_pos,
00865                             t, value,
00866                             reader->byte_order,
00867                             NULL);
00868 
00869 
00870 #if RECURSIVE_MARSHAL_READ_TRACE
00871   _dbus_verbose ("  type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",
00872                  reader, reader->type_pos, reader->value_pos,
00873                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
00874 #endif
00875 }
00876 
00883 int
00884 _dbus_type_reader_get_array_length (const DBusTypeReader  *reader)
00885 {
00886   _dbus_assert (!reader->klass->types_only);
00887   _dbus_assert (reader->klass == &array_reader_class);
00888 
00889   return array_reader_get_array_len (reader);
00890 }
00891 
00907 void
00908 _dbus_type_reader_read_fixed_multi (const DBusTypeReader  *reader,
00909                                     void                  *value,
00910                                     int                   *n_elements)
00911 {
00912   int element_type;
00913   int end_pos;
00914   int remaining_len;
00915   int alignment;
00916   int total_len;
00917 
00918   _dbus_assert (!reader->klass->types_only);
00919   _dbus_assert (reader->klass == &array_reader_class);
00920 
00921   element_type = _dbus_first_type_in_signature (reader->type_str,
00922                                                 reader->type_pos);
00923 
00924   _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */
00925   _dbus_assert (dbus_type_is_fixed (element_type));
00926 
00927   alignment = _dbus_type_get_alignment (element_type);
00928 
00929   _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
00930 
00931   total_len = array_reader_get_array_len (reader);
00932   end_pos = reader->u.array.start_pos + total_len;
00933   remaining_len = end_pos - reader->value_pos;
00934 
00935 #if RECURSIVE_MARSHAL_READ_TRACE
00936   _dbus_verbose ("end_pos %d total_len %d remaining_len %d value_pos %d\n",
00937                  end_pos, total_len, remaining_len, reader->value_pos);
00938 #endif
00939 
00940   _dbus_assert (remaining_len <= total_len);
00941 
00942   if (remaining_len == 0)
00943     *(const DBusBasicValue**) value = NULL;
00944   else
00945     *(const DBusBasicValue**) value =
00946       (void*) _dbus_string_get_const_data_len (reader->value_str,
00947                                                reader->value_pos,
00948                                                remaining_len);
00949 
00950   *n_elements = remaining_len / alignment;
00951   _dbus_assert ((remaining_len % alignment) == 0);
00952 
00953 #if RECURSIVE_MARSHAL_READ_TRACE
00954   _dbus_verbose ("  type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n",
00955                  reader, reader->type_pos, reader->value_pos,
00956                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
00957 #endif
00958 }
00959 
00972 void
00973 _dbus_type_reader_recurse (DBusTypeReader *reader,
00974                            DBusTypeReader *sub)
00975 {
00976   int t;
00977 
00978   t = _dbus_first_type_in_signature (reader->type_str, reader->type_pos);
00979 
00980   switch (t)
00981     {
00982     case DBUS_TYPE_STRUCT:
00983       if (reader->klass->types_only)
00984         sub->klass = &struct_types_only_reader_class;
00985       else
00986         sub->klass = &struct_reader_class;
00987       break;
00988     case DBUS_TYPE_DICT_ENTRY:
00989       if (reader->klass->types_only)
00990         sub->klass = &dict_entry_types_only_reader_class;
00991       else
00992         sub->klass = &dict_entry_reader_class;
00993       break;
00994     case DBUS_TYPE_ARRAY:
00995       if (reader->klass->types_only)
00996         sub->klass = &array_types_only_reader_class;
00997       else
00998         sub->klass = &array_reader_class;
00999       break;
01000     case DBUS_TYPE_VARIANT:
01001       if (reader->klass->types_only)
01002         _dbus_assert_not_reached ("can't recurse into variant typecode");
01003       else
01004         sub->klass = &variant_reader_class;
01005       break;
01006     default:
01007       _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
01008 #ifndef DBUS_DISABLE_CHECKS
01009       if (t == DBUS_TYPE_INVALID)
01010         _dbus_warn_check_failed ("You can't recurse into an empty array or off the end of a message body\n");
01011 #endif /* DBUS_DISABLE_CHECKS */
01012 
01013       _dbus_assert_not_reached ("don't yet handle recursing into this type");
01014     }
01015 
01016   _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]);
01017 
01018   (* sub->klass->recurse) (sub, reader);
01019 
01020 #if RECURSIVE_MARSHAL_READ_TRACE
01021   _dbus_verbose ("  type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
01022                  sub, sub->type_pos, sub->value_pos,
01023                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
01024 #endif
01025 }
01026 
01035 dbus_bool_t
01036 _dbus_type_reader_next (DBusTypeReader *reader)
01037 {
01038   int t;
01039 
01040   t = _dbus_type_reader_get_current_type (reader);
01041 
01042 #if RECURSIVE_MARSHAL_READ_TRACE
01043   _dbus_verbose ("  type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
01044                  reader, reader->type_pos, reader->value_pos,
01045                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
01046                  _dbus_type_to_string (t));
01047 #endif
01048 
01049   if (t == DBUS_TYPE_INVALID)
01050     return FALSE;
01051 
01052   (* reader->klass->next) (reader, t);
01053 
01054 #if RECURSIVE_MARSHAL_READ_TRACE
01055   _dbus_verbose ("  type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
01056                  reader, reader->type_pos, reader->value_pos,
01057                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
01058                  _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
01059 #endif
01060 
01061   return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
01062 }
01063 
01075 dbus_bool_t
01076 _dbus_type_reader_has_next (const DBusTypeReader *reader)
01077 {
01078   /* Not efficient but works for now. */
01079   DBusTypeReader copy;
01080 
01081   copy = *reader;
01082   return _dbus_type_reader_next (&copy);
01083 }
01084 
01106 void
01107 _dbus_type_reader_get_signature (const DBusTypeReader  *reader,
01108                                  const DBusString     **str_p,
01109                                  int                   *start_p,
01110                                  int                   *len_p)
01111 {
01112   *str_p = reader->type_str;
01113   *start_p = reader->type_pos;
01114   *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);
01115 }
01116 
01117 typedef struct
01118 {
01119   DBusString replacement; 
01120   int padding;            
01121 } ReplacementBlock;
01122 
01123 static dbus_bool_t
01124 replacement_block_init (ReplacementBlock *block,
01125                         DBusTypeReader   *reader)
01126 {
01127   if (!_dbus_string_init (&block->replacement))
01128     return FALSE;
01129 
01130   /* % 8 is the padding to have the same align properties in
01131    * our replacement string as we do at the position being replaced
01132    */
01133   block->padding = reader->value_pos % 8;
01134 
01135   if (!_dbus_string_lengthen (&block->replacement, block->padding))
01136     goto oom;
01137 
01138   return TRUE;
01139 
01140  oom:
01141   _dbus_string_free (&block->replacement);
01142   return FALSE;
01143 }
01144 
01145 static dbus_bool_t
01146 replacement_block_replace (ReplacementBlock     *block,
01147                            DBusTypeReader       *reader,
01148                            const DBusTypeReader *realign_root)
01149 {
01150   DBusTypeWriter writer;
01151   DBusTypeReader realign_reader;
01152   DBusList *fixups;
01153   int orig_len;
01154 
01155   _dbus_assert (realign_root != NULL);
01156 
01157   orig_len = _dbus_string_get_length (&block->replacement);
01158 
01159   realign_reader = *realign_root;
01160 
01161 #if RECURSIVE_MARSHAL_WRITE_TRACE
01162   _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n",
01163                  &writer, _dbus_string_get_length (&block->replacement));
01164 #endif
01165   _dbus_type_writer_init_values_only (&writer,
01166                                       realign_reader.byte_order,
01167                                       realign_reader.type_str,
01168                                       realign_reader.type_pos,
01169                                       &block->replacement,
01170                                       _dbus_string_get_length (&block->replacement));
01171 
01172   _dbus_assert (realign_reader.value_pos <= reader->value_pos);
01173 
01174 #if RECURSIVE_MARSHAL_WRITE_TRACE
01175   _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n",
01176                  realign_reader.value_pos, &writer, reader->value_pos);
01177 #endif
01178   fixups = NULL;
01179   if (!_dbus_type_writer_write_reader_partial (&writer,
01180                                                &realign_reader,
01181                                                reader,
01182                                                block->padding,
01183                                                _dbus_string_get_length (&block->replacement) - block->padding,
01184                                                &fixups))
01185     goto oom;
01186 
01187 #if RECURSIVE_MARSHAL_WRITE_TRACE
01188   _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding,
01189                  _dbus_string_get_length (&block->replacement) - block->padding);
01190   _dbus_verbose_bytes_of_string (&block->replacement, block->padding,
01191                                  _dbus_string_get_length (&block->replacement) - block->padding);
01192   _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n",
01193                  reader->value_pos, reader->value_pos % 8,
01194                  realign_reader.value_pos - reader->value_pos,
01195                  realign_reader.value_pos);
01196   _dbus_verbose_bytes_of_string (reader->value_str,
01197                                  reader->value_pos,
01198                                  realign_reader.value_pos - reader->value_pos);
01199 #endif
01200 
01201   /* Move the replacement into position
01202    * (realign_reader should now be at the end of the block to be replaced)
01203    */
01204   if (!_dbus_string_replace_len (&block->replacement, block->padding,
01205                                  _dbus_string_get_length (&block->replacement) - block->padding,
01206                                  (DBusString*) reader->value_str,
01207                                  reader->value_pos,
01208                                  realign_reader.value_pos - reader->value_pos))
01209     goto oom;
01210 
01211   /* Process our fixups now that we can't have an OOM error */
01212   apply_and_free_fixups (&fixups, reader);
01213 
01214   return TRUE;
01215 
01216  oom:
01217   _dbus_string_set_length (&block->replacement, orig_len);
01218   free_fixups (&fixups);
01219   return FALSE;
01220 }
01221 
01222 static void
01223 replacement_block_free (ReplacementBlock *block)
01224 {
01225   _dbus_string_free (&block->replacement);
01226 }
01227 
01228 /* In the variable-length case, we have to fix alignment after we insert.
01229  * The strategy is as follows:
01230  *
01231  *  - pad a new string to have the same alignment as the
01232  *    start of the current basic value
01233  *  - write the new basic value
01234  *  - copy from the original reader to the new string,
01235  *    which will fix the alignment of types following
01236  *    the new value
01237  *    - this copy has to start at realign_root,
01238  *      but not really write anything until it
01239  *      passes the value being set
01240  *    - as an optimization, we can stop copying
01241  *      when the source and dest values are both
01242  *      on an 8-boundary, since we know all following
01243  *      padding and alignment will be identical
01244  *  - copy the new string back to the original
01245  *    string, replacing the relevant part of the
01246  *    original string
01247  *  - now any arrays in the original string that
01248  *    contained the replaced string may have the
01249  *    wrong length; so we have to fix that
01250  */
01251 static dbus_bool_t
01252 reader_set_basic_variable_length (DBusTypeReader       *reader,
01253                                   int                   current_type,
01254                                   const void           *value,
01255                                   const DBusTypeReader *realign_root)
01256 {
01257   dbus_bool_t retval;
01258   ReplacementBlock block;
01259   DBusTypeWriter writer;
01260 
01261   _dbus_assert (realign_root != NULL);
01262 
01263   retval = FALSE;
01264 
01265   if (!replacement_block_init (&block, reader))
01266     return FALSE;
01267 
01268   /* Write the new basic value */
01269 #if RECURSIVE_MARSHAL_WRITE_TRACE
01270   _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n",
01271                  &writer, _dbus_string_get_length (&block.replacement));
01272 #endif
01273   _dbus_type_writer_init_values_only (&writer,
01274                                       reader->byte_order,
01275                                       reader->type_str,
01276                                       reader->type_pos,
01277                                       &block.replacement,
01278                                       _dbus_string_get_length (&block.replacement));
01279 #if RECURSIVE_MARSHAL_WRITE_TRACE
01280   _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer);
01281 #endif
01282   if (!_dbus_type_writer_write_basic (&writer, current_type, value))
01283     goto out;
01284 
01285   if (!replacement_block_replace (&block,
01286                                   reader,
01287                                   realign_root))
01288     goto out;
01289 
01290   retval = TRUE;
01291 
01292  out:
01293   replacement_block_free (&block);
01294   return retval;
01295 }
01296 
01297 static void
01298 reader_set_basic_fixed_length (DBusTypeReader *reader,
01299                                int             current_type,
01300                                const void     *value)
01301 {
01302   _dbus_marshal_set_basic ((DBusString*) reader->value_str,
01303                            reader->value_pos,
01304                            current_type,
01305                            value,
01306                            reader->byte_order,
01307                            NULL, NULL);
01308 }
01309 
01344 dbus_bool_t
01345 _dbus_type_reader_set_basic (DBusTypeReader       *reader,
01346                              const void           *value,
01347                              const DBusTypeReader *realign_root)
01348 {
01349   int current_type;
01350 
01351   _dbus_assert (!reader->klass->types_only);
01352   _dbus_assert (reader->value_str == realign_root->value_str);
01353   _dbus_assert (reader->value_pos >= realign_root->value_pos);
01354 
01355   current_type = _dbus_type_reader_get_current_type (reader);
01356 
01357 #if RECURSIVE_MARSHAL_WRITE_TRACE
01358   _dbus_verbose ("  SET BASIC type reader %p type_pos = %d value_pos = %d remaining sig '%s' realign_root = %p with value_pos %d current_type = %s\n",
01359                  reader, reader->type_pos, reader->value_pos,
01360                  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
01361                  realign_root,
01362                  realign_root ? realign_root->value_pos : -1,
01363                  _dbus_type_to_string (current_type));
01364   _dbus_verbose_bytes_of_string (realign_root->value_str, realign_root->value_pos,
01365                                  _dbus_string_get_length (realign_root->value_str) -
01366                                  realign_root->value_pos);
01367 #endif
01368 
01369   _dbus_assert (dbus_type_is_basic (current_type));
01370 
01371   if (dbus_type_is_fixed (current_type))
01372     {
01373       reader_set_basic_fixed_length (reader, current_type, value);
01374       return TRUE;
01375     }
01376   else
01377     {
01378       _dbus_assert (realign_root != NULL);
01379       return reader_set_basic_variable_length (reader, current_type,
01380                                                value, realign_root);
01381     }
01382 }
01383 
01401 dbus_bool_t
01402 _dbus_type_reader_delete (DBusTypeReader        *reader,
01403                           const DBusTypeReader  *realign_root)
01404 {
01405   dbus_bool_t retval;
01406   ReplacementBlock block;
01407 
01408   _dbus_assert (realign_root != NULL);
01409   _dbus_assert (reader->klass == &array_reader_class);
01410 
01411   retval = FALSE;
01412 
01413   if (!replacement_block_init (&block, reader))
01414     return FALSE;
01415 
01416   if (!replacement_block_replace (&block,
01417                                   reader,
01418                                   realign_root))
01419     goto out;
01420 
01421   retval = TRUE;
01422 
01423  out:
01424   replacement_block_free (&block);
01425   return retval;
01426 }
01427 
01436 dbus_bool_t
01437 _dbus_type_reader_greater_than (const DBusTypeReader  *lhs,
01438                                 const DBusTypeReader  *rhs)
01439 {
01440   _dbus_assert (lhs->value_str == rhs->value_str);
01441 
01442   return lhs->value_pos > rhs->value_pos;
01443 }
01444 
01445 /*
01446  *
01447  *
01448  *         DBusTypeWriter
01449  *
01450  *
01451  *
01452  */
01453 
01474 void
01475 _dbus_type_writer_init (DBusTypeWriter *writer,
01476                         int             byte_order,
01477                         DBusString     *type_str,
01478                         int             type_pos,
01479                         DBusString     *value_str,
01480                         int             value_pos)
01481 {
01482   writer->byte_order = byte_order;
01483   writer->type_str = type_str;
01484   writer->type_pos = type_pos;
01485   writer->value_str = value_str;
01486   writer->value_pos = value_pos;
01487   writer->container_type = DBUS_TYPE_INVALID;
01488   writer->type_pos_is_expectation = FALSE;
01489   writer->enabled = TRUE;
01490 
01491 #if RECURSIVE_MARSHAL_WRITE_TRACE
01492   _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
01493                  writer->type_str ?
01494                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
01495                  "unknown");
01496 #endif
01497 }
01498 
01509 void
01510 _dbus_type_writer_init_types_delayed (DBusTypeWriter *writer,
01511                                       int             byte_order,
01512                                       DBusString     *value_str,
01513                                       int             value_pos)
01514 {
01515   _dbus_type_writer_init (writer, byte_order,
01516                           NULL, 0, value_str, value_pos);
01517 }
01518 
01527 void
01528 _dbus_type_writer_add_types (DBusTypeWriter *writer,
01529                              DBusString     *type_str,
01530                              int             type_pos)
01531 {
01532   if (writer->type_str == NULL) /* keeps us from using this as setter */
01533     {
01534       writer->type_str = type_str;
01535       writer->type_pos = type_pos;
01536     }
01537 }
01538 
01544 void
01545 _dbus_type_writer_remove_types (DBusTypeWriter *writer)
01546 {
01547   writer->type_str = NULL;
01548   writer->type_pos = -1;
01549 }
01550 
01565 void
01566 _dbus_type_writer_init_values_only (DBusTypeWriter   *writer,
01567                                     int               byte_order,
01568                                     const DBusString *type_str,
01569                                     int               type_pos,
01570                                     DBusString       *value_str,
01571                                     int               value_pos)
01572 {
01573   _dbus_type_writer_init (writer, byte_order,
01574                           (DBusString*)type_str, type_pos,
01575                           value_str, value_pos);
01576 
01577   writer->type_pos_is_expectation = TRUE;
01578 }
01579 
01580 static dbus_bool_t
01581 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
01582                                            int             type,
01583                                            const void     *value)
01584 {
01585   if (writer->enabled)
01586     return _dbus_marshal_write_basic (writer->value_str,
01587                                       writer->value_pos,
01588                                       type,
01589                                       value,
01590                                       writer->byte_order,
01591                                       &writer->value_pos);
01592   else
01593     return TRUE;
01594 }
01595 
01596 /* If our parent is an array, things are a little bit complicated.
01597  *
01598  * The parent must have a complete element type, such as
01599  * "i" or "aai" or "(ii)" or "a(ii)". There can't be
01600  * unclosed parens, or an "a" with no following type.
01601  *
01602  * To recurse, the only allowed operation is to recurse into the
01603  * first type in the element type. So for "i" you can't recurse, for
01604  * "ai" you can recurse into the array, for "(ii)" you can recurse
01605  * into the struct.
01606  *
01607  * If you recurse into the array for "ai", then you must specify
01608  * "i" for the element type of the array you recurse into.
01609  *
01610  * While inside an array at any level, we need to avoid writing to
01611  * type_str, since the type only appears once for the whole array,
01612  * it does not appear for each array element.
01613  *
01614  * While inside an array type_pos points to the expected next
01615  * typecode, rather than the next place we could write a typecode.
01616  */
01617 static void
01618 writer_recurse_init_and_check (DBusTypeWriter *writer,
01619                                int             container_type,
01620                                DBusTypeWriter *sub)
01621 {
01622   _dbus_type_writer_init (sub,
01623                           writer->byte_order,
01624                           writer->type_str,
01625                           writer->type_pos,
01626                           writer->value_str,
01627                           writer->value_pos);
01628 
01629   sub->container_type = container_type;
01630 
01631   if (writer->type_pos_is_expectation ||
01632       (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
01633     sub->type_pos_is_expectation = TRUE;
01634   else
01635     sub->type_pos_is_expectation = FALSE;
01636 
01637   sub->enabled = writer->enabled;
01638 
01639 #ifndef DBUS_DISABLE_CHECKS
01640   if (writer->type_pos_is_expectation && writer->type_str)
01641     {
01642       int expected;
01643 
01644       expected = _dbus_first_type_in_signature (writer->type_str, writer->type_pos);
01645 
01646       if (expected != sub->container_type)
01647         {
01648           if (expected != DBUS_TYPE_INVALID)
01649             _dbus_warn_check_failed ("Writing an element of type %s, but the expected type here is %s\n"
01650                                      "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
01651                                      _dbus_type_to_string (sub->container_type),
01652                                      _dbus_type_to_string (expected),
01653                                      _dbus_string_get_const_data (writer->type_str), writer->type_pos);
01654           else
01655             _dbus_warn_check_failed ("Writing an element of type %s, but no value is expected here\n",
01656                                      "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
01657                                      _dbus_type_to_string (sub->container_type),
01658                                      _dbus_string_get_const_data (writer->type_str), writer->type_pos);
01659           
01660           _dbus_assert_not_reached ("bad array element or variant content written");
01661         }
01662     }
01663 #endif /* DBUS_DISABLE_CHECKS */
01664 
01665 #if RECURSIVE_MARSHAL_WRITE_TRACE
01666   _dbus_verbose ("  type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n",
01667                  writer,
01668                  _dbus_type_to_string (writer->container_type),
01669                  writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
01670                  writer->type_str ?
01671                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
01672                  "unknown",
01673                  writer->enabled);
01674   _dbus_verbose ("  type writer %p recurse sub %s   type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
01675                  sub,
01676                  _dbus_type_to_string (sub->container_type),
01677                  sub->type_pos, sub->value_pos,
01678                  sub->type_pos_is_expectation,
01679                  sub->enabled);
01680 #endif
01681 }
01682 
01683 static dbus_bool_t
01684 write_or_verify_typecode (DBusTypeWriter *writer,
01685                           int             typecode)
01686 {
01687   /* A subwriter inside an array or variant will have type_pos
01688    * pointing to the expected typecode; a writer not inside an array
01689    * or variant has type_pos pointing to the next place to insert a
01690    * typecode.
01691    */
01692 #if RECURSIVE_MARSHAL_WRITE_TRACE
01693   _dbus_verbose ("  type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n",
01694                  writer, writer->type_pos,
01695                  writer->type_str ?
01696                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
01697                  "unknown",
01698                  writer->enabled);
01699 #endif
01700 
01701   if (writer->type_str == NULL)
01702     return TRUE;
01703 
01704   if (writer->type_pos_is_expectation)
01705     {
01706 #ifndef DBUS_DISABLE_CHECKS
01707       {
01708         int expected;
01709 
01710         expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
01711 
01712         if (expected != typecode)
01713           {
01714             if (expected != DBUS_TYPE_INVALID)
01715               _dbus_warn_check_failed ("Array or variant type requires that type %s be written, but %s was written.\n"
01716                                        "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
01717                                        _dbus_type_to_string (expected), _dbus_type_to_string (typecode),
01718                                        _dbus_string_get_const_data (writer->type_str), writer->type_pos);
01719             else
01720               _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"
01721                                        "The overall signature expected here was '%s' and we are on byte %d of that signature.\n",
01722                                        _dbus_type_to_string (typecode),
01723                                        _dbus_string_get_const_data (writer->type_str), writer->type_pos);
01724             _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
01725           }
01726       }
01727 #endif /* DBUS_DISABLE_CHECKS */
01728 
01729       /* if immediately inside an array we'd always be appending an element,
01730        * so the expected type doesn't change; if inside a struct or something
01731        * below an array, we need to move through said struct or something.
01732        */
01733       if (writer->container_type != DBUS_TYPE_ARRAY)
01734         writer->type_pos += 1;
01735     }
01736   else
01737     {
01738       if (!_dbus_string_insert_byte (writer->type_str,
01739                                      writer->type_pos,
01740                                      typecode))
01741         return FALSE;
01742 
01743       writer->type_pos += 1;
01744     }
01745 
01746 #if RECURSIVE_MARSHAL_WRITE_TRACE
01747   _dbus_verbose ("  type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
01748                  writer, writer->type_pos,
01749                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
01750 #endif
01751 
01752   return TRUE;
01753 }
01754 
01755 static dbus_bool_t
01756 writer_recurse_struct_or_dict_entry (DBusTypeWriter   *writer,
01757                                      int               begin_char,
01758                                      const DBusString *contained_type,
01759                                      int               contained_type_start,
01760                                      int               contained_type_len,
01761                                      DBusTypeWriter   *sub)
01762 {
01763   /* FIXME right now contained_type is ignored; we could probably
01764    * almost trivially fix the code so if it's present we
01765    * write it out and then set type_pos_is_expectation
01766    */
01767 
01768   /* Ensure that we'll be able to add alignment padding and the typecode */
01769   if (writer->enabled)
01770     {
01771       if (!_dbus_string_alloc_space (sub->value_str, 8))
01772         return FALSE;
01773     }
01774 
01775   if (!write_or_verify_typecode (sub, begin_char))
01776     _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
01777 
01778   if (writer->enabled)
01779     {
01780       if (!_dbus_string_insert_bytes (sub->value_str,
01781                                       sub->value_pos,
01782                                       _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
01783                                       '\0'))
01784         _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
01785       sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
01786     }
01787 
01788   return TRUE;
01789 }
01790 
01791 
01792 static dbus_bool_t
01793 writer_recurse_array (DBusTypeWriter   *writer,
01794                       const DBusString *contained_type,
01795                       int               contained_type_start,
01796                       int               contained_type_len,
01797                       DBusTypeWriter   *sub,
01798                       dbus_bool_t       is_array_append)
01799 {
01800   dbus_uint32_t value = 0;
01801   int alignment;
01802   int aligned;
01803 
01804 #ifndef DBUS_DISABLE_CHECKS
01805   if (writer->container_type == DBUS_TYPE_ARRAY &&
01806       writer->type_str)
01807     {
01808       if (!_dbus_string_equal_substring (contained_type,
01809                                          contained_type_start,
01810                                          contained_type_len,
01811                                          writer->type_str,
01812                                          writer->u.array.element_type_pos + 1))
01813         {
01814           _dbus_warn_check_failed ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
01815                                    _dbus_string_get_const_data_len (contained_type,
01816                                                                     contained_type_start,
01817                                                                     contained_type_len));
01818           _dbus_assert_not_reached ("incompatible type for child array");
01819         }
01820     }
01821 #endif /* DBUS_DISABLE_CHECKS */
01822 
01823   if (writer->enabled && !is_array_append)
01824     {
01825       /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding
01826        * before array values
01827        */
01828       if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4))
01829         return FALSE;
01830     }
01831 
01832   if (writer->type_str != NULL)
01833     {
01834       sub->type_pos += 1; /* move to point to the element type, since type_pos
01835                            * should be the expected type for further writes
01836                            */
01837       sub->u.array.element_type_pos = sub->type_pos;
01838     }
01839 
01840   if (!writer->type_pos_is_expectation)
01841     {
01842       /* sub is a toplevel/outermost array so we need to write the type data */
01843 
01844       /* alloc space for array typecode, element signature */
01845       if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len))
01846         return FALSE;
01847 
01848       if (!_dbus_string_insert_byte (writer->type_str,
01849                                      writer->type_pos,
01850                                      DBUS_TYPE_ARRAY))
01851         _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
01852 
01853       if (!_dbus_string_copy_len (contained_type,
01854                                   contained_type_start, contained_type_len,
01855                                   sub->type_str,
01856                                   sub->u.array.element_type_pos))
01857         _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
01858     }
01859 
01860   if (writer->type_str != NULL)
01861     {
01862       /* If the parent is an array, we hold type_pos pointing at the array element type;
01863        * otherwise advance it to reflect the array value we just recursed into
01864        */
01865       if (writer->container_type != DBUS_TYPE_ARRAY)
01866         writer->type_pos += 1 + contained_type_len;
01867       else
01868         _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
01869     }
01870 
01871   if (writer->enabled)
01872     {
01873       /* Write (or jump over, if is_array_append) the length */
01874       sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
01875 
01876       if (is_array_append)
01877         {
01878           sub->value_pos += 4;
01879         }
01880       else
01881         {
01882           if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
01883                                                           &value))
01884             _dbus_assert_not_reached ("should not have failed to insert array len");
01885         }
01886 
01887       _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
01888 
01889       /* Write alignment padding for array elements
01890        * Note that we write the padding *even for empty arrays*
01891        * to avoid wonky special cases
01892        */
01893       alignment = element_type_get_alignment (contained_type, contained_type_start);
01894 
01895       aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
01896       if (aligned != sub->value_pos)
01897         {
01898           if (!is_array_append)
01899             {
01900               if (!_dbus_string_insert_bytes (sub->value_str,
01901                                               sub->value_pos,
01902                                               aligned - sub->value_pos,
01903                                               '\0'))
01904                 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
01905             }
01906 
01907           sub->value_pos = aligned;
01908         }
01909 
01910       sub->u.array.start_pos = sub->value_pos;
01911 
01912       if (is_array_append)
01913         {
01914           dbus_uint32_t len;
01915 
01916           _dbus_assert (_DBUS_ALIGN_VALUE (sub->u.array.len_pos, 4) ==
01917                         (unsigned) sub->u.array.len_pos);
01918           len = _dbus_unpack_uint32 (sub->byte_order,
01919                                      _dbus_string_get_const_data_len (sub->value_str,
01920                                                                       sub->u.array.len_pos,
01921                                                                       4));
01922 
01923           sub->value_pos += len;
01924         }
01925     }
01926   else
01927     {
01928       /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */
01929       sub->u.array.len_pos = -1;
01930       sub->u.array.start_pos = sub->value_pos;
01931     }
01932 
01933   _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
01934   _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos);
01935 
01936 #if RECURSIVE_MARSHAL_WRITE_TRACE
01937       _dbus_verbose ("  type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub,
01938                      sub->type_str ?
01939                      _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) :
01940                      "unknown",
01941                      sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos);
01942 #endif
01943 
01944   return TRUE;
01945 }
01946 
01947 /* Variant value will normally have:
01948  *   1 byte signature length not including nul
01949  *   signature typecodes (nul terminated)
01950  *   padding to alignment of contained type
01951  *   body according to signature
01952  *
01953  * The signature string can only have a single type
01954  * in it but that type may be complex/recursive.
01955  *
01956  * So a typical variant type with the integer 3 will have these
01957  * octets:
01958  *   0x1 'i' '\0' [1 byte padding to alignment boundary] 0x0 0x0 0x0 0x3
01959  *
01960  * The main world of hurt for writing out a variant is that the type
01961  * string is the same string as the value string. Which means
01962  * inserting to the type string will move the value_pos; and it means
01963  * that inserting to the type string could break type alignment.
01964  */
01965 static dbus_bool_t
01966 writer_recurse_variant (DBusTypeWriter   *writer,
01967                         const DBusString *contained_type,
01968                         int               contained_type_start,
01969                         int               contained_type_len,
01970                         DBusTypeWriter   *sub)
01971 {
01972   int contained_alignment;
01973   
01974   if (writer->enabled)
01975     {
01976       /* Allocate space for the worst case, which is 1 byte sig
01977        * length, nul byte at end of sig, and 7 bytes padding to
01978        * 8-boundary.
01979        */
01980       if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
01981         return FALSE;
01982     }
01983 
01984   /* write VARIANT typecode to the parent's type string */
01985   if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
01986     return FALSE;
01987 
01988   /* If not enabled, mark that we have no type_str anymore ... */
01989 
01990   if (!writer->enabled)
01991     {
01992       sub->type_str = NULL;
01993       sub->type_pos = -1;
01994 
01995       return TRUE;
01996     }
01997 
01998   /* If we're enabled then continue ... */
01999 
02000   if (!_dbus_string_insert_byte (sub->value_str,
02001                                  sub->value_pos,
02002                                  contained_type_len))
02003     _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
02004 
02005   sub->value_pos += 1;
02006 
02007   /* Here we switch over to the expected type sig we're about to write */
02008   sub->type_str = sub->value_str;
02009   sub->type_pos = sub->value_pos;
02010 
02011   if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len,
02012                               sub->value_str, sub->value_pos))
02013     _dbus_assert_not_reached ("should not have failed to insert variant type sig");
02014 
02015   sub->value_pos += contained_type_len;
02016 
02017   if (!_dbus_string_insert_byte (sub->value_str,
02018                                  sub->value_pos,
02019                                  DBUS_TYPE_INVALID))
02020     _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
02021 
02022   sub->value_pos += 1;
02023 
02024   contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (contained_type, contained_type_start));
02025   
02026   if (!_dbus_string_insert_bytes (sub->value_str,
02027                                   sub->value_pos,
02028                                   _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment) - sub->value_pos,
02029                                   '\0'))
02030     _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
02031   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment);
02032 
02033   return TRUE;
02034 }
02035 
02036 static dbus_bool_t
02037 _dbus_type_writer_recurse_contained_len (DBusTypeWriter   *writer,
02038                                          int               container_type,
02039                                          const DBusString *contained_type,
02040                                          int               contained_type_start,
02041                                          int               contained_type_len,
02042                                          DBusTypeWriter   *sub,
02043                                          dbus_bool_t       is_array_append)
02044 {
02045   writer_recurse_init_and_check (writer, container_type, sub);
02046 
02047   switch (container_type)
02048     {
02049     case DBUS_TYPE_STRUCT:
02050       return writer_recurse_struct_or_dict_entry (writer,
02051                                                   DBUS_STRUCT_BEGIN_CHAR,
02052                                                   contained_type,
02053                                                   contained_type_start, contained_type_len,
02054                                                   sub);
02055       break;
02056     case DBUS_TYPE_DICT_ENTRY:
02057       return writer_recurse_struct_or_dict_entry (writer,
02058                                                   DBUS_DICT_ENTRY_BEGIN_CHAR,
02059                                                   contained_type,
02060                                                   contained_type_start, contained_type_len,
02061                                                   sub);
02062       break;
02063     case DBUS_TYPE_ARRAY:
02064       return writer_recurse_array (writer,
02065                                    contained_type, contained_type_start, contained_type_len,
02066                                    sub, is_array_append);
02067       break;
02068     case DBUS_TYPE_VARIANT:
02069       return writer_recurse_variant (writer,
02070                                      contained_type, contained_type_start, contained_type_len,
02071                                      sub);
02072       break;
02073     default:
02074       _dbus_assert_not_reached ("tried to recurse into type that doesn't support that");
02075       return FALSE;
02076       break;
02077     }
02078 }
02079 
02090 dbus_bool_t
02091 _dbus_type_writer_recurse (DBusTypeWriter   *writer,
02092                            int               container_type,
02093                            const DBusString *contained_type,
02094                            int               contained_type_start,
02095                            DBusTypeWriter   *sub)
02096 {
02097   int contained_type_len;
02098 
02099   if (contained_type)
02100     contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
02101   else
02102     contained_type_len = 0;
02103 
02104   return _dbus_type_writer_recurse_contained_len (writer, container_type,
02105                                                   contained_type,
02106                                                   contained_type_start,
02107                                                   contained_type_len,
02108                                                   sub,
02109                                                   FALSE);
02110 }
02111 
02124 dbus_bool_t
02125 _dbus_type_writer_append_array (DBusTypeWriter   *writer,
02126                                 const DBusString *contained_type,
02127                                 int               contained_type_start,
02128                                 DBusTypeWriter   *sub)
02129 {
02130   int contained_type_len;
02131 
02132   if (contained_type)
02133     contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
02134   else
02135     contained_type_len = 0;
02136 
02137   return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY,
02138                                                   contained_type,
02139                                                   contained_type_start,
02140                                                   contained_type_len,
02141                                                   sub,
02142                                                   TRUE);
02143 }
02144 
02145 static int
02146 writer_get_array_len (DBusTypeWriter *writer)
02147 {
02148   _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
02149   return writer->value_pos - writer->u.array.start_pos;
02150 }
02151 
02160 dbus_bool_t
02161 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
02162                              DBusTypeWriter *sub)
02163 {
02164   /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
02165   _dbus_assert (!writer->type_pos_is_expectation ||
02166                 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
02167 
02168 #if RECURSIVE_MARSHAL_WRITE_TRACE
02169   _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
02170                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
02171                  _dbus_type_to_string (writer->container_type));
02172   _dbus_verbose ("  type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
02173                  sub, sub->type_pos, sub->value_pos,
02174                  sub->type_pos_is_expectation,
02175                  _dbus_type_to_string (sub->container_type));
02176 #endif
02177 
02178   if (sub->container_type == DBUS_TYPE_STRUCT)
02179     {
02180       if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
02181         return FALSE;
02182     }
02183   else if (sub->container_type == DBUS_TYPE_DICT_ENTRY)
02184     {
02185       if (!write_or_verify_typecode (sub, DBUS_DICT_ENTRY_END_CHAR))
02186         return FALSE;
02187     }
02188   else if (sub->container_type == DBUS_TYPE_ARRAY)
02189     {
02190       if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */
02191         {
02192           dbus_uint32_t len;
02193 
02194           /* Set the array length */
02195           len = writer_get_array_len (sub);
02196           _dbus_marshal_set_uint32 (sub->value_str,
02197                                     sub->u.array.len_pos,
02198                                     len,
02199                                     sub->byte_order);
02200 #if RECURSIVE_MARSHAL_WRITE_TRACE
02201           _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",
02202                          len, sub->u.array.len_pos);
02203 #endif
02204         }
02205 #if RECURSIVE_MARSHAL_WRITE_TRACE
02206       else
02207         {
02208           _dbus_verbose ("    not filling in sub array len because we were disabled when we passed the len\n");
02209         }
02210 #endif
02211     }
02212 
02213   /* Now get type_pos right for the parent writer. Here are the cases:
02214    *
02215    * Cases !writer->type_pos_is_expectation:
02216    *   (in these cases we want to update to the new insertion point)
02217    *
02218    * - if we recursed into a STRUCT then we didn't know in advance
02219    *   what the types in the struct would be; so we have to fill in
02220    *   that information now.
02221    *       writer->type_pos = sub->type_pos
02222    *
02223    * - if we recursed into anything else, we knew the full array
02224    *   type, or knew the single typecode marking VARIANT, so
02225    *   writer->type_pos is already correct.
02226    *       writer->type_pos should remain as-is
02227    *
02228    * - note that the parent is never an ARRAY or VARIANT, if it were
02229    *   then type_pos_is_expectation would be TRUE. The parent
02230    *   is thus known to be a toplevel or STRUCT.
02231    *
02232    * Cases where writer->type_pos_is_expectation:
02233    *   (in these cases we want to update to next expected type to write)
02234    *
02235    * - we recursed from STRUCT into STRUCT and we didn't increment
02236    *   type_pos in the parent just to stay consistent with the
02237    *   !writer->type_pos_is_expectation case (though we could
02238    *   special-case this in recurse_struct instead if we wanted)
02239    *       writer->type_pos = sub->type_pos
02240    *
02241    * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
02242    *   for parent should have been incremented already
02243    *       writer->type_pos should remain as-is
02244    *
02245    * - we recursed from ARRAY into a sub-element, so type_pos in the
02246    *   parent is the element type and should remain the element type
02247    *   for the benefit of the next child element
02248    *       writer->type_pos should remain as-is
02249    *
02250    * - we recursed from VARIANT into its value, so type_pos in the
02251    *   parent makes no difference since there's only one value
02252    *   and we just finished writing it and won't use type_pos again
02253    *       writer->type_pos should remain as-is
02254    *
02255    *
02256    * For all these, DICT_ENTRY is the same as STRUCT
02257    */
02258   if (writer->type_str != NULL)
02259     {
02260       if ((sub->container_type == DBUS_TYPE_STRUCT ||
02261            sub->container_type == DBUS_TYPE_DICT_ENTRY) &&
02262           (writer->container_type == DBUS_TYPE_STRUCT ||
02263            writer->container_type == DBUS_TYPE_DICT_ENTRY ||
02264            writer->container_type == DBUS_TYPE_INVALID))
02265         {
02266           /* Advance the parent to the next struct field */
02267           writer->type_pos = sub->type_pos;
02268         }
02269     }
02270 
02271   writer->value_pos = sub->value_pos;
02272 
02273 #if RECURSIVE_MARSHAL_WRITE_TRACE
02274   _dbus_verbose ("  type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
02275                  writer, writer->type_pos, writer->value_pos,
02276                  writer->type_str ?
02277                  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
02278                  "unknown");
02279 #endif
02280 
02281   return TRUE;
02282 }
02283 
02292 dbus_bool_t
02293 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
02294                                int             type,
02295                                const void     *value)
02296 {
02297   dbus_bool_t retval;
02298 
02299   /* First ensure that our type realloc will succeed */
02300   if (!writer->type_pos_is_expectation && writer->type_str != NULL)
02301     {
02302       if (!_dbus_string_alloc_space (writer->type_str, 1))
02303         return FALSE;
02304     }
02305 
02306   retval = FALSE;
02307 
02308   if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
02309     goto out;
02310 
02311   if (!write_or_verify_typecode (writer, type))
02312     _dbus_assert_not_reached ("failed to write typecode after prealloc");
02313 
02314   retval = TRUE;
02315 
02316  out:
02317 #if RECURSIVE_MARSHAL_WRITE_TRACE
02318   _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",
02319                  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
02320                  writer->enabled);
02321 #endif
02322 
02323   return retval;
02324 }
02325 
02340 dbus_bool_t
02341 _dbus_type_writer_write_fixed_multi (DBusTypeWriter        *writer,
02342                                      int                    element_type,
02343                                      const void            *value,
02344                                      int                    n_elements)
02345 {
02346   _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
02347   _dbus_assert (dbus_type_is_fixed (element_type));
02348   _dbus_assert (writer->type_pos_is_expectation);
02349   _dbus_assert (n_elements >= 0);
02350 
02351 #if RECURSIVE_MARSHAL_WRITE_TRACE
02352   _dbus_verbose ("  type writer %p entering fixed multi type_pos = %d value_pos = %d n_elements %d\n",
02353                  writer, writer->type_pos, writer->value_pos, n_elements);
02354 #endif
02355 
02356   if (!write_or_verify_typecode (writer, element_type))
02357     _dbus_assert_not_reached ("OOM should not happen if only verifying typecode");
02358 
02359   if (writer->enabled)
02360     {
02361       if (!_dbus_marshal_write_fixed_multi (writer->value_str,
02362                                             writer->value_pos,
02363                                             element_type,
02364                                             value,
02365                                             n_elements,
02366                                             writer->byte_order,
02367                                             &writer->value_pos))
02368         return FALSE;
02369     }
02370 
02371 #if RECURSIVE_MARSHAL_WRITE_TRACE
02372   _dbus_verbose ("  type writer %p fixed multi written new type_pos = %d new value_pos = %d n_elements %d\n",
02373                  writer, writer->type_pos, writer->value_pos, n_elements);
02374 #endif
02375 
02376   return TRUE;
02377 }
02378 
02379 static void
02380 enable_if_after (DBusTypeWriter       *writer,
02381                  DBusTypeReader       *reader,
02382                  const DBusTypeReader *start_after)
02383 {
02384   if (start_after)
02385     {
02386       if (!writer->enabled && _dbus_type_reader_greater_than (reader, start_after))
02387         {
02388           _dbus_type_writer_set_enabled (writer, TRUE);
02389 #if RECURSIVE_MARSHAL_WRITE_TRACE
02390           _dbus_verbose ("ENABLING writer %p at %d because reader at value_pos %d is after reader at value_pos %d\n",
02391                          writer, writer->value_pos, reader->value_pos, start_after->value_pos);
02392 #endif
02393         }
02394 
02395       _dbus_assert ((!writer->enabled && !_dbus_type_reader_greater_than (reader, start_after)) ||
02396                     (writer->enabled && _dbus_type_reader_greater_than (reader, start_after)));
02397     }
02398 }
02399 
02400 static dbus_bool_t
02401 append_fixup (DBusList               **fixups,
02402               const DBusArrayLenFixup *fixup)
02403 {
02404   DBusArrayLenFixup *f;
02405 
02406   f = dbus_new (DBusArrayLenFixup, 1);
02407   if (f == NULL)
02408     return FALSE;
02409 
02410   *f = *fixup;
02411 
02412   if (!_dbus_list_append (fixups, f))
02413     {
02414       dbus_free (f);
02415       return FALSE;
02416     }
02417 
02418   _dbus_assert (f->len_pos_in_reader == fixup->len_pos_in_reader);
02419   _dbus_assert (f->new_len == fixup->new_len);
02420 
02421   return TRUE;
02422 }
02423 
02424 /* This loop is trivial if you ignore all the start_after nonsense,
02425  * so if you're trying to figure it out, start by ignoring that
02426  */
02427 static dbus_bool_t
02428 writer_write_reader_helper (DBusTypeWriter       *writer,
02429                             DBusTypeReader       *reader,
02430                             const DBusTypeReader *start_after,
02431                             int                   start_after_new_pos,
02432                             int                   start_after_new_len,
02433                             DBusList            **fixups,
02434                             dbus_bool_t           inside_start_after)
02435 {
02436   int current_type;
02437 
02438   while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
02439     {
02440       if (dbus_type_is_container (current_type))
02441         {
02442           DBusTypeReader subreader;
02443           DBusTypeWriter subwriter;
02444           const DBusString *sig_str;
02445           int sig_start;
02446           int sig_len;
02447           dbus_bool_t enabled_at_recurse;
02448           dbus_bool_t past_start_after;
02449           int reader_array_len_pos;
02450           int reader_array_start_pos;
02451           dbus_bool_t this_is_start_after;
02452 
02453           /* type_pos is checked since e.g. in a struct the struct
02454            * and its first field have the same value_pos.
02455            * type_str will differ in reader/start_after for variants
02456            * where type_str is inside the value_str
02457            */
02458           if (!inside_start_after && start_after &&
02459               reader->value_pos == start_after->value_pos &&
02460               reader->type_str == start_after->type_str &&
02461               reader->type_pos == start_after->type_pos)
02462             this_is_start_after = TRUE;
02463           else
02464             this_is_start_after = FALSE;
02465 
02466           _dbus_type_reader_recurse (reader, &subreader);
02467 
02468           if (current_type == DBUS_TYPE_ARRAY)
02469             {
02470               reader_array_len_pos = ARRAY_READER_LEN_POS (&subreader);
02471               reader_array_start_pos = subreader.u.array.start_pos;
02472             }
02473           else
02474             {
02475               /* quiet gcc */
02476               reader_array_len_pos = -1;
02477               reader_array_start_pos = -1;
02478             }
02479 
02480           _dbus_type_reader_get_signature (&subreader, &sig_str,
02481                                            &sig_start, &sig_len);
02482 
02483 #if RECURSIVE_MARSHAL_WRITE_TRACE
02484           _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",
02485                          _dbus_type_to_string (current_type),
02486                          reader->value_pos,
02487                          subreader.value_pos,
02488                          writer->value_pos,
02489                          start_after ? start_after->value_pos : -1,
02490                          _dbus_string_get_length (writer->value_str),
02491                          inside_start_after, this_is_start_after);
02492 #endif
02493 
02494           if (!inside_start_after && !this_is_start_after)
02495             enable_if_after (writer, &subreader, start_after);
02496           enabled_at_recurse = writer->enabled;
02497           if (!_dbus_type_writer_recurse_contained_len (writer, current_type,
02498                                                         sig_str, sig_start, sig_len,
02499                                                         &subwriter, FALSE))
02500             goto oom;
02501 
02502 #if RECURSIVE_MARSHAL_WRITE_TRACE
02503           _dbus_verbose ("recursed into subwriter at %d write target len %d\n",
02504                          subwriter.value_pos,
02505                          _dbus_string_get_length (subwriter.value_str));
02506 #endif
02507 
02508           if (!writer_write_reader_helper (&subwriter, &subreader, start_after,
02509                                            start_after_new_pos, start_after_new_len,
02510                                            fixups,
02511                                            inside_start_after ||
02512                                            this_is_start_after))
02513             goto oom;
02514 
02515 #if RECURSIVE_MARSHAL_WRITE_TRACE
02516           _dbus_verbose ("about to unrecurse from %s subreader at %d writer at %d subwriter at %d  write target len %d\n",
02517                          _dbus_type_to_string (current_type),
02518                          subreader.value_pos,
02519                          writer->value_pos,
02520                          subwriter.value_pos,
02521                          _dbus_string_get_length (writer->value_str));
02522 #endif
02523 
02524           if (!inside_start_after && !this_is_start_after)
02525             enable_if_after (writer, &subreader, start_after);
02526           past_start_after = writer->enabled;
02527           if (!_dbus_type_writer_unrecurse (writer, &subwriter))
02528             goto oom;
02529 
02530           /* If we weren't enabled when we recursed, we didn't
02531            * write an array len; if we passed start_after
02532            * somewhere inside the array, then we need to generate
02533            * a fixup.
02534            */
02535           if (start_after != NULL &&
02536               !enabled_at_recurse && past_start_after &&
02537               current_type == DBUS_TYPE_ARRAY &&
02538               fixups != NULL)
02539             {
02540               DBusArrayLenFixup fixup;
02541               int bytes_written_after_start_after;
02542               int bytes_before_start_after;
02543               int old_len;
02544 
02545               /* this subwriter access is moderately unkosher since we
02546                * already unrecursed, but it works as long as unrecurse
02547                * doesn't break us on purpose
02548                */
02549               bytes_written_after_start_after = writer_get_array_len (&subwriter);
02550 
02551               bytes_before_start_after =
02552                 start_after->value_pos - reader_array_start_pos;
02553 
02554               fixup.len_pos_in_reader = reader_array_len_pos;
02555               fixup.new_len =
02556                 bytes_before_start_after +
02557                 start_after_new_len +
02558                 bytes_written_after_start_after;
02559 
02560               _dbus_assert (_DBUS_ALIGN_VALUE (fixup.len_pos_in_reader, 4) ==
02561                             (unsigned) fixup.len_pos_in_reader);
02562 
02563               old_len = _dbus_unpack_uint32 (reader->byte_order,
02564                                              _dbus_string_get_const_data_len (reader->value_str,
02565                                                                               fixup.len_pos_in_reader, 4));
02566 
02567               if (old_len != fixup.new_len && !append_fixup (fixups, &fixup))
02568                 goto oom;
02569 
02570 #if RECURSIVE_MARSHAL_WRITE_TRACE
02571               _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",
02572                              fixup.len_pos_in_reader,
02573                              fixup.new_len,
02574                              reader_array_start_pos,
02575                              start_after->value_pos,
02576                              bytes_before_start_after,
02577                              start_after_new_len,
02578                              bytes_written_after_start_after);
02579 #endif
02580             }
02581         }
02582       else
02583         {
02584           DBusBasicValue val;
02585 
02586           _dbus_assert (dbus_type_is_basic (current_type));
02587 
02588 #if RECURSIVE_MARSHAL_WRITE_TRACE
02589           _dbus_verbose ("Reading basic value %s at %d\n",
02590                          _dbus_type_to_string (current_type),
02591                          reader->value_pos);
02592 #endif
02593 
02594           _dbus_type_reader_read_basic (reader, &val);
02595 
02596 #if RECURSIVE_MARSHAL_WRITE_TRACE
02597           _dbus_verbose ("Writing basic value %s at %d write target len %d inside_start_after = %d\n",
02598                          _dbus_type_to_string (current_type),
02599                          writer->value_pos,
02600                          _dbus_string_get_length (writer->value_str),
02601                          inside_start_after);
02602 #endif
02603           if (!inside_start_after)
02604             enable_if_after (writer, reader, start_after);
02605           if (!_dbus_type_writer_write_basic (writer, current_type, &val))
02606             goto oom;
02607 #if RECURSIVE_MARSHAL_WRITE_TRACE
02608           _dbus_verbose ("Wrote basic value %s, new value_pos %d write target len %d\n",
02609                          _dbus_type_to_string (current_type),
02610                          writer->value_pos,
02611                          _dbus_string_get_length (writer->value_str));
02612 #endif
02613         }
02614 
02615       _dbus_type_reader_next (reader);
02616     }
02617 
02618   return TRUE;
02619 
02620  oom:
02621   if (fixups)
02622     apply_and_free_fixups (fixups, NULL); /* NULL for reader to apply to */
02623 
02624   return FALSE;
02625 }
02626 
02658 dbus_bool_t
02659 _dbus_type_writer_write_reader_partial (DBusTypeWriter       *writer,
02660                                         DBusTypeReader       *reader,
02661                                         const DBusTypeReader *start_after,
02662                                         int                   start_after_new_pos,
02663                                         int                   start_after_new_len,
02664                                         DBusList            **fixups)
02665 {
02666   DBusTypeWriter orig;
02667   int orig_type_len;
02668   int orig_value_len;
02669   int new_bytes;
02670   int orig_enabled;
02671 
02672   orig = *writer;
02673   orig_type_len = _dbus_string_get_length (writer->type_str);
02674   orig_value_len = _dbus_string_get_length (writer->value_str);
02675   orig_enabled = writer->enabled;
02676 
02677   if (start_after)
02678     _dbus_type_writer_set_enabled (writer, FALSE);
02679 
02680   if (!writer_write_reader_helper (writer, reader, start_after,
02681                                    start_after_new_pos,
02682                                    start_after_new_len,
02683                                    fixups, FALSE))
02684     goto oom;
02685 
02686   _dbus_type_writer_set_enabled (writer, orig_enabled);
02687   return TRUE;
02688 
02689  oom:
02690   if (!writer->type_pos_is_expectation)
02691     {
02692       new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len;
02693       _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes);
02694     }
02695   new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len;
02696   _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes);
02697 
02698   *writer = orig;
02699 
02700   return FALSE;
02701 }
02702 
02712 dbus_bool_t
02713 _dbus_type_writer_write_reader (DBusTypeWriter       *writer,
02714                                 DBusTypeReader       *reader)
02715 {
02716   return _dbus_type_writer_write_reader_partial (writer, reader, NULL, 0, 0, NULL);
02717 }
02718 
02728 void
02729 _dbus_type_writer_set_enabled (DBusTypeWriter   *writer,
02730                                dbus_bool_t       enabled)
02731 {
02732   writer->enabled = enabled != FALSE;
02733 }
02734  /* end of DBusMarshal group */
02736 
02737 /* tests in dbus-marshal-recursive-util.c */

Generated on Mon Dec 14 22:26:11 2009 for D-Bus by  doxygen 1.4.7