Main Page | Modules | Namespace List | Class Hierarchy | Data Structures | Directories | File List | Namespace Members | Data Fields | Related Pages

dbus-marshal-recursive.c

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

Generated on Tue Sep 13 01:28:07 2005 for D-BUS by  doxygen 1.4.4