2003-02-24 Anders Carlsson <andersca@codefactory.se>
[platform/upstream/dbus.git] / dbus / dbus-message-builder.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message-builder.c Build messages from text files for testing (internal to D-BUS implementation)
3  * 
4  * Copyright (C) 2003 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include <config.h>
24
25 #ifdef DBUS_BUILD_TESTS
26
27 #include "dbus-message-builder.h"
28 #include "dbus-hash.h"
29 #include "dbus-internals.h"
30 #include "dbus-marshal.h"
31
32 /**
33  * @defgroup DBusMessageBuilder code for loading test message data
34  * @ingroup  DBusInternals
35  * @brief code for loading up test data for unit tests
36  *
37  * The code in here is used for unit testing, it loads
38  * up message data from a description in a file.
39  *
40  * @{
41  */
42
43 typedef struct
44 {
45   DBusString name;
46   int start;  /**< Calculate length since here */
47   int length; /**< length to write */
48   int offset; /**< where to write it into the data */
49   int endian; /**< endianness to write with */
50 } SavedLength;
51
52 static void
53 free_saved_length (void *data)
54 {
55   SavedLength *sl = data;
56
57   if (sl == NULL)
58     return; /* all hash free functions have to accept NULL */
59   
60   _dbus_string_free (&sl->name);
61   dbus_free (sl);
62 }
63
64 static SavedLength*
65 ensure_saved_length (DBusHashTable    *hash,
66                      const DBusString *name)
67 {
68   SavedLength *sl;
69   const char *s;
70
71   _dbus_string_get_const_data (name, &s);
72
73   sl = _dbus_hash_table_lookup_string (hash, s);
74   if (sl != NULL)
75     return sl;
76   
77   sl = dbus_new0 (SavedLength, 1);
78
79   if (!_dbus_string_init (&sl->name, _DBUS_INT_MAX))
80     {
81       dbus_free (sl);
82       return NULL;
83     }
84
85   if (!_dbus_string_copy (name, 0, &sl->name, 0))
86     goto failed;
87
88   _dbus_string_get_const_data (&sl->name, &s);
89
90   if (!_dbus_hash_table_insert_string (hash, (char*)s, sl))
91     goto failed;
92
93   sl->start = -1;
94   sl->length = -1;
95   sl->offset = -1;
96   sl->endian = -1;
97   
98   return sl;
99   
100  failed:
101   free_saved_length (sl);
102   return NULL;
103 }
104
105 static dbus_bool_t
106 save_start (DBusHashTable    *hash,
107             const DBusString *name,
108             int               start)
109 {
110   SavedLength *sl;
111
112   sl = ensure_saved_length (hash, name);
113
114   if (sl == NULL)
115     return FALSE;
116   else if (sl->start >= 0)
117     {
118       _dbus_warn ("Same START_LENGTH given twice\n");
119       return FALSE;
120     }
121   else
122     sl->start = start;
123
124   return TRUE;
125 }
126
127 static dbus_bool_t
128 save_length (DBusHashTable    *hash,
129              const DBusString *name,
130              int               length)
131 {
132   SavedLength *sl;
133
134   sl = ensure_saved_length (hash, name);
135
136   if (sl == NULL)
137     return FALSE;
138   else if (sl->length >= 0)
139     {
140       _dbus_warn ("Same END_LENGTH given twice\n");
141       return FALSE;
142     }
143   else
144     sl->length = length;
145
146   return TRUE;
147 }
148
149 static dbus_bool_t
150 save_offset (DBusHashTable    *hash,
151              const DBusString *name,
152              int               offset,
153              int               endian)
154 {
155   SavedLength *sl;
156
157   sl = ensure_saved_length (hash, name);
158
159   if (sl == NULL)
160     return FALSE;
161   else if (sl->offset >= 0)
162     {
163       _dbus_warn ("Same LENGTH given twice\n");
164       return FALSE;
165     }
166   else
167     {
168       sl->offset = offset;
169       sl->endian = endian;
170     }
171
172   return TRUE;
173 }
174
175 /** Saves the segment to delete in order to unalign the next item */
176 #define SAVE_FOR_UNALIGN(str, boundary)                                 \
177   int align_pad_start = _dbus_string_get_length (str);                  \
178   int align_pad_end = _DBUS_ALIGN_VALUE (align_pad_start, (boundary))
179
180 /** Deletes the alignment padding */
181 #define PERFORM_UNALIGN(str)                                    \
182   if (unalign)                                                  \
183     {                                                           \
184       _dbus_string_delete ((str), align_pad_start,              \
185                            align_pad_end - align_pad_start);    \
186       unalign = FALSE;                                          \
187     }
188
189
190 static dbus_bool_t
191 append_quoted_string (DBusString       *dest,
192                       const DBusString *quoted,
193                       int               start_pos,
194                       int              *new_pos)
195 {
196   dbus_bool_t in_quotes = FALSE;
197   int i;
198
199   /* FIXME: We might want to add escaping in case we want to put '
200    * characters in our strings.
201    */
202   
203   i = start_pos;
204   while (i < _dbus_string_get_length (quoted))
205     {
206       unsigned char b;
207
208       b = _dbus_string_get_byte (quoted, i);
209       
210       if (in_quotes)
211         {
212           if (b == '\'')
213             break;
214           else
215             {
216               if (!_dbus_string_append_byte (dest, b))
217                 return FALSE;
218             }
219         }
220       else
221         {
222           if (b == '\'')
223             in_quotes = TRUE;
224           else if (b == ' ' || b == '\n' || b == '\t')
225             break; /* end on whitespace if not quoted */
226           else
227             {
228               if (!_dbus_string_append_byte (dest, b))
229                 return FALSE;
230             }
231         }
232       
233       ++i;
234     }
235
236   if (new_pos)
237     *new_pos = i;
238   
239   if (!_dbus_string_append_byte (dest, '\0'))
240     return FALSE;
241   return TRUE;
242 }
243
244 static dbus_bool_t
245 append_saved_length (DBusString       *dest,
246                      DBusHashTable    *length_hash,
247                      const DBusString *name,
248                      int               offset,
249                      int               endian)
250 {
251   if (!save_offset (length_hash, name,
252                     offset, endian))
253     {
254       _dbus_warn ("failed to save offset to LENGTH\n");
255       return FALSE;
256     }
257   
258   if (!_dbus_marshal_uint32 (dest, endian,
259                              -1))
260     {
261       _dbus_warn ("failed to append a length\n");
262       return FALSE;
263     }
264
265   return TRUE;
266 }
267
268 /**
269  * Reads the given filename, which should be in "message description
270  * language" (look at some examples), and builds up the message data
271  * from it.  The message data may be invalid, or valid.
272  *
273  * The parser isn't very strict, it's just a hack for test programs.
274  * 
275  * The file format is:
276  * @code
277  *   VALID_HEADER normal header; byte order, padding, header len, body len, serial
278  *   BIG_ENDIAN switch to big endian
279  *   LITTLE_ENDIAN switch to little endian
280  *   OPPOSITE_ENDIAN switch to opposite endian
281  *   ALIGN <N> aligns to the given value
282  *   UNALIGN skips alignment for the next marshal
283  *   BYTE <N> inserts the given integer in [0,255] or char in 'a' format
284  *   START_LENGTH <name> marks the start of a length to measure
285  *   END_LENGTH <name> records the length since START_LENGTH under the given name
286  *                     (or if no START_LENGTH, absolute length)
287  *   LENGTH <name> inserts the saved length of the same name
288  *   CHOP <N> chops last N bytes off the data
289  *   FIELD_NAME <abcd> inserts 4-byte field name
290  *   TYPE <typename> inserts a typecode byte 
291  * @endcode
292  * 
293  * Following commands insert aligned data unless
294  * preceded by "UNALIGN":
295  * @code
296  *   INT32 <N> marshals an INT32
297  *   UINT32 <N> marshals a UINT32
298  *   DOUBLE <N> marshals a double
299  *   STRING 'Foo' marshals a string
300  *   INT32_ARRAY { 3, 4, 5, 6} marshals an INT32 array
301  *   UINT32_ARRAY { 3, 4, 5, 6} marshals an UINT32 array
302  *   DOUBLE_ARRAY { 1.0, 2.0, 3.0, 4.0} marshals a DOUBLE array  
303  * @endcode
304  *
305  * @todo add support for array types INT32_ARRAY { 3, 4, 5, 6 }
306  * and so forth.
307  * 
308  * @param dest the string to append the message data to
309  * @param filename the filename to load
310  * @returns #TRUE on success
311  */
312 dbus_bool_t
313 _dbus_message_data_load (DBusString       *dest,
314                          const DBusString *filename)
315 {
316   DBusString file;
317   DBusResultCode result;
318   DBusString line;
319   dbus_bool_t retval;
320   int line_no;
321   dbus_bool_t unalign;
322   DBusHashTable *length_hash;
323   int endian;
324   DBusHashIter iter;
325   
326   retval = FALSE;
327   length_hash = NULL;
328   
329   if (!_dbus_string_init (&file, _DBUS_INT_MAX))
330     return FALSE;
331
332   if (!_dbus_string_init (&line, _DBUS_INT_MAX))
333     {
334       _dbus_string_free (&file);
335       return FALSE;
336     }
337   
338   if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS)
339     {
340       const char *s;
341       _dbus_string_get_const_data (filename, &s);
342       _dbus_warn ("Getting contents of %s failed: %s\n",
343                   s, dbus_result_to_string (result));
344                      
345       goto out;
346     }
347
348   length_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
349                                       NULL,
350                                       free_saved_length);
351   if (length_hash == NULL)
352     goto out;
353   
354   endian = DBUS_COMPILER_BYTE_ORDER;
355   unalign = FALSE;
356   line_no = 0;
357  next_iteration:
358   while (_dbus_string_pop_line (&file, &line))
359     {
360       dbus_bool_t just_set_unalign;
361
362       just_set_unalign = FALSE;
363       line_no += 1;
364
365       _dbus_string_delete_leading_blanks (&line);
366
367       if (_dbus_string_get_length (&line) == 0)
368         {
369           /* empty line */
370           goto next_iteration;
371         }
372       else if (_dbus_string_starts_with_c_str (&line,
373                                                "#"))
374         {
375           /* Ignore this comment */
376           goto next_iteration;
377         }
378       else if (_dbus_string_starts_with_c_str (&line,
379                                                "VALID_HEADER"))
380         {
381           int i;
382           DBusString name;
383           
384           if (!_dbus_string_append_byte (dest, endian))
385             {
386               _dbus_warn ("could not append endianness\n");
387               goto parse_failed;
388             }
389
390           i = 0;
391           while (i < 3)
392             {
393               if (!_dbus_string_append_byte (dest, '\0'))
394                 {
395                   _dbus_warn ("could not append nul pad\n");
396                   goto parse_failed;
397                 }
398               ++i;
399             }
400
401           _dbus_string_init_const (&name, "Header");
402           if (!append_saved_length (dest, length_hash,
403                                     &name, _dbus_string_get_length (dest),
404                                     endian))
405             goto parse_failed;
406
407           _dbus_string_init_const (&name, "Body");
408           if (!append_saved_length (dest, length_hash,
409                                     &name, _dbus_string_get_length (dest),
410                                     endian))
411             goto parse_failed;
412           
413           /* client serial */
414           if (!_dbus_marshal_int32 (dest, endian, 1))
415             {
416               _dbus_warn ("couldn't append client serial\n");
417               goto parse_failed;
418             }
419         }
420       else if (_dbus_string_starts_with_c_str (&line,
421                                                "BIG_ENDIAN"))
422         {
423           endian = DBUS_BIG_ENDIAN;
424         }
425       else if (_dbus_string_starts_with_c_str (&line,
426                                                "LITTLE_ENDIAN"))
427         {
428           endian = DBUS_LITTLE_ENDIAN;
429         }
430       else if (_dbus_string_starts_with_c_str (&line,
431                                                "OPPOSITE_ENDIAN"))
432         {
433           if (endian == DBUS_BIG_ENDIAN)
434             endian = DBUS_LITTLE_ENDIAN;
435           else
436             endian = DBUS_BIG_ENDIAN;
437         }
438       else if (_dbus_string_starts_with_c_str (&line,
439                                                "ALIGN"))
440         {
441           long val;
442
443           _dbus_string_delete_first_word (&line);
444
445           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
446             {
447               _dbus_warn ("Failed to parse integer\n");
448               goto parse_failed;
449             }
450
451           if (val > 16)
452             {
453               _dbus_warn ("Aligning to %ld boundary is crack\n",
454                           val);
455               goto parse_failed;
456             }
457           
458           if (!_dbus_string_align_length (dest, val))
459             goto parse_failed;
460         }
461       else if (_dbus_string_starts_with_c_str (&line, "UNALIGN"))
462         {
463           unalign = TRUE;
464           just_set_unalign = TRUE;
465         }
466       else if (_dbus_string_starts_with_c_str (&line, "CHOP"))
467         {
468           long val;
469
470           /* FIXME if you CHOP the offset for a LENGTH
471            * command, we segfault.
472            */
473           
474           _dbus_string_delete_first_word (&line);
475
476           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
477             {
478               _dbus_warn ("Failed to parse integer to chop\n");
479               goto parse_failed;
480             }
481
482           if (val > _dbus_string_get_length (dest))
483             {
484               _dbus_warn ("Trying to chop %ld bytes but we only have %d\n",
485                           val,
486                           _dbus_string_get_length (dest));
487               goto parse_failed;
488             }
489           
490           _dbus_string_shorten (dest, val);
491         }
492       else if (_dbus_string_starts_with_c_str (&line, "BYTE"))
493         {
494           unsigned char the_byte;
495           
496           _dbus_string_delete_first_word (&line);
497
498           if (_dbus_string_equal_c_str (&line, "'\\''"))
499             the_byte = '\'';
500           else if (_dbus_string_get_byte (&line, 0) == '\'' &&
501                    _dbus_string_get_length (&line) >= 3 &&
502                    _dbus_string_get_byte (&line, 2) == '\'')
503             the_byte = _dbus_string_get_byte (&line, 1);
504           else
505             {
506               long val;
507               if (!_dbus_string_parse_int (&line, 0, &val, NULL))
508                 {
509                   _dbus_warn ("Failed to parse integer for BYTE\n");
510                   goto parse_failed;
511                 }
512
513               if (val > 255)
514                 {
515                   _dbus_warn ("A byte must be in range 0-255 not %ld\n",
516                                  val);
517                   goto parse_failed;
518                 }
519               the_byte = (unsigned char) val;
520             }
521
522           _dbus_string_append_byte (dest, the_byte);
523         }
524       else if (_dbus_string_starts_with_c_str (&line,
525                                                "START_LENGTH"))
526         {
527           _dbus_string_delete_first_word (&line);
528
529           if (!save_start (length_hash, &line,
530                            _dbus_string_get_length (dest)))
531             {
532               _dbus_warn ("failed to save length start\n");
533               goto parse_failed;
534             }
535         }
536       else if (_dbus_string_starts_with_c_str (&line,
537                                                "END_LENGTH"))
538         {
539           _dbus_string_delete_first_word (&line);
540
541           if (!save_length (length_hash, &line,
542                             _dbus_string_get_length (dest)))
543             {
544               _dbus_warn ("failed to save length end\n");
545               goto parse_failed;
546             }
547         }
548       else if (_dbus_string_starts_with_c_str (&line,
549                                                "LENGTH"))
550         {
551           SAVE_FOR_UNALIGN (dest, 4);
552           
553           _dbus_string_delete_first_word (&line);
554
555           if (!append_saved_length (dest, length_hash,
556                                     &line,
557                                     unalign ? align_pad_start : align_pad_end,
558                                     endian))
559             {
560               _dbus_warn ("failed to add LENGTH\n");
561               goto parse_failed;
562             }
563
564           PERFORM_UNALIGN (dest);
565         }
566       else if (_dbus_string_starts_with_c_str (&line,
567                                                "FIELD_NAME"))
568         {
569           _dbus_string_delete_first_word (&line);
570
571           if (_dbus_string_get_length (&line) != 4)
572             {
573               const char *s;
574               _dbus_string_get_const_data (&line, &s);
575               _dbus_warn ("Field name must be four characters not \"%s\"\n",
576                              s);
577               goto parse_failed;
578             }
579
580           if (unalign)
581             unalign = FALSE;
582           else
583             _dbus_string_align_length (dest, 4);
584           
585           if (!_dbus_string_copy (&line, 0, dest,
586                                   _dbus_string_get_length (dest)))
587             goto parse_failed;
588         }
589       else if (_dbus_string_starts_with_c_str (&line,
590                                                "TYPE"))
591         {
592           int code;
593           
594           _dbus_string_delete_first_word (&line);          
595
596           if (_dbus_string_starts_with_c_str (&line, "INVALID"))
597             code = DBUS_TYPE_INVALID;
598           else if (_dbus_string_starts_with_c_str (&line, "NIL"))
599             code = DBUS_TYPE_NIL;
600           else if (_dbus_string_starts_with_c_str (&line, "BOOLEAN_ARRAY"))
601             code = DBUS_TYPE_BOOLEAN_ARRAY;
602           else if (_dbus_string_starts_with_c_str (&line, "INT32_ARRAY"))
603             code = DBUS_TYPE_INT32_ARRAY;
604           else if (_dbus_string_starts_with_c_str (&line, "UINT32_ARRAY"))
605             code = DBUS_TYPE_UINT32_ARRAY;
606           else if (_dbus_string_starts_with_c_str (&line, "DOUBLE_ARRAY"))
607             code = DBUS_TYPE_DOUBLE_ARRAY;
608           else if (_dbus_string_starts_with_c_str (&line, "BYTE_ARRAY"))
609             code = DBUS_TYPE_BYTE_ARRAY;
610           else if (_dbus_string_starts_with_c_str (&line, "STRING_ARRAY"))
611             code = DBUS_TYPE_STRING_ARRAY;
612           else if (_dbus_string_starts_with_c_str (&line, "BOOLEAN"))
613             code = DBUS_TYPE_BOOLEAN;
614           else if (_dbus_string_starts_with_c_str (&line, "INT32"))
615             code = DBUS_TYPE_INT32;
616           else if (_dbus_string_starts_with_c_str (&line, "UINT32"))
617             code = DBUS_TYPE_UINT32;
618           else if (_dbus_string_starts_with_c_str (&line, "DOUBLE"))
619             code = DBUS_TYPE_DOUBLE;
620           else if (_dbus_string_starts_with_c_str (&line, "STRING"))
621             code = DBUS_TYPE_STRING;
622           else
623             {
624               const char *s;
625               _dbus_string_get_const_data (&line, &s);
626               _dbus_warn ("%s is not a valid type name\n", s);
627               goto parse_failed;
628             }
629
630           if (!_dbus_string_append_byte (dest, code))
631             {
632               _dbus_warn ("could not append typecode byte\n");
633               goto parse_failed;
634             }
635         }
636       else if (_dbus_string_starts_with_c_str (&line,
637                                                "BOOLEAN_ARRAY"))
638         {
639           SAVE_FOR_UNALIGN (dest, 4);
640           int i, len, allocated;
641           unsigned char *values;
642           unsigned char b, val;
643
644           allocated = 4;
645           values = dbus_new (unsigned char, allocated);
646           if (!values)
647             {
648               _dbus_warn ("could not allocate memory for BOOLEAN_ARRAY\n");
649               goto parse_failed;
650             }
651
652           len = 0;
653           
654           _dbus_string_delete_first_word (&line);
655           _dbus_string_skip_blank (&line, 0, &i);
656           b = _dbus_string_get_byte (&line, i++);
657           
658           if (b != '{')
659             goto parse_failed;
660
661           while (i < _dbus_string_get_length (&line))
662             {
663               _dbus_string_skip_blank (&line, i, &i);         
664               
665               if (_dbus_string_find_to (&line, i, i + 5,
666                                         "false", NULL))
667                 {
668                   i += 5;
669                   val = TRUE;
670                 }
671               else if (_dbus_string_find_to (&line, i, i + 4,
672                                              "true", NULL))
673                 {
674                   i += 4;
675                   val = FALSE;
676                 }
677               else
678                 {
679                   _dbus_warn ("could not parse BOOLEAN_ARRAY\n");
680                   goto parse_failed;
681                 }
682
683               values[len++] = val;
684               if (len == allocated)
685                 {
686                   allocated *= 2;
687                   values = dbus_realloc (values, allocated * sizeof (unsigned char));
688                   if (!values)
689                     {
690                       _dbus_warn ("could not allocate memory for BOOLEAN_ARRAY\n");
691                       goto parse_failed;
692                     }
693                 }
694               
695               _dbus_string_skip_blank (&line, i, &i);
696               
697               b = _dbus_string_get_byte (&line, i++);
698
699               if (b == '}')
700                 break;
701               else if (b != ',')
702                 goto parse_failed;
703             }
704
705           if (!_dbus_marshal_int32 (dest, endian, len) ||
706               !_dbus_string_append_len (dest, values, len))
707             {
708               _dbus_warn ("failed to append BOOLEAN_ARRAY\n");
709               goto parse_failed;
710             }
711           dbus_free (values);
712           
713           PERFORM_UNALIGN (dest);
714         }
715       else if (_dbus_string_starts_with_c_str (&line,
716                                                "INT32_ARRAY"))
717         {
718           SAVE_FOR_UNALIGN (dest, 4);
719           int i, len, allocated;
720           dbus_int32_t *values;
721           long val;
722           unsigned char b;
723
724           allocated = 4;
725           values = dbus_new (dbus_int32_t, allocated);
726           if (!values)
727             {
728               _dbus_warn ("could not allocate memory for INT32_ARRAY\n");
729               goto parse_failed;
730             }
731           
732           len = 0;
733           
734           _dbus_string_delete_first_word (&line);
735           _dbus_string_skip_blank (&line, 0, &i);
736           b = _dbus_string_get_byte (&line, i++);
737
738           if (b != '{')
739             goto parse_failed;
740
741           while (i < _dbus_string_get_length (&line))
742             {
743               _dbus_string_skip_blank (&line, i, &i);
744
745               if (!_dbus_string_parse_int (&line, i, &val, &i))
746                 {
747                   _dbus_warn ("could not parse integer for INT32_ARRAY\n");
748                   goto parse_failed;
749                 }
750
751               values[len++] = val;
752               if (len == allocated)
753                 {
754                   allocated *= 2;
755                   values = dbus_realloc (values, allocated * sizeof (dbus_int32_t));
756                   if (!values)
757                     {
758                       _dbus_warn ("could not allocate memory for INT32_ARRAY\n");
759                       goto parse_failed;
760                     }
761                 }
762               
763               _dbus_string_skip_blank (&line, i, &i);
764               
765               b = _dbus_string_get_byte (&line, i++);
766
767               if (b == '}')
768                 break;
769               else if (b != ',')
770                 goto parse_failed;
771             }
772
773           if (!_dbus_marshal_int32_array (dest, endian, values, len))
774             {
775               _dbus_warn ("failed to append INT32_ARRAY\n");
776               goto parse_failed;
777             }
778           dbus_free (values);
779           
780           PERFORM_UNALIGN (dest);
781         }
782       else if (_dbus_string_starts_with_c_str (&line,
783                                                "UINT32_ARRAY"))
784         {
785           SAVE_FOR_UNALIGN (dest, 4);
786           int i, len, allocated;
787           dbus_uint32_t *values;
788           long val;
789           unsigned char b;
790
791           allocated = 4;
792           values = dbus_new (dbus_uint32_t, allocated);
793           if (!values)
794             {
795               _dbus_warn ("could not allocate memory for UINT32_ARRAY\n");
796               goto parse_failed;
797             }
798           
799           len = 0;
800           
801           _dbus_string_delete_first_word (&line);
802           _dbus_string_skip_blank (&line, 0, &i);
803           b = _dbus_string_get_byte (&line, i++);
804
805           if (b != '{')
806             goto parse_failed;
807
808           while (i < _dbus_string_get_length (&line))
809             {
810               _dbus_string_skip_blank (&line, i, &i);
811
812               if (!_dbus_string_parse_int (&line, i, &val, &i))
813                 {
814                   _dbus_warn ("could not parse integer for UINT32_ARRAY\n");
815                   goto parse_failed;
816                 }
817
818               values[len++] = val;
819               if (len == allocated)
820                 {
821                   allocated *= 2;
822                   values = dbus_realloc (values, allocated * sizeof (dbus_uint32_t));
823                   if (!values)
824                     {
825                       _dbus_warn ("could not allocate memory for UINT32_ARRAY\n");
826                       goto parse_failed;
827                     }
828                 }
829               
830               _dbus_string_skip_blank (&line, i, &i);
831               
832               b = _dbus_string_get_byte (&line, i++);
833
834               if (b == '}')
835                 break;
836               else if (b != ',')
837                 goto parse_failed;
838             }
839
840           if (!_dbus_marshal_uint32_array (dest, endian, values, len))
841             {
842               _dbus_warn ("failed to append UINT32_ARRAY\n");
843               goto parse_failed;
844             }
845           dbus_free (values);
846           
847           PERFORM_UNALIGN (dest);
848         }
849       else if (_dbus_string_starts_with_c_str (&line,
850                                                "DOUBLE_ARRAY"))
851         {
852           SAVE_FOR_UNALIGN (dest, 8);
853           int i, len, allocated;
854           double *values;
855           double val;
856           unsigned char b;
857
858           allocated = 4;
859           values = dbus_new (double, allocated);
860           if (!values)
861             {
862               _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
863               goto parse_failed;
864             }
865           
866           len = 0;
867           
868           _dbus_string_delete_first_word (&line);
869           _dbus_string_skip_blank (&line, 0, &i);
870           b = _dbus_string_get_byte (&line, i++);
871
872           if (b != '{')
873             goto parse_failed;
874
875           while (i < _dbus_string_get_length (&line))
876             {
877               _dbus_string_skip_blank (&line, i, &i);
878
879               if (!_dbus_string_parse_double (&line, i, &val, &i))
880                 {
881                   _dbus_warn ("could not parse double for DOUBLE_ARRAY\n");
882                   goto parse_failed;
883                 }
884
885               values[len++] = val;
886               if (len == allocated)
887                 {
888                   allocated *= 2;
889                   values = dbus_realloc (values, allocated * sizeof (double));
890                   if (!values)
891                     {
892                       _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
893                       goto parse_failed;
894                     }
895                 }
896               
897               _dbus_string_skip_blank (&line, i, &i);
898               
899               b = _dbus_string_get_byte (&line, i++);
900
901               if (b == '}')
902                 break;
903               else if (b != ',')
904                 goto parse_failed;
905             }
906
907           if (!_dbus_marshal_double_array (dest, endian, values, len))
908             {
909               _dbus_warn ("failed to append DOUBLE_ARRAY\n");
910               goto parse_failed;
911             }
912           dbus_free (values);
913           
914           PERFORM_UNALIGN (dest);
915         }
916       else if (_dbus_string_starts_with_c_str (&line,
917                                                "STRING_ARRAY"))
918         {
919           SAVE_FOR_UNALIGN (dest, 4);
920           int i, len, allocated;
921           char **values;
922           char *val;
923           DBusString val_str;
924           unsigned char b;
925
926           allocated = 4;
927           values = dbus_new (char *, allocated);
928           if (!values)
929             {
930               _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
931               goto parse_failed;
932             }
933           
934           len = 0;
935           
936           _dbus_string_delete_first_word (&line);
937           _dbus_string_skip_blank (&line, 0, &i);
938           b = _dbus_string_get_byte (&line, i++);
939
940           if (b != '{')
941             goto parse_failed;
942
943           _dbus_string_init (&val_str, _DBUS_INT_MAX);
944           while (i < _dbus_string_get_length (&line))
945             {
946               _dbus_string_skip_blank (&line, i, &i);
947
948               if (!append_quoted_string (&val_str, &line, i, &i))
949                 {
950                   _dbus_warn ("could not parse quoted string for STRING_ARRAY\n");
951                   goto parse_failed;
952                 }
953               i++;
954
955               if (!_dbus_string_steal_data (&val_str, &val))
956                 {
957                   _dbus_warn ("could not allocate memory for STRING_ARRAY string\n");
958                   goto parse_failed;
959                 }
960               
961               values[len++] = val;
962               if (len == allocated)
963                 {
964                   allocated *= 2;
965                   values = dbus_realloc (values, allocated * sizeof (char *));
966                   if (!values)
967                     {
968                       _dbus_warn ("could not allocate memory for STRING_ARRAY\n");
969                       goto parse_failed;
970                     }
971                 }
972               
973               _dbus_string_skip_blank (&line, i, &i);
974               
975               b = _dbus_string_get_byte (&line, i++);
976
977               if (b == '}')
978                 break;
979               else if (b != ',')
980                 {
981                   _dbus_warn ("missing comma when parsing STRING_ARRAY\n");
982                   goto parse_failed;
983                 }
984             }
985           _dbus_string_free (&val_str);
986           
987           if (!_dbus_marshal_string_array (dest, endian, (const char **)values, len))
988             {
989               _dbus_warn ("failed to append STRING_ARRAY\n");
990               goto parse_failed;
991             }
992
993           values[len] = NULL;
994           dbus_free_string_array (values);
995           
996           PERFORM_UNALIGN (dest);
997         }
998       else if (_dbus_string_starts_with_c_str (&line,
999                                                "BOOLEAN"))
1000         {
1001           unsigned char val;
1002
1003           _dbus_string_delete_first_word (&line);
1004
1005           if (_dbus_string_starts_with_c_str (&line, "true"))
1006             val = TRUE;
1007           else if (_dbus_string_starts_with_c_str (&line, "false"))
1008             val = FALSE;
1009           else
1010             {
1011               _dbus_warn ("could not parse BOOLEAN\n");
1012               goto parse_failed;
1013             }
1014           if (!_dbus_string_append_byte (dest, val))
1015             {
1016               _dbus_warn ("failed to append BOOLEAN\n");
1017               goto parse_failed;
1018             }
1019         }
1020       
1021       else if (_dbus_string_starts_with_c_str (&line,
1022                                                "INT32"))
1023         {
1024           SAVE_FOR_UNALIGN (dest, 4);
1025           long val;
1026           
1027           _dbus_string_delete_first_word (&line);
1028
1029           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
1030             {
1031               _dbus_warn ("could not parse integer for INT32\n");
1032               goto parse_failed;
1033             }
1034           
1035           if (!_dbus_marshal_int32 (dest, endian,
1036                                     val))
1037             {
1038               _dbus_warn ("failed to append INT32\n");
1039               goto parse_failed;
1040             }
1041
1042           PERFORM_UNALIGN (dest);
1043         }
1044       else if (_dbus_string_starts_with_c_str (&line,
1045                                                "UINT32"))
1046         {
1047           SAVE_FOR_UNALIGN (dest, 4);
1048           long val;
1049           
1050           _dbus_string_delete_first_word (&line);
1051
1052           /* FIXME should have _dbus_string_parse_uint32 */
1053           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
1054             goto parse_failed;
1055           
1056           if (!_dbus_marshal_uint32 (dest, endian,
1057                                      val))
1058             {
1059               _dbus_warn ("failed to append UINT32\n");
1060               goto parse_failed;
1061             }
1062
1063           PERFORM_UNALIGN (dest);
1064         }
1065       else if (_dbus_string_starts_with_c_str (&line,
1066                                                "DOUBLE"))
1067         {
1068           SAVE_FOR_UNALIGN (dest, 8);
1069           double val;
1070           
1071           _dbus_string_delete_first_word (&line);
1072
1073           if (!_dbus_string_parse_double (&line, 0, &val, NULL))
1074             goto parse_failed;
1075           
1076           if (!_dbus_marshal_double (dest, endian,
1077                                      val))
1078             {
1079               _dbus_warn ("failed to append DOUBLE\n");
1080               goto parse_failed;
1081             }
1082
1083           PERFORM_UNALIGN (dest);
1084         }
1085       else if (_dbus_string_starts_with_c_str (&line,
1086                                                "STRING"))
1087         {
1088           SAVE_FOR_UNALIGN (dest, 4);
1089           int size_offset;
1090           int old_len;
1091           
1092           _dbus_string_delete_first_word (&line);
1093
1094           size_offset = _dbus_string_get_length (dest);
1095           size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
1096           if (!_dbus_marshal_uint32 (dest, endian, 0))
1097             {
1098               _dbus_warn ("Failed to append string size\n");
1099               goto parse_failed;
1100             }
1101
1102           old_len = _dbus_string_get_length (dest);
1103           if (!append_quoted_string (dest, &line, 0, NULL))
1104             {
1105               _dbus_warn ("Failed to append quoted string\n");
1106               goto parse_failed;
1107             }
1108
1109           _dbus_marshal_set_uint32 (dest, endian, size_offset,
1110                                     /* subtract 1 for nul */
1111                                     _dbus_string_get_length (dest) - old_len - 1);
1112           
1113           PERFORM_UNALIGN (dest);
1114         }
1115       else
1116         goto parse_failed;
1117       
1118       if (!just_set_unalign && unalign)
1119         {
1120           _dbus_warn ("UNALIGN prior to something that isn't aligned\n");
1121           goto parse_failed;
1122         }
1123
1124       goto next_iteration; /* skip parse_failed */
1125       
1126     parse_failed:
1127       {
1128         const char *s;
1129         _dbus_string_get_const_data (&line, &s);
1130         _dbus_warn ("couldn't process line %d \"%s\"\n",
1131                     line_no, s);
1132         goto out;
1133       }
1134     }
1135
1136   _dbus_hash_iter_init (length_hash, &iter);
1137   while (_dbus_hash_iter_next (&iter))
1138     {
1139       SavedLength *sl = _dbus_hash_iter_get_value (&iter);
1140       const char *s;
1141
1142       _dbus_string_get_const_data (&sl->name, &s);
1143       
1144       if (sl->length < 0)
1145         {
1146           _dbus_warn ("Used LENGTH %s but never did END_LENGTH\n",
1147                       s);
1148           goto out;
1149         }
1150       else if (sl->offset < 0)
1151         {
1152           _dbus_warn ("Did END_LENGTH %s but never used LENGTH\n",
1153                       s);
1154           goto out;
1155         }
1156       else
1157         {
1158           if (sl->start < 0)
1159             sl->start = 0;
1160           
1161           _dbus_verbose ("Filling in length %s endian = %d offset = %d start = %d length = %d\n",
1162                          s, sl->endian, sl->offset, sl->start, sl->length);
1163           _dbus_marshal_set_int32 (dest,
1164                                    sl->endian,
1165                                    sl->offset,
1166                                    sl->length - sl->start);
1167         }
1168
1169       _dbus_hash_iter_remove_entry (&iter);
1170     }
1171   
1172   retval = TRUE;
1173   
1174  out:
1175   if (length_hash != NULL)
1176     _dbus_hash_table_unref (length_hash);
1177   
1178   _dbus_string_free (&file);
1179   _dbus_string_free (&line);
1180   return retval;
1181 }
1182
1183 /** @} */
1184 #endif /* DBUS_BUILD_TESTS */