Main Page | Modules | Data Structures | Directories | File List | Data Fields | Related Pages

dbus-message-builder.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-message-builder.c Build messages from text files for testing (internal to D-BUS implementation)
00003  * 
00004  * Copyright (C) 2003, 2004 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 #include <config.h>
00024 
00025 #ifdef DBUS_BUILD_TESTS
00026 
00027 #include "dbus-message-builder.h"
00028 #include "dbus-hash.h"
00029 #include "dbus-internals.h"
00030 #include "dbus-marshal.h"
00031 
00046 typedef struct
00047 {
00048   DBusString name; 
00049   int start;  
00050   int length; 
00051   int offset; 
00052   int endian; 
00053 } SavedLength;
00054 
00055 static void
00056 free_saved_length (void *data)
00057 {
00058   SavedLength *sl = data;
00059 
00060   if (sl == NULL)
00061     return; /* all hash free functions have to accept NULL */
00062   
00063   _dbus_string_free (&sl->name);
00064   dbus_free (sl);
00065 }
00066 
00067 static SavedLength*
00068 ensure_saved_length (DBusHashTable    *hash,
00069                      const DBusString *name)
00070 {
00071   SavedLength *sl;
00072   const char *s;
00073   
00074   s = _dbus_string_get_const_data (name);
00075 
00076   sl = _dbus_hash_table_lookup_string (hash, s);
00077   if (sl != NULL)
00078     return sl;
00079   
00080   sl = dbus_new0 (SavedLength, 1);
00081 
00082   if (!_dbus_string_init (&sl->name))
00083     {
00084       dbus_free (sl);
00085       return NULL;
00086     }
00087 
00088   if (!_dbus_string_copy (name, 0, &sl->name, 0))
00089     goto failed;
00090 
00091   s = _dbus_string_get_const_data (&sl->name);
00092 
00093   if (!_dbus_hash_table_insert_string (hash, (char*)s, sl))
00094     goto failed;
00095 
00096   sl->start = -1;
00097   sl->length = -1;
00098   sl->offset = -1;
00099   sl->endian = -1;
00100   
00101   return sl;
00102   
00103  failed:
00104   free_saved_length (sl);
00105   return NULL;
00106 }
00107 
00108 static dbus_bool_t
00109 save_start (DBusHashTable    *hash,
00110             const DBusString *name,
00111             int               start)
00112 {
00113   SavedLength *sl;
00114 
00115   sl = ensure_saved_length (hash, name);
00116 
00117   if (sl == NULL)
00118     return FALSE;
00119   else if (sl->start >= 0)
00120     {
00121       _dbus_warn ("Same START_LENGTH given twice\n");
00122       return FALSE;
00123     }
00124   else
00125     sl->start = start;
00126 
00127   return TRUE;
00128 }
00129 
00130 static dbus_bool_t
00131 save_length (DBusHashTable    *hash,
00132              const DBusString *name,
00133              int               length)
00134 {
00135   SavedLength *sl;
00136 
00137   sl = ensure_saved_length (hash, name);
00138 
00139   if (sl == NULL)
00140     return FALSE;
00141   else if (sl->length >= 0)
00142     {
00143       _dbus_warn ("Same END_LENGTH given twice\n");
00144       return FALSE;
00145     }
00146   else
00147     sl->length = length;
00148 
00149   return TRUE;
00150 }
00151 
00152 static dbus_bool_t
00153 save_offset (DBusHashTable    *hash,
00154              const DBusString *name,
00155              int               offset,
00156              int               endian)
00157 {
00158   SavedLength *sl;
00159 
00160   sl = ensure_saved_length (hash, name);
00161 
00162   if (sl == NULL)
00163     return FALSE;
00164   else if (sl->offset >= 0)
00165     {
00166       _dbus_warn ("Same LENGTH given twice\n");
00167       return FALSE;
00168     }
00169   else
00170     {
00171       sl->offset = offset;
00172       sl->endian = endian;
00173     }
00174 
00175   return TRUE;
00176 }
00177 
00179 #define SAVE_FOR_UNALIGN(str, boundary)                                 \
00180   int align_pad_start = _dbus_string_get_length (str);                  \
00181   int align_pad_end = _DBUS_ALIGN_VALUE (align_pad_start, (boundary))
00182 
00184 #define PERFORM_UNALIGN(str)                                    \
00185   if (unalign)                                                  \
00186     {                                                           \
00187       _dbus_string_delete ((str), align_pad_start,              \
00188                            align_pad_end - align_pad_start);    \
00189       unalign = FALSE;                                          \
00190     }
00191 
00192 
00193 static dbus_bool_t
00194 append_quoted_string (DBusString       *dest,
00195                       const DBusString *quoted,
00196                       int               start_pos,
00197                       int              *new_pos)
00198 {
00199   dbus_bool_t in_quotes = FALSE;
00200   int i;
00201 
00202   /* FIXME: We might want to add escaping in case we want to put '
00203    * characters in our strings.
00204    */
00205   
00206   i = start_pos;
00207   while (i < _dbus_string_get_length (quoted))
00208     {
00209       unsigned char b;
00210 
00211       b = _dbus_string_get_byte (quoted, i);
00212       
00213       if (in_quotes)
00214         {
00215           if (b == '\'')
00216             break;
00217           else
00218             {
00219               if (!_dbus_string_append_byte (dest, b))
00220                 return FALSE;
00221             }
00222         }
00223       else
00224         {
00225           if (b == '\'')
00226             in_quotes = TRUE;
00227           else if (b == ' ' || b == '\n' || b == '\t')
00228             break; /* end on whitespace if not quoted */
00229           else
00230             {
00231               if (!_dbus_string_append_byte (dest, b))
00232                 return FALSE;
00233             }
00234         }
00235       
00236       ++i;
00237     }
00238 
00239   if (new_pos)
00240     *new_pos = i;
00241   
00242   if (!_dbus_string_append_byte (dest, '\0'))
00243     return FALSE;
00244   return TRUE;
00245 }
00246 
00247 static dbus_bool_t
00248 append_saved_length (DBusString       *dest,
00249                      DBusHashTable    *length_hash,
00250                      const DBusString *name,
00251                      int               offset,
00252                      int               endian)
00253 {
00254   if (!save_offset (length_hash, name,
00255                     offset, endian))
00256     {
00257       _dbus_warn ("failed to save offset to LENGTH\n");
00258       return FALSE;
00259     }
00260   
00261   if (!_dbus_marshal_uint32 (dest, endian,
00262                              -1))
00263     {
00264       _dbus_warn ("failed to append a length\n");
00265       return FALSE;
00266     }
00267 
00268   return TRUE;
00269 }
00270 
00271 static int
00272 message_type_from_string (const DBusString *str,
00273                           int               start)
00274 {
00275   const char *s;
00276 
00277   s = _dbus_string_get_const_data_len (str, start,
00278                                        _dbus_string_get_length (str) - start);
00279 
00280   if (strncmp (s, "method_call", strlen ("method_call")) == 0)
00281     return DBUS_MESSAGE_TYPE_METHOD_CALL;
00282   else if (strncmp (s, "method_return", strlen ("method_return")) == 0)
00283     return DBUS_MESSAGE_TYPE_METHOD_RETURN;
00284   else if (strncmp (s, "signal", strlen ("signal")) == 0)
00285     return DBUS_MESSAGE_TYPE_SIGNAL;
00286   else if (strncmp (s, "error", strlen ("error")) == 0)
00287     return DBUS_MESSAGE_TYPE_ERROR;
00288   else if (strncmp (s, "invalid", strlen ("invalid")) == 0)
00289     return DBUS_MESSAGE_TYPE_INVALID;
00290   else
00291     return -1;
00292 }
00293 
00294 static dbus_bool_t
00295 append_string_field (DBusString *dest,
00296                      int         endian,
00297                      int         field,
00298                      int         type,
00299                      const char *value)
00300 {
00301   int len;
00302   
00303   if (!_dbus_string_append_byte (dest, field))
00304     {
00305       _dbus_warn ("couldn't append field name byte\n");
00306       return FALSE;
00307     }
00308   
00309   if (!_dbus_string_append_byte (dest, type))
00310     {
00311       _dbus_warn ("could not append typecode byte\n");
00312       return FALSE;
00313     }
00314 
00315   len = strlen (value);
00316 
00317   if (!_dbus_marshal_uint32 (dest, endian, len))
00318     {
00319       _dbus_warn ("couldn't append string length\n");
00320       return FALSE;
00321     }
00322   
00323   if (!_dbus_string_append (dest, value))
00324     {
00325       _dbus_warn ("couldn't append field value\n");
00326       return FALSE;
00327     }
00328 
00329   if (!_dbus_string_append_byte (dest, 0))
00330     {
00331       _dbus_warn ("couldn't append string nul term\n");
00332       return FALSE;
00333     }
00334 
00335   return TRUE;
00336 }
00337 
00338 static dbus_bool_t
00339 parse_basic_type (DBusString *src, char type,
00340                   DBusString *dest, dbus_bool_t *unalign,
00341                   int endian)
00342 {
00343   int align;
00344   int align_pad_start, align_pad_end;
00345   unsigned char data[16];
00346 
00347   switch (type)
00348     {
00349     case DBUS_TYPE_BYTE:
00350     case DBUS_TYPE_BOOLEAN:
00351       align = 1;
00352       break;
00353     case DBUS_TYPE_UINT32:
00354     case DBUS_TYPE_INT32:
00355       align = 4;
00356       break;
00357     case DBUS_TYPE_DOUBLE:
00358       align = 8;
00359       break;
00360     default:
00361       _dbus_assert_not_reached ("not a basic type");
00362       break;
00363     }
00364 
00365   align_pad_start = _dbus_string_get_length (dest);
00366   align_pad_end = _DBUS_ALIGN_VALUE (align_pad_start, align);
00367 
00368   _dbus_string_delete_first_word (src);
00369 
00370   if (!_dbus_string_parse_basic_type (src, type, 0, data, NULL))
00371     {
00372       _dbus_verbose ("failed to parse type '%c'", type);
00373       return FALSE;
00374     }
00375 
00376   if (!_dbus_marshal_basic_type (dest, type, data, endian))
00377     {
00378       _dbus_verbose ("failed to marshal type '%c'", type);
00379       return FALSE;
00380     }
00381 
00382   if (*unalign)
00383     {
00384       _dbus_string_delete (dest, align_pad_start,
00385                            align_pad_end - align_pad_start);
00386       *unalign = FALSE;
00387     }
00388 
00389   return TRUE;
00390 }
00391 
00392 static dbus_bool_t
00393 parse_basic_array (DBusString *src, char type,
00394                    DBusString *dest, dbus_bool_t *unalign,
00395                    int endian)
00396 {
00397   int array_align, elem_size;
00398   int i, len, allocated;
00399   unsigned char *values, b;
00400   int values_offset;
00401   int align_pad_start, align_pad_end;
00402   dbus_bool_t retval = FALSE;
00403 
00404   array_align = 4; /* length */
00405   switch (type)
00406     {
00407     case DBUS_TYPE_BYTE:
00408     case DBUS_TYPE_BOOLEAN:
00409       elem_size = 1;
00410       break;
00411     case DBUS_TYPE_UINT32:
00412     case DBUS_TYPE_INT32:
00413       elem_size = 4;
00414       break;
00415     case DBUS_TYPE_DOUBLE:
00416       array_align = 8;
00417       elem_size = 8;
00418       break;
00419     default:
00420       _dbus_assert_not_reached ("not a basic type");
00421       break;
00422     }
00423 
00424   align_pad_start = _dbus_string_get_length (dest);
00425   align_pad_end = _DBUS_ALIGN_VALUE (align_pad_start, array_align);
00426 
00427   len = 0;
00428   allocated = 2;
00429   values = NULL;
00430   values_offset = 0;
00431           
00432   _dbus_string_delete_first_word (src);
00433   _dbus_string_skip_blank (src, 0, &i);
00434   b = _dbus_string_get_byte (src, i++);
00435 
00436   if (b != '{')
00437     goto failed;
00438 
00439   while (i < _dbus_string_get_length (src))
00440     {
00441       _dbus_string_skip_blank (src, i, &i);
00442 
00443       if (!values || len == allocated - 1)
00444         {
00445           allocated *= 2;
00446           values = dbus_realloc (values, allocated * elem_size);
00447           if (!values)
00448             {
00449               _dbus_warn ("could not allocate memory for '%c' ARRAY\n", type);
00450               goto failed;
00451             }
00452         }
00453 
00454       if (!_dbus_string_parse_basic_type (src, type, i, values + values_offset, &i))
00455         {
00456           _dbus_warn ("could not parse integer element %d of '%c' ARRAY\n", len, type);
00457           goto failed;
00458         }
00459 
00460       values_offset += elem_size;
00461       len++;
00462               
00463       _dbus_string_skip_blank (src, i, &i);
00464 
00465       b = _dbus_string_get_byte (src, i++);
00466 
00467       if (b == '}')
00468         break;
00469       else if (b != ',')
00470         goto failed;
00471     }
00472 
00473   if (!_dbus_marshal_basic_type_array (dest, type, values, len, endian))
00474     {
00475       _dbus_warn ("failed to append '%c' ARRAY\n", type);
00476       goto failed;
00477     }
00478 
00479   if (*unalign)
00480     {
00481       _dbus_string_delete (dest, align_pad_start,
00482                            align_pad_end - align_pad_start);
00483       *unalign = FALSE;
00484     }
00485 
00486   retval = TRUE;
00487 
00488  failed:
00489   dbus_free (values);
00490   return retval;
00491 }
00492 
00493 static char
00494 lookup_basic_type (const DBusString *str, dbus_bool_t *is_array)
00495 {
00496   int i;
00497   char type = DBUS_TYPE_INVALID;
00498   static struct {
00499     const char *name;
00500     char        type;
00501   } name_to_type[] = {
00502     { "BYTE",    DBUS_TYPE_BYTE },
00503     { "BOOLEAN", DBUS_TYPE_BOOLEAN },
00504     { "INT32",   DBUS_TYPE_INT32 },
00505     { "UINT32",  DBUS_TYPE_UINT32 },
00506     { "DOUBLE",  DBUS_TYPE_DOUBLE }
00507   };
00508 
00509   for (i = 0; i < _DBUS_N_ELEMENTS(name_to_type); i++)
00510     {
00511       const char *name = name_to_type[i].name;
00512       if (_dbus_string_starts_with_c_str (str, name)) 
00513         {
00514           int offset = strlen (name);
00515           type = name_to_type[i].type;
00516           if (is_array)
00517             *is_array = _dbus_string_find (str, offset, "_ARRAY", NULL);
00518           break;
00519         }
00520     }
00521 
00522   return type;
00523 }
00524 
00576 dbus_bool_t
00577 _dbus_message_data_load (DBusString       *dest,
00578                          const DBusString *filename)
00579 {
00580   DBusString file;
00581   DBusError error;
00582   DBusString line;
00583   dbus_bool_t retval;
00584   int line_no;
00585   dbus_bool_t unalign;
00586   DBusHashTable *length_hash;
00587   int endian;
00588   DBusHashIter iter;
00589   char type;
00590   dbus_bool_t is_array;
00591   
00592   retval = FALSE;
00593   length_hash = NULL;
00594   
00595   if (!_dbus_string_init (&file))
00596     return FALSE;
00597 
00598   if (!_dbus_string_init (&line))
00599     {
00600       _dbus_string_free (&file);
00601       return FALSE;
00602     }
00603 
00604   _dbus_verbose ("Loading %s\n", _dbus_string_get_const_data (filename));
00605 
00606   dbus_error_init (&error);
00607   if (!_dbus_file_get_contents (&file, filename, &error))
00608     {
00609       _dbus_warn ("Getting contents of %s failed: %s\n",
00610                   _dbus_string_get_const_data (filename), error.message);
00611       dbus_error_free (&error);
00612       goto out;
00613     }
00614 
00615   length_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
00616                                       NULL,
00617                                       free_saved_length);
00618   if (length_hash == NULL)
00619     goto out;
00620   
00621   endian = DBUS_COMPILER_BYTE_ORDER;
00622   unalign = FALSE;
00623   line_no = 0;
00624  next_iteration:
00625   while (_dbus_string_pop_line (&file, &line))
00626     {
00627       dbus_bool_t just_set_unalign;
00628 
00629       just_set_unalign = FALSE;
00630       line_no += 1;
00631 
00632       _dbus_string_delete_leading_blanks (&line);
00633 
00634       if (_dbus_string_get_length (&line) == 0)
00635         {
00636           /* empty line */
00637           goto next_iteration;
00638         }
00639       else if (_dbus_string_starts_with_c_str (&line,
00640                                                "#"))
00641         {
00642           /* Ignore this comment */
00643           goto next_iteration;
00644         }
00645       else if (_dbus_string_starts_with_c_str (&line,
00646                                                "VALID_HEADER"))
00647         {
00648           int i;
00649           DBusString name;
00650           int message_type;
00651 
00652           if (_dbus_string_get_length (&line) < (int) strlen ("VALID_HEADER "))
00653             {
00654               _dbus_warn ("no args to VALID_HEADER\n");
00655               goto parse_failed;
00656             }
00657           
00658           if (!_dbus_string_append_byte (dest, endian))
00659             {
00660               _dbus_warn ("could not append endianness\n");
00661               goto parse_failed;
00662             }
00663 
00664           message_type = message_type_from_string (&line,
00665                                                    strlen ("VALID_HEADER "));
00666           if (message_type < 0)
00667             {
00668               _dbus_warn ("VALID_HEADER not followed by space then known message type\n");
00669               goto parse_failed;
00670             }
00671           
00672           if (!_dbus_string_append_byte (dest, message_type))
00673             {
00674               _dbus_warn ("could not append message type\n");
00675               goto parse_failed;
00676             }
00677           
00678           i = 0;
00679           while (i < 2)
00680             {
00681               if (!_dbus_string_append_byte (dest, '\0'))
00682                 {
00683                   _dbus_warn ("could not append nul pad\n");
00684                   goto parse_failed;
00685                 }
00686               ++i;
00687             }
00688 
00689           _dbus_string_init_const (&name, "Header");
00690           if (!append_saved_length (dest, length_hash,
00691                                     &name, _dbus_string_get_length (dest),
00692                                     endian))
00693             goto parse_failed;
00694 
00695           _dbus_string_init_const (&name, "Body");
00696           if (!append_saved_length (dest, length_hash,
00697                                     &name, _dbus_string_get_length (dest),
00698                                     endian))
00699             goto parse_failed;
00700           
00701           /* client serial */
00702           if (!_dbus_marshal_uint32 (dest, endian, 1))
00703             {
00704               _dbus_warn ("couldn't append client serial\n");
00705               goto parse_failed;
00706             }
00707         }
00708       else if (_dbus_string_starts_with_c_str (&line,
00709                                                "REQUIRED_FIELDS"))
00710         {
00711           if (!append_string_field (dest, endian,
00712                                     DBUS_HEADER_FIELD_INTERFACE,
00713                                     DBUS_TYPE_STRING,
00714                                     "org.freedesktop.BlahBlahInterface"))
00715             goto parse_failed;
00716           if (!append_string_field (dest, endian,
00717                                     DBUS_HEADER_FIELD_MEMBER,
00718                                     DBUS_TYPE_STRING,
00719                                     "BlahBlahMethod"))
00720             goto parse_failed;
00721           if (!append_string_field (dest, endian,
00722                                     DBUS_HEADER_FIELD_PATH,
00723                                     DBUS_TYPE_OBJECT_PATH,
00724                                     "/blah/blah/path"))
00725             goto parse_failed;
00726 
00727           /* FIXME later we'll validate this, and then it will break
00728            * and the .message files will have to include the right thing
00729            */
00730           if (!append_string_field (dest, endian,
00731                                     DBUS_HEADER_FIELD_SIGNATURE,
00732                                     DBUS_TYPE_STRING,
00733                                     "iii"))
00734             goto parse_failed;
00735         }
00736       else if (_dbus_string_starts_with_c_str (&line,
00737                                                "BIG_ENDIAN"))
00738         {
00739           endian = DBUS_BIG_ENDIAN;
00740         }
00741       else if (_dbus_string_starts_with_c_str (&line,
00742                                                "LITTLE_ENDIAN"))
00743         {
00744           endian = DBUS_LITTLE_ENDIAN;
00745         }
00746       else if (_dbus_string_starts_with_c_str (&line,
00747                                                "OPPOSITE_ENDIAN"))
00748         {
00749           if (endian == DBUS_BIG_ENDIAN)
00750             endian = DBUS_LITTLE_ENDIAN;
00751           else
00752             endian = DBUS_BIG_ENDIAN;
00753         }
00754       else if (_dbus_string_starts_with_c_str (&line,
00755                                                "ALIGN"))
00756         {
00757           long val;
00758           int end;
00759           int orig_len;
00760           
00761           _dbus_string_delete_first_word (&line);
00762 
00763           if (!_dbus_string_parse_int (&line, 0, &val, &end))
00764             {
00765               _dbus_warn ("Failed to parse integer\n");
00766               goto parse_failed;
00767             }
00768 
00769           if (val > 8)
00770             {
00771               _dbus_warn ("Aligning to %ld boundary is crack\n",
00772                           val);
00773               goto parse_failed;
00774             }
00775 
00776           orig_len = _dbus_string_get_length (dest);
00777           
00778           if (!_dbus_string_align_length (dest, val))
00779             goto parse_failed;
00780 
00781           if (_dbus_string_parse_int (&line, end, &val, NULL))
00782             {
00783               /* If there's an optional second int argument,
00784                * fill in align padding with that value
00785                */
00786               if (val < 0 || val > 255)
00787                 {
00788                   _dbus_warn ("can't fill align padding with %ld, must be a byte value\n", val);
00789                   goto parse_failed;
00790                 }
00791 
00792               end = orig_len;
00793               while (end < _dbus_string_get_length (dest))
00794                 {
00795                   _dbus_string_set_byte (dest, end, val);
00796                   ++end;
00797                 }
00798             }
00799         }
00800       else if (_dbus_string_starts_with_c_str (&line, "UNALIGN"))
00801         {
00802           unalign = TRUE;
00803           just_set_unalign = TRUE;
00804         }
00805       else if (_dbus_string_starts_with_c_str (&line, "CHOP"))
00806         {
00807           long val;
00808 
00809           /* FIXME if you CHOP the offset for a LENGTH
00810            * command, we segfault.
00811            */
00812           
00813           _dbus_string_delete_first_word (&line);
00814 
00815           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
00816             {
00817               _dbus_warn ("Failed to parse integer to chop\n");
00818               goto parse_failed;
00819             }
00820 
00821           if (val > _dbus_string_get_length (dest))
00822             {
00823               _dbus_warn ("Trying to chop %ld bytes but we only have %d\n",
00824                           val,
00825                           _dbus_string_get_length (dest));
00826               goto parse_failed;
00827             }
00828           
00829           _dbus_string_shorten (dest, val);
00830         }
00831       else if (_dbus_string_starts_with_c_str (&line,
00832                                                "START_LENGTH"))
00833         {
00834           _dbus_string_delete_first_word (&line);
00835 
00836           if (!save_start (length_hash, &line,
00837                            _dbus_string_get_length (dest)))
00838             {
00839               _dbus_warn ("failed to save length start\n");
00840               goto parse_failed;
00841             }
00842         }
00843       else if (_dbus_string_starts_with_c_str (&line,
00844                                                "END_LENGTH"))
00845         {
00846           _dbus_string_delete_first_word (&line);
00847 
00848           if (!save_length (length_hash, &line,
00849                             _dbus_string_get_length (dest)))
00850             {
00851               _dbus_warn ("failed to save length end\n");
00852               goto parse_failed;
00853             }
00854         }
00855       else if (_dbus_string_starts_with_c_str (&line,
00856                                                "LENGTH"))
00857         {
00858           SAVE_FOR_UNALIGN (dest, 4);
00859           
00860           _dbus_string_delete_first_word (&line);
00861 
00862           if (!append_saved_length (dest, length_hash,
00863                                     &line,
00864                                     unalign ? align_pad_start : align_pad_end,
00865                                     endian))
00866             {
00867               _dbus_warn ("failed to add LENGTH\n");
00868               goto parse_failed;
00869             }
00870 
00871           PERFORM_UNALIGN (dest);
00872         }
00873       else if (_dbus_string_starts_with_c_str (&line,
00874                                                "HEADER_FIELD"))
00875         {
00876           int field;
00877 
00878           _dbus_string_delete_first_word (&line);
00879 
00880           if (_dbus_string_starts_with_c_str (&line, "INVALID"))
00881             field = DBUS_HEADER_FIELD_INVALID;
00882           else if (_dbus_string_starts_with_c_str (&line, "PATH"))
00883             field = DBUS_HEADER_FIELD_PATH;
00884           else if (_dbus_string_starts_with_c_str (&line, "INTERFACE"))
00885             field = DBUS_HEADER_FIELD_INTERFACE;
00886           else if (_dbus_string_starts_with_c_str (&line, "MEMBER"))
00887             field = DBUS_HEADER_FIELD_MEMBER;
00888           else if (_dbus_string_starts_with_c_str (&line, "ERROR_NAME"))
00889             field = DBUS_HEADER_FIELD_ERROR_NAME;
00890           else if (_dbus_string_starts_with_c_str (&line, "REPLY_SERIAL"))
00891             field = DBUS_HEADER_FIELD_REPLY_SERIAL;
00892           else if (_dbus_string_starts_with_c_str (&line, "DESTINATION"))
00893             field = DBUS_HEADER_FIELD_DESTINATION;
00894           else if (_dbus_string_starts_with_c_str (&line, "SENDER"))
00895             field = DBUS_HEADER_FIELD_SENDER;
00896           else if (_dbus_string_starts_with_c_str (&line, "SIGNATURE"))
00897             field = DBUS_HEADER_FIELD_SIGNATURE;
00898           else if (_dbus_string_starts_with_c_str (&line, "UNKNOWN"))
00899             field = 22; /* random unknown header field */
00900           else
00901             {
00902               _dbus_warn ("%s is not a valid header field name\n",
00903                           _dbus_string_get_const_data (&line));
00904               goto parse_failed;
00905             }
00906 
00907           if (!_dbus_string_append_byte (dest, field))
00908             {
00909               _dbus_warn ("could not append header field name byte\n");
00910               goto parse_failed;
00911             }
00912         }
00913       else if (_dbus_string_starts_with_c_str (&line,
00914                                                "TYPE"))
00915         {
00916           int code;
00917           
00918           _dbus_string_delete_first_word (&line);          
00919 
00920           if (_dbus_string_starts_with_c_str (&line, "INVALID"))
00921             code = DBUS_TYPE_INVALID;
00922           else if (_dbus_string_starts_with_c_str (&line, "NIL"))
00923             code = DBUS_TYPE_NIL;
00924           else if ((code = lookup_basic_type (&line, NULL)) != DBUS_TYPE_INVALID)
00925             ;
00926           else if (_dbus_string_starts_with_c_str (&line, "STRING"))
00927             code = DBUS_TYPE_STRING;
00928           else if (_dbus_string_starts_with_c_str (&line, "OBJECT_PATH"))
00929             code = DBUS_TYPE_OBJECT_PATH;
00930           else if (_dbus_string_starts_with_c_str (&line, "CUSTOM"))
00931             code = DBUS_TYPE_CUSTOM;
00932           else if (_dbus_string_starts_with_c_str (&line, "ARRAY"))
00933             code = DBUS_TYPE_ARRAY;
00934           else if (_dbus_string_starts_with_c_str (&line, "DICT"))
00935             code = DBUS_TYPE_DICT;
00936           else
00937             {
00938               _dbus_warn ("%s is not a valid type name\n", _dbus_string_get_const_data (&line));
00939               goto parse_failed;
00940             }
00941 
00942           if (!_dbus_string_append_byte (dest, code))
00943             {
00944               _dbus_warn ("could not append typecode byte\n");
00945               goto parse_failed;
00946             }
00947         }
00948       else if (_dbus_string_starts_with_c_str (&line,
00949                                                "STRING_ARRAY"))
00950         {
00951           SAVE_FOR_UNALIGN (dest, 4);
00952           int i, len, allocated;
00953           char **values;
00954           char *val;
00955           DBusString val_str;
00956           unsigned char b;
00957 
00958           allocated = 4;
00959           values = dbus_new (char *, allocated);
00960           if (!values)
00961             {
00962               _dbus_warn ("could not allocate memory for STRING_ARRAY\n");
00963               goto parse_failed;
00964             }
00965           
00966           len = 0;
00967           
00968           _dbus_string_delete_first_word (&line);
00969           _dbus_string_skip_blank (&line, 0, &i);
00970           b = _dbus_string_get_byte (&line, i++);
00971 
00972           if (b != '{')
00973             goto parse_failed;
00974 
00975           _dbus_string_init (&val_str);
00976           while (i < _dbus_string_get_length (&line))
00977             {
00978               _dbus_string_skip_blank (&line, i, &i);
00979 
00980               if (!append_quoted_string (&val_str, &line, i, &i))
00981                 {
00982                   _dbus_warn ("could not parse quoted string for STRING_ARRAY\n");
00983                   goto parse_failed;
00984                 }
00985               i++;
00986 
00987               if (!_dbus_string_steal_data (&val_str, &val))
00988                 {
00989                   _dbus_warn ("could not allocate memory for STRING_ARRAY string\n");
00990                   goto parse_failed;
00991                 }
00992               
00993               values[len++] = val;
00994               if (len == allocated)
00995                 {
00996                   allocated *= 2;
00997                   values = dbus_realloc (values, allocated * sizeof (char *));
00998                   if (!values)
00999                     {
01000                       _dbus_warn ("could not allocate memory for STRING_ARRAY\n");
01001                       goto parse_failed;
01002                     }
01003                 }
01004               
01005               _dbus_string_skip_blank (&line, i, &i);
01006               
01007               b = _dbus_string_get_byte (&line, i++);
01008 
01009               if (b == '}')
01010                 break;
01011               else if (b != ',')
01012                 {
01013                   _dbus_warn ("missing comma when parsing STRING_ARRAY\n");
01014                   goto parse_failed;
01015                 }
01016             }
01017           _dbus_string_free (&val_str);
01018           
01019           if (!_dbus_marshal_string_array (dest, endian, (const char **)values, len))
01020             {
01021               _dbus_warn ("failed to append STRING_ARRAY\n");
01022               goto parse_failed;
01023             }
01024 
01025           values[len] = NULL;
01026           dbus_free_string_array (values);
01027           
01028           PERFORM_UNALIGN (dest);
01029         }
01030       else if (_dbus_string_starts_with_c_str (&line,
01031                                                "STRING"))
01032         {
01033           SAVE_FOR_UNALIGN (dest, 4);
01034           int size_offset;
01035           int old_len;
01036           
01037           _dbus_string_delete_first_word (&line);
01038 
01039           size_offset = _dbus_string_get_length (dest);
01040           size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
01041           if (!_dbus_marshal_uint32 (dest, endian, 0))
01042             {
01043               _dbus_warn ("Failed to append string size\n");
01044               goto parse_failed;
01045             }
01046 
01047           old_len = _dbus_string_get_length (dest);
01048           if (!append_quoted_string (dest, &line, 0, NULL))
01049             {
01050               _dbus_warn ("Failed to append quoted string\n");
01051               goto parse_failed;
01052             }
01053 
01054           _dbus_marshal_set_uint32 (dest, endian, size_offset,
01055                                     /* subtract 1 for nul */
01056                                     _dbus_string_get_length (dest) - old_len - 1);
01057           
01058           PERFORM_UNALIGN (dest);
01059         }
01060       else if ((type = lookup_basic_type (&line, &is_array)) != DBUS_TYPE_INVALID)
01061         {
01062           if (is_array)
01063             {
01064               if (!parse_basic_array (&line, type, dest, &unalign, endian))
01065                 goto parse_failed;
01066             }
01067           else
01068             {
01069               if (!parse_basic_type (&line, type, dest, &unalign, endian))
01070                 goto parse_failed;
01071             }
01072         }
01073       else if (_dbus_string_starts_with_c_str (&line,
01074                                               "OBJECT_PATH"))
01075         {
01076           SAVE_FOR_UNALIGN (dest, 4);
01077           int size_offset;
01078           int old_len;
01079           
01080           _dbus_string_delete_first_word (&line);
01081           
01082           size_offset = _dbus_string_get_length (dest);
01083           size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
01084           if (!_dbus_marshal_uint32 (dest, endian, 0))
01085             {
01086               _dbus_warn ("Failed to append string size\n");
01087               goto parse_failed;
01088             }
01089 
01090           old_len = _dbus_string_get_length (dest);
01091           if (!append_quoted_string (dest, &line, 0, NULL))
01092             {
01093               _dbus_warn ("Failed to append quoted string\n");
01094               goto parse_failed;
01095             }
01096 
01097           _dbus_marshal_set_uint32 (dest, endian, size_offset,
01098                                     /* subtract 1 for nul */
01099                                     _dbus_string_get_length (dest) - old_len - 1);
01100           
01101           PERFORM_UNALIGN (dest);
01102         }      
01103       else
01104         goto parse_failed;
01105       
01106       if (!just_set_unalign && unalign)
01107         {
01108           _dbus_warn ("UNALIGN prior to something that isn't aligned\n");
01109           goto parse_failed;
01110         }
01111 
01112       goto next_iteration; /* skip parse_failed */
01113       
01114     parse_failed:
01115       {
01116         _dbus_warn ("couldn't process line %d \"%s\"\n",
01117                     line_no, _dbus_string_get_const_data (&line));
01118         goto out;
01119       }
01120     }
01121 
01122   _dbus_hash_iter_init (length_hash, &iter);
01123   while (_dbus_hash_iter_next (&iter))
01124     {
01125       SavedLength *sl = _dbus_hash_iter_get_value (&iter);
01126       const char *s;
01127 
01128       s = _dbus_string_get_const_data (&sl->name);
01129       
01130       if (sl->length < 0)
01131         {
01132           _dbus_warn ("Used LENGTH %s but never did END_LENGTH\n",
01133                       s);
01134           goto out;
01135         }
01136       else if (sl->offset < 0)
01137         {
01138           _dbus_warn ("Did END_LENGTH %s but never used LENGTH\n",
01139                       s);
01140           goto out;
01141         }
01142       else
01143         {
01144           if (sl->start < 0)
01145             sl->start = 0;
01146           
01147           _dbus_verbose ("Filling in length %s endian = %d offset = %d start = %d length = %d\n",
01148                          s, sl->endian, sl->offset, sl->start, sl->length);
01149           _dbus_marshal_set_int32 (dest,
01150                                    sl->endian,
01151                                    sl->offset,
01152                                    sl->length - sl->start);
01153         }
01154 
01155       _dbus_hash_iter_remove_entry (&iter);
01156     }
01157   
01158   retval = TRUE;
01159 
01160   _dbus_verbose_bytes_of_string (dest, 0, _dbus_string_get_length (dest));
01161   
01162  out:
01163   if (length_hash != NULL)
01164     _dbus_hash_table_unref (length_hash);
01165   
01166   _dbus_string_free (&file);
01167   _dbus_string_free (&line);
01168   return retval;
01169 }
01170 
01172 #endif /* DBUS_BUILD_TESTS */

Generated on Thu Aug 11 21:11:13 2005 for D-BUS by  doxygen 1.4.0