2003-03-10 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   {
339     const char *s;
340     _dbus_string_get_const_data (filename, &s);
341     _dbus_verbose ("Loading %s\n", s);
342   }
343   
344   if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS)
345     {
346       const char *s;
347       _dbus_string_get_const_data (filename, &s);
348       _dbus_warn ("Getting contents of %s failed: %s\n",
349                   s, dbus_result_to_string (result));
350                      
351       goto out;
352     }
353
354   length_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
355                                       NULL,
356                                       free_saved_length);
357   if (length_hash == NULL)
358     goto out;
359   
360   endian = DBUS_COMPILER_BYTE_ORDER;
361   unalign = FALSE;
362   line_no = 0;
363  next_iteration:
364   while (_dbus_string_pop_line (&file, &line))
365     {
366       dbus_bool_t just_set_unalign;
367
368       just_set_unalign = FALSE;
369       line_no += 1;
370
371       _dbus_string_delete_leading_blanks (&line);
372
373       if (_dbus_string_get_length (&line) == 0)
374         {
375           /* empty line */
376           goto next_iteration;
377         }
378       else if (_dbus_string_starts_with_c_str (&line,
379                                                "#"))
380         {
381           /* Ignore this comment */
382           goto next_iteration;
383         }
384       else if (_dbus_string_starts_with_c_str (&line,
385                                                "VALID_HEADER"))
386         {
387           int i;
388           DBusString name;
389           
390           if (!_dbus_string_append_byte (dest, endian))
391             {
392               _dbus_warn ("could not append endianness\n");
393               goto parse_failed;
394             }
395
396           i = 0;
397           while (i < 3)
398             {
399               if (!_dbus_string_append_byte (dest, '\0'))
400                 {
401                   _dbus_warn ("could not append nul pad\n");
402                   goto parse_failed;
403                 }
404               ++i;
405             }
406
407           _dbus_string_init_const (&name, "Header");
408           if (!append_saved_length (dest, length_hash,
409                                     &name, _dbus_string_get_length (dest),
410                                     endian))
411             goto parse_failed;
412
413           _dbus_string_init_const (&name, "Body");
414           if (!append_saved_length (dest, length_hash,
415                                     &name, _dbus_string_get_length (dest),
416                                     endian))
417             goto parse_failed;
418           
419           /* client serial */
420           if (!_dbus_marshal_int32 (dest, endian, 1))
421             {
422               _dbus_warn ("couldn't append client serial\n");
423               goto parse_failed;
424             }
425         }
426       else if (_dbus_string_starts_with_c_str (&line,
427                                                "BIG_ENDIAN"))
428         {
429           endian = DBUS_BIG_ENDIAN;
430         }
431       else if (_dbus_string_starts_with_c_str (&line,
432                                                "LITTLE_ENDIAN"))
433         {
434           endian = DBUS_LITTLE_ENDIAN;
435         }
436       else if (_dbus_string_starts_with_c_str (&line,
437                                                "OPPOSITE_ENDIAN"))
438         {
439           if (endian == DBUS_BIG_ENDIAN)
440             endian = DBUS_LITTLE_ENDIAN;
441           else
442             endian = DBUS_BIG_ENDIAN;
443         }
444       else if (_dbus_string_starts_with_c_str (&line,
445                                                "ALIGN"))
446         {
447           long val;
448           int end;
449           int orig_len;
450           
451           _dbus_string_delete_first_word (&line);
452
453           if (!_dbus_string_parse_int (&line, 0, &val, &end))
454             {
455               _dbus_warn ("Failed to parse integer\n");
456               goto parse_failed;
457             }
458
459           if (val > 8)
460             {
461               _dbus_warn ("Aligning to %ld boundary is crack\n",
462                           val);
463               goto parse_failed;
464             }
465
466           orig_len = _dbus_string_get_length (dest);
467           
468           if (!_dbus_string_align_length (dest, val))
469             goto parse_failed;
470
471           if (_dbus_string_parse_int (&line, end, &val, NULL))
472             {
473               /* If there's an optional second int argument,
474                * fill in align padding with that value
475                */
476               if (val < 0 || val > 255)
477                 {
478                   _dbus_warn ("can't fill align padding with %ld, must be a byte value\n", val);
479                   goto parse_failed;
480                 }
481
482               end = orig_len;
483               while (end < _dbus_string_get_length (dest))
484                 {
485                   _dbus_string_set_byte (dest, end, val);
486                   ++end;
487                 }
488             }
489         }
490       else if (_dbus_string_starts_with_c_str (&line, "UNALIGN"))
491         {
492           unalign = TRUE;
493           just_set_unalign = TRUE;
494         }
495       else if (_dbus_string_starts_with_c_str (&line, "CHOP"))
496         {
497           long val;
498
499           /* FIXME if you CHOP the offset for a LENGTH
500            * command, we segfault.
501            */
502           
503           _dbus_string_delete_first_word (&line);
504
505           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
506             {
507               _dbus_warn ("Failed to parse integer to chop\n");
508               goto parse_failed;
509             }
510
511           if (val > _dbus_string_get_length (dest))
512             {
513               _dbus_warn ("Trying to chop %ld bytes but we only have %d\n",
514                           val,
515                           _dbus_string_get_length (dest));
516               goto parse_failed;
517             }
518           
519           _dbus_string_shorten (dest, val);
520         }
521       else if (_dbus_string_starts_with_c_str (&line, "BYTE"))
522         {
523           unsigned char the_byte;
524           
525           _dbus_string_delete_first_word (&line);
526
527           if (_dbus_string_equal_c_str (&line, "'\\''"))
528             the_byte = '\'';
529           else if (_dbus_string_get_byte (&line, 0) == '\'' &&
530                    _dbus_string_get_length (&line) >= 3 &&
531                    _dbus_string_get_byte (&line, 2) == '\'')
532             the_byte = _dbus_string_get_byte (&line, 1);
533           else
534             {
535               long val;
536               if (!_dbus_string_parse_int (&line, 0, &val, NULL))
537                 {
538                   _dbus_warn ("Failed to parse integer for BYTE\n");
539                   goto parse_failed;
540                 }
541
542               if (val > 255)
543                 {
544                   _dbus_warn ("A byte must be in range 0-255 not %ld\n",
545                                  val);
546                   goto parse_failed;
547                 }
548               the_byte = (unsigned char) val;
549             }
550
551           _dbus_string_append_byte (dest, the_byte);
552         }
553       else if (_dbus_string_starts_with_c_str (&line,
554                                                "START_LENGTH"))
555         {
556           _dbus_string_delete_first_word (&line);
557
558           if (!save_start (length_hash, &line,
559                            _dbus_string_get_length (dest)))
560             {
561               _dbus_warn ("failed to save length start\n");
562               goto parse_failed;
563             }
564         }
565       else if (_dbus_string_starts_with_c_str (&line,
566                                                "END_LENGTH"))
567         {
568           _dbus_string_delete_first_word (&line);
569
570           if (!save_length (length_hash, &line,
571                             _dbus_string_get_length (dest)))
572             {
573               _dbus_warn ("failed to save length end\n");
574               goto parse_failed;
575             }
576         }
577       else if (_dbus_string_starts_with_c_str (&line,
578                                                "LENGTH"))
579         {
580           SAVE_FOR_UNALIGN (dest, 4);
581           
582           _dbus_string_delete_first_word (&line);
583
584           if (!append_saved_length (dest, length_hash,
585                                     &line,
586                                     unalign ? align_pad_start : align_pad_end,
587                                     endian))
588             {
589               _dbus_warn ("failed to add LENGTH\n");
590               goto parse_failed;
591             }
592
593           PERFORM_UNALIGN (dest);
594         }
595       else if (_dbus_string_starts_with_c_str (&line,
596                                                "FIELD_NAME"))
597         {
598           _dbus_string_delete_first_word (&line);
599
600           if (_dbus_string_get_length (&line) != 4)
601             {
602               const char *s;
603               _dbus_string_get_const_data (&line, &s);
604               _dbus_warn ("Field name must be four characters not \"%s\"\n",
605                              s);
606               goto parse_failed;
607             }
608
609           if (unalign)
610             unalign = FALSE;
611           else
612             _dbus_string_align_length (dest, 4);
613           
614           if (!_dbus_string_copy (&line, 0, dest,
615                                   _dbus_string_get_length (dest)))
616             goto parse_failed;
617         }
618       else if (_dbus_string_starts_with_c_str (&line,
619                                                "TYPE"))
620         {
621           int code;
622           
623           _dbus_string_delete_first_word (&line);          
624
625           if (_dbus_string_starts_with_c_str (&line, "INVALID"))
626             code = DBUS_TYPE_INVALID;
627           else if (_dbus_string_starts_with_c_str (&line, "NIL"))
628             code = DBUS_TYPE_NIL;
629           else if (_dbus_string_starts_with_c_str (&line, "BOOLEAN_ARRAY"))
630             code = DBUS_TYPE_BOOLEAN_ARRAY;
631           else if (_dbus_string_starts_with_c_str (&line, "INT32_ARRAY"))
632             code = DBUS_TYPE_INT32_ARRAY;
633           else if (_dbus_string_starts_with_c_str (&line, "UINT32_ARRAY"))
634             code = DBUS_TYPE_UINT32_ARRAY;
635           else if (_dbus_string_starts_with_c_str (&line, "DOUBLE_ARRAY"))
636             code = DBUS_TYPE_DOUBLE_ARRAY;
637           else if (_dbus_string_starts_with_c_str (&line, "BYTE_ARRAY"))
638             code = DBUS_TYPE_BYTE_ARRAY;
639           else if (_dbus_string_starts_with_c_str (&line, "STRING_ARRAY"))
640             code = DBUS_TYPE_STRING_ARRAY;
641           else if (_dbus_string_starts_with_c_str (&line, "BOOLEAN"))
642             code = DBUS_TYPE_BOOLEAN;
643           else if (_dbus_string_starts_with_c_str (&line, "INT32"))
644             code = DBUS_TYPE_INT32;
645           else if (_dbus_string_starts_with_c_str (&line, "UINT32"))
646             code = DBUS_TYPE_UINT32;
647           else if (_dbus_string_starts_with_c_str (&line, "DOUBLE"))
648             code = DBUS_TYPE_DOUBLE;
649           else if (_dbus_string_starts_with_c_str (&line, "STRING"))
650             code = DBUS_TYPE_STRING;
651           else if (_dbus_string_starts_with_c_str (&line, "DICT"))
652             code = DBUS_TYPE_DICT;
653           else
654             {
655               const char *s;
656               _dbus_string_get_const_data (&line, &s);
657               _dbus_warn ("%s is not a valid type name\n", s);
658               goto parse_failed;
659             }
660
661           if (!_dbus_string_append_byte (dest, code))
662             {
663               _dbus_warn ("could not append typecode byte\n");
664               goto parse_failed;
665             }
666         }
667       else if (_dbus_string_starts_with_c_str (&line,
668                                                "BOOLEAN_ARRAY"))
669         {
670           SAVE_FOR_UNALIGN (dest, 4);
671           int i, len, allocated;
672           unsigned char *values;
673           unsigned char b, val;
674
675           allocated = 4;
676           values = dbus_new (unsigned char, allocated);
677           if (!values)
678             {
679               _dbus_warn ("could not allocate memory for BOOLEAN_ARRAY\n");
680               goto parse_failed;
681             }
682
683           len = 0;
684           
685           _dbus_string_delete_first_word (&line);
686           _dbus_string_skip_blank (&line, 0, &i);
687           b = _dbus_string_get_byte (&line, i++);
688           
689           if (b != '{')
690             goto parse_failed;
691
692           while (i < _dbus_string_get_length (&line))
693             {
694               _dbus_string_skip_blank (&line, i, &i);         
695               
696               if (_dbus_string_find_to (&line, i, i + 5,
697                                         "false", NULL))
698                 {
699                   i += 5;
700                   val = TRUE;
701                 }
702               else if (_dbus_string_find_to (&line, i, i + 4,
703                                              "true", NULL))
704                 {
705                   i += 4;
706                   val = FALSE;
707                 }
708               else
709                 {
710                   _dbus_warn ("could not parse BOOLEAN_ARRAY\n");
711                   goto parse_failed;
712                 }
713
714               values[len++] = val;
715               if (len == allocated)
716                 {
717                   allocated *= 2;
718                   values = dbus_realloc (values, allocated * sizeof (unsigned char));
719                   if (!values)
720                     {
721                       _dbus_warn ("could not allocate memory for BOOLEAN_ARRAY\n");
722                       goto parse_failed;
723                     }
724                 }
725               
726               _dbus_string_skip_blank (&line, i, &i);
727               
728               b = _dbus_string_get_byte (&line, i++);
729
730               if (b == '}')
731                 break;
732               else if (b != ',')
733                 goto parse_failed;
734             }
735
736           if (!_dbus_marshal_int32 (dest, endian, len) ||
737               !_dbus_string_append_len (dest, values, len))
738             {
739               _dbus_warn ("failed to append BOOLEAN_ARRAY\n");
740               goto parse_failed;
741             }
742           dbus_free (values);
743           
744           PERFORM_UNALIGN (dest);
745         }
746       else if (_dbus_string_starts_with_c_str (&line,
747                                                "INT32_ARRAY"))
748         {
749           SAVE_FOR_UNALIGN (dest, 4);
750           int i, len, allocated;
751           dbus_int32_t *values;
752           long val;
753           unsigned char b;
754
755           allocated = 4;
756           values = dbus_new (dbus_int32_t, allocated);
757           if (!values)
758             {
759               _dbus_warn ("could not allocate memory for INT32_ARRAY\n");
760               goto parse_failed;
761             }
762           
763           len = 0;
764           
765           _dbus_string_delete_first_word (&line);
766           _dbus_string_skip_blank (&line, 0, &i);
767           b = _dbus_string_get_byte (&line, i++);
768
769           if (b != '{')
770             goto parse_failed;
771
772           while (i < _dbus_string_get_length (&line))
773             {
774               _dbus_string_skip_blank (&line, i, &i);
775
776               if (!_dbus_string_parse_int (&line, i, &val, &i))
777                 {
778                   _dbus_warn ("could not parse integer for INT32_ARRAY\n");
779                   goto parse_failed;
780                 }
781
782               values[len++] = val;
783               if (len == allocated)
784                 {
785                   allocated *= 2;
786                   values = dbus_realloc (values, allocated * sizeof (dbus_int32_t));
787                   if (!values)
788                     {
789                       _dbus_warn ("could not allocate memory for INT32_ARRAY\n");
790                       goto parse_failed;
791                     }
792                 }
793               
794               _dbus_string_skip_blank (&line, i, &i);
795               
796               b = _dbus_string_get_byte (&line, i++);
797
798               if (b == '}')
799                 break;
800               else if (b != ',')
801                 goto parse_failed;
802             }
803
804           if (!_dbus_marshal_int32_array (dest, endian, values, len))
805             {
806               _dbus_warn ("failed to append INT32_ARRAY\n");
807               goto parse_failed;
808             }
809           dbus_free (values);
810           
811           PERFORM_UNALIGN (dest);
812         }
813       else if (_dbus_string_starts_with_c_str (&line,
814                                                "UINT32_ARRAY"))
815         {
816           SAVE_FOR_UNALIGN (dest, 4);
817           int i, len, allocated;
818           dbus_uint32_t *values;
819           long val;
820           unsigned char b;
821
822           allocated = 4;
823           values = dbus_new (dbus_uint32_t, allocated);
824           if (!values)
825             {
826               _dbus_warn ("could not allocate memory for UINT32_ARRAY\n");
827               goto parse_failed;
828             }
829           
830           len = 0;
831           
832           _dbus_string_delete_first_word (&line);
833           _dbus_string_skip_blank (&line, 0, &i);
834           b = _dbus_string_get_byte (&line, i++);
835
836           if (b != '{')
837             goto parse_failed;
838
839           while (i < _dbus_string_get_length (&line))
840             {
841               _dbus_string_skip_blank (&line, i, &i);
842
843               if (!_dbus_string_parse_int (&line, i, &val, &i))
844                 {
845                   _dbus_warn ("could not parse integer for UINT32_ARRAY\n");
846                   goto parse_failed;
847                 }
848
849               values[len++] = val;
850               if (len == allocated)
851                 {
852                   allocated *= 2;
853                   values = dbus_realloc (values, allocated * sizeof (dbus_uint32_t));
854                   if (!values)
855                     {
856                       _dbus_warn ("could not allocate memory for UINT32_ARRAY\n");
857                       goto parse_failed;
858                     }
859                 }
860               
861               _dbus_string_skip_blank (&line, i, &i);
862               
863               b = _dbus_string_get_byte (&line, i++);
864
865               if (b == '}')
866                 break;
867               else if (b != ',')
868                 goto parse_failed;
869             }
870
871           if (!_dbus_marshal_uint32_array (dest, endian, values, len))
872             {
873               _dbus_warn ("failed to append UINT32_ARRAY\n");
874               goto parse_failed;
875             }
876           dbus_free (values);
877           
878           PERFORM_UNALIGN (dest);
879         }
880       else if (_dbus_string_starts_with_c_str (&line,
881                                                "DOUBLE_ARRAY"))
882         {
883           SAVE_FOR_UNALIGN (dest, 8);
884           int i, len, allocated;
885           double *values;
886           double val;
887           unsigned char b;
888
889           allocated = 4;
890           values = dbus_new (double, allocated);
891           if (!values)
892             {
893               _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
894               goto parse_failed;
895             }
896           
897           len = 0;
898           
899           _dbus_string_delete_first_word (&line);
900           _dbus_string_skip_blank (&line, 0, &i);
901           b = _dbus_string_get_byte (&line, i++);
902
903           if (b != '{')
904             goto parse_failed;
905
906           while (i < _dbus_string_get_length (&line))
907             {
908               _dbus_string_skip_blank (&line, i, &i);
909
910               if (!_dbus_string_parse_double (&line, i, &val, &i))
911                 {
912                   _dbus_warn ("could not parse double for DOUBLE_ARRAY\n");
913                   goto parse_failed;
914                 }
915
916               values[len++] = val;
917               if (len == allocated)
918                 {
919                   allocated *= 2;
920                   values = dbus_realloc (values, allocated * sizeof (double));
921                   if (!values)
922                     {
923                       _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
924                       goto parse_failed;
925                     }
926                 }
927               
928               _dbus_string_skip_blank (&line, i, &i);
929               
930               b = _dbus_string_get_byte (&line, i++);
931
932               if (b == '}')
933                 break;
934               else if (b != ',')
935                 goto parse_failed;
936             }
937
938           if (!_dbus_marshal_double_array (dest, endian, values, len))
939             {
940               _dbus_warn ("failed to append DOUBLE_ARRAY\n");
941               goto parse_failed;
942             }
943           dbus_free (values);
944           
945           PERFORM_UNALIGN (dest);
946         }
947       else if (_dbus_string_starts_with_c_str (&line,
948                                                "STRING_ARRAY"))
949         {
950           SAVE_FOR_UNALIGN (dest, 4);
951           int i, len, allocated;
952           char **values;
953           char *val;
954           DBusString val_str;
955           unsigned char b;
956
957           allocated = 4;
958           values = dbus_new (char *, allocated);
959           if (!values)
960             {
961               _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
962               goto parse_failed;
963             }
964           
965           len = 0;
966           
967           _dbus_string_delete_first_word (&line);
968           _dbus_string_skip_blank (&line, 0, &i);
969           b = _dbus_string_get_byte (&line, i++);
970
971           if (b != '{')
972             goto parse_failed;
973
974           _dbus_string_init (&val_str, _DBUS_INT_MAX);
975           while (i < _dbus_string_get_length (&line))
976             {
977               _dbus_string_skip_blank (&line, i, &i);
978
979               if (!append_quoted_string (&val_str, &line, i, &i))
980                 {
981                   _dbus_warn ("could not parse quoted string for STRING_ARRAY\n");
982                   goto parse_failed;
983                 }
984               i++;
985
986               if (!_dbus_string_steal_data (&val_str, &val))
987                 {
988                   _dbus_warn ("could not allocate memory for STRING_ARRAY string\n");
989                   goto parse_failed;
990                 }
991               
992               values[len++] = val;
993               if (len == allocated)
994                 {
995                   allocated *= 2;
996                   values = dbus_realloc (values, allocated * sizeof (char *));
997                   if (!values)
998                     {
999                       _dbus_warn ("could not allocate memory for STRING_ARRAY\n");
1000                       goto parse_failed;
1001                     }
1002                 }
1003               
1004               _dbus_string_skip_blank (&line, i, &i);
1005               
1006               b = _dbus_string_get_byte (&line, i++);
1007
1008               if (b == '}')
1009                 break;
1010               else if (b != ',')
1011                 {
1012                   _dbus_warn ("missing comma when parsing STRING_ARRAY\n");
1013                   goto parse_failed;
1014                 }
1015             }
1016           _dbus_string_free (&val_str);
1017           
1018           if (!_dbus_marshal_string_array (dest, endian, (const char **)values, len))
1019             {
1020               _dbus_warn ("failed to append STRING_ARRAY\n");
1021               goto parse_failed;
1022             }
1023
1024           values[len] = NULL;
1025           dbus_free_string_array (values);
1026           
1027           PERFORM_UNALIGN (dest);
1028         }
1029       else if (_dbus_string_starts_with_c_str (&line,
1030                                                "BOOLEAN"))
1031         {
1032           unsigned char val;
1033
1034           _dbus_string_delete_first_word (&line);
1035
1036           if (_dbus_string_starts_with_c_str (&line, "true"))
1037             val = TRUE;
1038           else if (_dbus_string_starts_with_c_str (&line, "false"))
1039             val = FALSE;
1040           else
1041             {
1042               _dbus_warn ("could not parse BOOLEAN\n");
1043               goto parse_failed;
1044             }
1045           if (!_dbus_string_append_byte (dest, val))
1046             {
1047               _dbus_warn ("failed to append BOOLEAN\n");
1048               goto parse_failed;
1049             }
1050         }
1051       
1052       else if (_dbus_string_starts_with_c_str (&line,
1053                                                "INT32"))
1054         {
1055           SAVE_FOR_UNALIGN (dest, 4);
1056           long val;
1057           
1058           _dbus_string_delete_first_word (&line);
1059
1060           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
1061             {
1062               _dbus_warn ("could not parse integer for INT32\n");
1063               goto parse_failed;
1064             }
1065           
1066           if (!_dbus_marshal_int32 (dest, endian,
1067                                     val))
1068             {
1069               _dbus_warn ("failed to append INT32\n");
1070               goto parse_failed;
1071             }
1072
1073           PERFORM_UNALIGN (dest);
1074         }
1075       else if (_dbus_string_starts_with_c_str (&line,
1076                                                "UINT32"))
1077         {
1078           SAVE_FOR_UNALIGN (dest, 4);
1079           long val;
1080           
1081           _dbus_string_delete_first_word (&line);
1082
1083           /* FIXME should have _dbus_string_parse_uint32 */
1084           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
1085             goto parse_failed;
1086           
1087           if (!_dbus_marshal_uint32 (dest, endian,
1088                                      val))
1089             {
1090               _dbus_warn ("failed to append UINT32\n");
1091               goto parse_failed;
1092             }
1093
1094           PERFORM_UNALIGN (dest);
1095         }
1096       else if (_dbus_string_starts_with_c_str (&line,
1097                                                "DOUBLE"))
1098         {
1099           SAVE_FOR_UNALIGN (dest, 8);
1100           double val;
1101           
1102           _dbus_string_delete_first_word (&line);
1103
1104           if (!_dbus_string_parse_double (&line, 0, &val, NULL))
1105             goto parse_failed;
1106           
1107           if (!_dbus_marshal_double (dest, endian,
1108                                      val))
1109             {
1110               _dbus_warn ("failed to append DOUBLE\n");
1111               goto parse_failed;
1112             }
1113
1114           PERFORM_UNALIGN (dest);
1115         }
1116       else if (_dbus_string_starts_with_c_str (&line,
1117                                                "STRING"))
1118         {
1119           SAVE_FOR_UNALIGN (dest, 4);
1120           int size_offset;
1121           int old_len;
1122           
1123           _dbus_string_delete_first_word (&line);
1124
1125           size_offset = _dbus_string_get_length (dest);
1126           size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
1127           if (!_dbus_marshal_uint32 (dest, endian, 0))
1128             {
1129               _dbus_warn ("Failed to append string size\n");
1130               goto parse_failed;
1131             }
1132
1133           old_len = _dbus_string_get_length (dest);
1134           if (!append_quoted_string (dest, &line, 0, NULL))
1135             {
1136               _dbus_warn ("Failed to append quoted string\n");
1137               goto parse_failed;
1138             }
1139
1140           _dbus_marshal_set_uint32 (dest, endian, size_offset,
1141                                     /* subtract 1 for nul */
1142                                     _dbus_string_get_length (dest) - old_len - 1);
1143           
1144           PERFORM_UNALIGN (dest);
1145         }
1146       else
1147         goto parse_failed;
1148       
1149       if (!just_set_unalign && unalign)
1150         {
1151           _dbus_warn ("UNALIGN prior to something that isn't aligned\n");
1152           goto parse_failed;
1153         }
1154
1155       goto next_iteration; /* skip parse_failed */
1156       
1157     parse_failed:
1158       {
1159         const char *s;
1160         _dbus_string_get_const_data (&line, &s);
1161         _dbus_warn ("couldn't process line %d \"%s\"\n",
1162                     line_no, s);
1163         goto out;
1164       }
1165     }
1166
1167   _dbus_hash_iter_init (length_hash, &iter);
1168   while (_dbus_hash_iter_next (&iter))
1169     {
1170       SavedLength *sl = _dbus_hash_iter_get_value (&iter);
1171       const char *s;
1172
1173       _dbus_string_get_const_data (&sl->name, &s);
1174       
1175       if (sl->length < 0)
1176         {
1177           _dbus_warn ("Used LENGTH %s but never did END_LENGTH\n",
1178                       s);
1179           goto out;
1180         }
1181       else if (sl->offset < 0)
1182         {
1183           _dbus_warn ("Did END_LENGTH %s but never used LENGTH\n",
1184                       s);
1185           goto out;
1186         }
1187       else
1188         {
1189           if (sl->start < 0)
1190             sl->start = 0;
1191           
1192           _dbus_verbose ("Filling in length %s endian = %d offset = %d start = %d length = %d\n",
1193                          s, sl->endian, sl->offset, sl->start, sl->length);
1194           _dbus_marshal_set_int32 (dest,
1195                                    sl->endian,
1196                                    sl->offset,
1197                                    sl->length - sl->start);
1198         }
1199
1200       _dbus_hash_iter_remove_entry (&iter);
1201     }
1202   
1203   retval = TRUE;
1204   
1205  out:
1206   if (length_hash != NULL)
1207     _dbus_hash_table_unref (length_hash);
1208   
1209   _dbus_string_free (&file);
1210   _dbus_string_free (&line);
1211   return retval;
1212 }
1213
1214 /** @} */
1215 #endif /* DBUS_BUILD_TESTS */