f779c8c17d9610150a60fca741274c4ac170a6ab
[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   s = _dbus_string_get_const_data (name);
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))
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   s = _dbus_string_get_const_data (&sl->name);
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 static int
269 message_type_from_string (const DBusString *str,
270                           int               start)
271 {
272   const char *s;
273
274   s = _dbus_string_get_const_data_len (str, start,
275                                        _dbus_string_get_length (str) - start);
276
277   if (strncmp (s, "method_call", strlen ("method_call")) == 0)
278     return DBUS_MESSAGE_TYPE_METHOD_CALL;
279   else if (strncmp (s, "method_return", strlen ("method_return")) == 0)
280     return DBUS_MESSAGE_TYPE_METHOD_RETURN;
281   else if (strncmp (s, "signal", strlen ("signal")) == 0)
282     return DBUS_MESSAGE_TYPE_SIGNAL;
283   else if (strncmp (s, "error", strlen ("error")) == 0)
284     return DBUS_MESSAGE_TYPE_ERROR;
285   else if (strncmp (s, "invalid", strlen ("invalid")) == 0)
286     return DBUS_MESSAGE_TYPE_INVALID;
287   else
288     return -1;
289 }
290
291 /**
292  * Reads the given filename, which should be in "message description
293  * language" (look at some examples), and builds up the message data
294  * from it.  The message data may be invalid, or valid.
295  *
296  * The parser isn't very strict, it's just a hack for test programs.
297  * 
298  * The file format is:
299  * @code
300  *   VALID_HEADER <type> normal header; byte order, type, padding, header len, body len, serial
301  *   BIG_ENDIAN switch to big endian
302  *   LITTLE_ENDIAN switch to little endian
303  *   OPPOSITE_ENDIAN switch to opposite endian
304  *   ALIGN <N> aligns to the given value
305  *   UNALIGN skips alignment for the next marshal
306  *   BYTE <N> inserts the given integer in [0,255] or char in 'a' format
307  *   START_LENGTH <name> marks the start of a length to measure
308  *   END_LENGTH <name> records the length since START_LENGTH under the given name
309  *                     (or if no START_LENGTH, absolute length)
310  *   LENGTH <name> inserts the saved length of the same name
311  *   CHOP <N> chops last N bytes off the data
312  *   FIELD_NAME <abcd> inserts 4-byte field name
313  *   TYPE <typename> inserts a typecode byte 
314  * @endcode
315  * 
316  * Following commands insert aligned data unless
317  * preceded by "UNALIGN":
318  * @code
319  *   INT32 <N> marshals an INT32
320  *   UINT32 <N> marshals a UINT32
321  *   INT64 <N> marshals an INT64
322  *   UINT64 <N> marshals a UINT64
323  *   DOUBLE <N> marshals a double
324  *   STRING 'Foo' marshals a string
325  *   BYTE_ARRAY { 'a', 3, 4, 5, 6} marshals a BYTE array
326  *   BOOLEAN_ARRAY { false, true, false} marshals a BOOLEAN array
327  *   INT32_ARRAY { 3, 4, 5, 6} marshals an INT32 array
328  *   UINT32_ARRAY { 3, 4, 5, 6} marshals an UINT32 array
329  *   DOUBLE_ARRAY { 1.0, 2.0, 3.0, 4.0} marshals a DOUBLE array  
330  *   STRING_ARRAY { "foo", "bar", "gazonk"} marshals a STRING array  
331  * @endcode
332  *
333  * @todo add support for array types INT32_ARRAY { 3, 4, 5, 6 }
334  * and so forth.
335  * 
336  * @param dest the string to append the message data to
337  * @param filename the filename to load
338  * @returns #TRUE on success
339  */
340 dbus_bool_t
341 _dbus_message_data_load (DBusString       *dest,
342                          const DBusString *filename)
343 {
344   DBusString file;
345   DBusError error;
346   DBusString line;
347   dbus_bool_t retval;
348   int line_no;
349   dbus_bool_t unalign;
350   DBusHashTable *length_hash;
351   int endian;
352   DBusHashIter iter;
353   
354   retval = FALSE;
355   length_hash = NULL;
356   
357   if (!_dbus_string_init (&file))
358     return FALSE;
359
360   if (!_dbus_string_init (&line))
361     {
362       _dbus_string_free (&file);
363       return FALSE;
364     }
365
366   _dbus_verbose ("Loading %s\n", _dbus_string_get_const_data (filename));
367
368   dbus_error_init (&error);
369   if (!_dbus_file_get_contents (&file, filename, &error))
370     {
371       _dbus_warn ("Getting contents of %s failed: %s\n",
372                   _dbus_string_get_const_data (filename), error.message);
373       dbus_error_free (&error);
374       goto out;
375     }
376
377   length_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
378                                       NULL,
379                                       free_saved_length);
380   if (length_hash == NULL)
381     goto out;
382   
383   endian = DBUS_COMPILER_BYTE_ORDER;
384   unalign = FALSE;
385   line_no = 0;
386  next_iteration:
387   while (_dbus_string_pop_line (&file, &line))
388     {
389       dbus_bool_t just_set_unalign;
390
391       just_set_unalign = FALSE;
392       line_no += 1;
393
394       _dbus_string_delete_leading_blanks (&line);
395
396       if (_dbus_string_get_length (&line) == 0)
397         {
398           /* empty line */
399           goto next_iteration;
400         }
401       else if (_dbus_string_starts_with_c_str (&line,
402                                                "#"))
403         {
404           /* Ignore this comment */
405           goto next_iteration;
406         }
407       else if (_dbus_string_starts_with_c_str (&line,
408                                                "VALID_HEADER"))
409         {
410           int i;
411           DBusString name;
412           int message_type;
413
414           if (_dbus_string_get_length (&line) < (int) strlen ("VALID_HEADER "))
415             {
416               _dbus_warn ("no args to VALID_HEADER\n");
417               goto parse_failed;
418             }
419           
420           if (!_dbus_string_append_byte (dest, endian))
421             {
422               _dbus_warn ("could not append endianness\n");
423               goto parse_failed;
424             }
425
426           message_type = message_type_from_string (&line,
427                                                    strlen ("VALID_HEADER "));
428           if (message_type < 0)
429             {
430               _dbus_warn ("VALID_HEADER not followed by space then known message type\n");
431               goto parse_failed;
432             }
433           
434           if (!_dbus_string_append_byte (dest, message_type))
435             {
436               _dbus_warn ("could not append message type\n");
437               goto parse_failed;
438             }
439           
440           i = 0;
441           while (i < 2)
442             {
443               if (!_dbus_string_append_byte (dest, '\0'))
444                 {
445                   _dbus_warn ("could not append nul pad\n");
446                   goto parse_failed;
447                 }
448               ++i;
449             }
450
451           _dbus_string_init_const (&name, "Header");
452           if (!append_saved_length (dest, length_hash,
453                                     &name, _dbus_string_get_length (dest),
454                                     endian))
455             goto parse_failed;
456
457           _dbus_string_init_const (&name, "Body");
458           if (!append_saved_length (dest, length_hash,
459                                     &name, _dbus_string_get_length (dest),
460                                     endian))
461             goto parse_failed;
462           
463           /* client serial */
464           if (!_dbus_marshal_int32 (dest, endian, 1))
465             {
466               _dbus_warn ("couldn't append client serial\n");
467               goto parse_failed;
468             }
469         }
470       else if (_dbus_string_starts_with_c_str (&line,
471                                                "BIG_ENDIAN"))
472         {
473           endian = DBUS_BIG_ENDIAN;
474         }
475       else if (_dbus_string_starts_with_c_str (&line,
476                                                "LITTLE_ENDIAN"))
477         {
478           endian = DBUS_LITTLE_ENDIAN;
479         }
480       else if (_dbus_string_starts_with_c_str (&line,
481                                                "OPPOSITE_ENDIAN"))
482         {
483           if (endian == DBUS_BIG_ENDIAN)
484             endian = DBUS_LITTLE_ENDIAN;
485           else
486             endian = DBUS_BIG_ENDIAN;
487         }
488       else if (_dbus_string_starts_with_c_str (&line,
489                                                "ALIGN"))
490         {
491           long val;
492           int end;
493           int orig_len;
494           
495           _dbus_string_delete_first_word (&line);
496
497           if (!_dbus_string_parse_int (&line, 0, &val, &end))
498             {
499               _dbus_warn ("Failed to parse integer\n");
500               goto parse_failed;
501             }
502
503           if (val > 8)
504             {
505               _dbus_warn ("Aligning to %ld boundary is crack\n",
506                           val);
507               goto parse_failed;
508             }
509
510           orig_len = _dbus_string_get_length (dest);
511           
512           if (!_dbus_string_align_length (dest, val))
513             goto parse_failed;
514
515           if (_dbus_string_parse_int (&line, end, &val, NULL))
516             {
517               /* If there's an optional second int argument,
518                * fill in align padding with that value
519                */
520               if (val < 0 || val > 255)
521                 {
522                   _dbus_warn ("can't fill align padding with %ld, must be a byte value\n", val);
523                   goto parse_failed;
524                 }
525
526               end = orig_len;
527               while (end < _dbus_string_get_length (dest))
528                 {
529                   _dbus_string_set_byte (dest, end, val);
530                   ++end;
531                 }
532             }
533         }
534       else if (_dbus_string_starts_with_c_str (&line, "UNALIGN"))
535         {
536           unalign = TRUE;
537           just_set_unalign = TRUE;
538         }
539       else if (_dbus_string_starts_with_c_str (&line, "CHOP"))
540         {
541           long val;
542
543           /* FIXME if you CHOP the offset for a LENGTH
544            * command, we segfault.
545            */
546           
547           _dbus_string_delete_first_word (&line);
548
549           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
550             {
551               _dbus_warn ("Failed to parse integer to chop\n");
552               goto parse_failed;
553             }
554
555           if (val > _dbus_string_get_length (dest))
556             {
557               _dbus_warn ("Trying to chop %ld bytes but we only have %d\n",
558                           val,
559                           _dbus_string_get_length (dest));
560               goto parse_failed;
561             }
562           
563           _dbus_string_shorten (dest, val);
564         }
565       else if (_dbus_string_starts_with_c_str (&line,
566                                                "START_LENGTH"))
567         {
568           _dbus_string_delete_first_word (&line);
569
570           if (!save_start (length_hash, &line,
571                            _dbus_string_get_length (dest)))
572             {
573               _dbus_warn ("failed to save length start\n");
574               goto parse_failed;
575             }
576         }
577       else if (_dbus_string_starts_with_c_str (&line,
578                                                "END_LENGTH"))
579         {
580           _dbus_string_delete_first_word (&line);
581
582           if (!save_length (length_hash, &line,
583                             _dbus_string_get_length (dest)))
584             {
585               _dbus_warn ("failed to save length end\n");
586               goto parse_failed;
587             }
588         }
589       else if (_dbus_string_starts_with_c_str (&line,
590                                                "LENGTH"))
591         {
592           SAVE_FOR_UNALIGN (dest, 4);
593           
594           _dbus_string_delete_first_word (&line);
595
596           if (!append_saved_length (dest, length_hash,
597                                     &line,
598                                     unalign ? align_pad_start : align_pad_end,
599                                     endian))
600             {
601               _dbus_warn ("failed to add LENGTH\n");
602               goto parse_failed;
603             }
604
605           PERFORM_UNALIGN (dest);
606         }
607       else if (_dbus_string_starts_with_c_str (&line,
608                                                "FIELD_NAME"))
609         {
610           _dbus_string_delete_first_word (&line);
611
612           if (_dbus_string_get_length (&line) != 4)
613             {
614               _dbus_warn ("Field name must be four characters not \"%s\"\n",
615                           _dbus_string_get_const_data (&line));
616               goto parse_failed;
617             }
618
619           if (unalign)
620             unalign = FALSE;
621           else
622             _dbus_string_align_length (dest, 4);
623           
624           if (!_dbus_string_copy (&line, 0, dest,
625                                   _dbus_string_get_length (dest)))
626             goto parse_failed;
627         }
628       else if (_dbus_string_starts_with_c_str (&line,
629                                                "TYPE"))
630         {
631           int code;
632           
633           _dbus_string_delete_first_word (&line);          
634
635           if (_dbus_string_starts_with_c_str (&line, "INVALID"))
636             code = DBUS_TYPE_INVALID;
637           else if (_dbus_string_starts_with_c_str (&line, "NIL"))
638             code = DBUS_TYPE_NIL;
639           else if (_dbus_string_starts_with_c_str (&line, "BYTE"))
640             code = DBUS_TYPE_BYTE;
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, "NAMED"))
652             code = DBUS_TYPE_NAMED;
653           else if (_dbus_string_starts_with_c_str (&line, "ARRAY"))
654             code = DBUS_TYPE_ARRAY;
655           else if (_dbus_string_starts_with_c_str (&line, "DICT"))
656             code = DBUS_TYPE_DICT;
657           else
658             {
659               _dbus_warn ("%s is not a valid type name\n", _dbus_string_get_const_data (&line));
660               goto parse_failed;
661             }
662
663           if (!_dbus_string_append_byte (dest, code))
664             {
665               _dbus_warn ("could not append typecode byte\n");
666               goto parse_failed;
667             }
668         }
669       else if (_dbus_string_starts_with_c_str (&line,
670                                                "BYTE_ARRAY"))
671         {
672           SAVE_FOR_UNALIGN (dest, 4);
673           int i, len, allocated;
674           unsigned char *values;
675           unsigned char b;
676           long val;
677
678           allocated = 4;
679           values = dbus_new (unsigned char, allocated);
680           if (!values)
681             {
682               _dbus_warn ("could not allocate memory for BYTE_ARRAY\n");
683               goto parse_failed;
684             }
685
686           len = 0;
687           
688           _dbus_string_delete_first_word (&line);
689           _dbus_string_skip_blank (&line, 0, &i);
690           b = _dbus_string_get_byte (&line, i++);
691           
692           if (b != '{')
693             goto parse_failed;
694
695           while (i < _dbus_string_get_length (&line))
696             {
697               _dbus_string_skip_blank (&line, i, &i);         
698
699               if (_dbus_string_get_byte (&line, i) == '\'' &&
700                   _dbus_string_get_length (&line) >= i + 4 &&
701                   _dbus_string_get_byte (&line, i + 1) == '\\' &&
702                   _dbus_string_get_byte (&line, i + 2) == '\'' &&
703                   _dbus_string_get_byte (&line, i + 3) == '\'')
704                 {
705                   val = '\'';
706                   i += 4;
707                 }
708               else if (_dbus_string_get_byte (&line, i) == '\'' &&
709                        _dbus_string_get_length (&line) >= i + 3 &&
710                        _dbus_string_get_byte (&line, i + 2) == '\'')
711                 {
712                   val = _dbus_string_get_byte (&line, i + 1);
713                   i += 3;
714                 }
715               else
716                 {
717                   if (!_dbus_string_parse_int (&line, i, &val, &i))
718                     {
719                       _dbus_warn ("Failed to parse integer for BYTE_ARRAY\n");
720                       goto parse_failed;
721                     }
722
723                   if (val < 0 || val > 255)
724                     {
725                       _dbus_warn ("A byte must be in range 0-255 not %ld\n",
726                                   val);
727                       goto parse_failed;
728                     }
729                 }
730
731               values[len++] = val;
732               if (len == allocated)
733                 {
734                   allocated *= 2;
735                   values = dbus_realloc (values, allocated * sizeof (unsigned char));
736                   if (!values)
737                     {
738                       _dbus_warn ("could not allocate memory for BYTE_ARRAY\n");
739                       goto parse_failed;
740                     }
741                 }
742               
743               _dbus_string_skip_blank (&line, i, &i);
744               
745               b = _dbus_string_get_byte (&line, i++);
746
747               if (b == '}')
748                 break;
749               else if (b != ',')
750                 goto parse_failed;
751             }
752
753           if (!_dbus_marshal_int32 (dest, endian, len) ||
754               !_dbus_string_append_len (dest, values, len))
755             {
756               _dbus_warn ("failed to append BYTE_ARRAY\n");
757               goto parse_failed;
758             }
759           dbus_free (values);
760           
761           PERFORM_UNALIGN (dest);
762         }
763       else if (_dbus_string_starts_with_c_str (&line,
764                                                "BOOLEAN_ARRAY"))
765         {
766           SAVE_FOR_UNALIGN (dest, 4);
767           int i, len, allocated;
768           unsigned char *values;
769           unsigned char b, val;
770
771           allocated = 4;
772           values = dbus_new (unsigned char, allocated);
773           if (!values)
774             {
775               _dbus_warn ("could not allocate memory for BOOLEAN_ARRAY\n");
776               goto parse_failed;
777             }
778
779           len = 0;
780           
781           _dbus_string_delete_first_word (&line);
782           _dbus_string_skip_blank (&line, 0, &i);
783           b = _dbus_string_get_byte (&line, i++);
784           
785           if (b != '{')
786             goto parse_failed;
787
788           while (i < _dbus_string_get_length (&line))
789             {
790               _dbus_string_skip_blank (&line, i, &i);         
791               
792               if (_dbus_string_find_to (&line, i, i + 5,
793                                         "false", NULL))
794                 {
795                   i += 5;
796                   val = TRUE;
797                 }
798               else if (_dbus_string_find_to (&line, i, i + 4,
799                                              "true", NULL))
800                 {
801                   i += 4;
802                   val = FALSE;
803                 }
804               else
805                 {
806                   _dbus_warn ("could not parse BOOLEAN_ARRAY\n");
807                   goto parse_failed;
808                 }
809
810               values[len++] = val;
811               if (len == allocated)
812                 {
813                   allocated *= 2;
814                   values = dbus_realloc (values, allocated * sizeof (unsigned char));
815                   if (!values)
816                     {
817                       _dbus_warn ("could not allocate memory for BOOLEAN_ARRAY\n");
818                       goto parse_failed;
819                     }
820                 }
821               
822               _dbus_string_skip_blank (&line, i, &i);
823               
824               b = _dbus_string_get_byte (&line, i++);
825
826               if (b == '}')
827                 break;
828               else if (b != ',')
829                 goto parse_failed;
830             }
831
832           if (!_dbus_marshal_int32 (dest, endian, len) ||
833               !_dbus_string_append_len (dest, values, len))
834             {
835               _dbus_warn ("failed to append BOOLEAN_ARRAY\n");
836               goto parse_failed;
837             }
838           dbus_free (values);
839           
840           PERFORM_UNALIGN (dest);
841         }
842       else if (_dbus_string_starts_with_c_str (&line,
843                                                "INT32_ARRAY"))
844         {
845           SAVE_FOR_UNALIGN (dest, 4);
846           int i, len, allocated;
847           dbus_int32_t *values;
848           long val;
849           unsigned char b;
850
851           allocated = 4;
852           values = dbus_new (dbus_int32_t, allocated);
853           if (!values)
854             {
855               _dbus_warn ("could not allocate memory for INT32_ARRAY\n");
856               goto parse_failed;
857             }
858           
859           len = 0;
860           
861           _dbus_string_delete_first_word (&line);
862           _dbus_string_skip_blank (&line, 0, &i);
863           b = _dbus_string_get_byte (&line, i++);
864
865           if (b != '{')
866             goto parse_failed;
867
868           while (i < _dbus_string_get_length (&line))
869             {
870               _dbus_string_skip_blank (&line, i, &i);
871
872               if (!_dbus_string_parse_int (&line, i, &val, &i))
873                 {
874                   _dbus_warn ("could not parse integer for INT32_ARRAY\n");
875                   goto parse_failed;
876                 }
877
878               values[len++] = val;
879               if (len == allocated)
880                 {
881                   allocated *= 2;
882                   values = dbus_realloc (values, allocated * sizeof (dbus_int32_t));
883                   if (!values)
884                     {
885                       _dbus_warn ("could not allocate memory for INT32_ARRAY\n");
886                       goto parse_failed;
887                     }
888                 }
889               
890               _dbus_string_skip_blank (&line, i, &i);
891               
892               b = _dbus_string_get_byte (&line, i++);
893
894               if (b == '}')
895                 break;
896               else if (b != ',')
897                 goto parse_failed;
898             }
899
900           if (!_dbus_marshal_int32_array (dest, endian, values, len))
901             {
902               _dbus_warn ("failed to append INT32_ARRAY\n");
903               goto parse_failed;
904             }
905           dbus_free (values);
906           
907           PERFORM_UNALIGN (dest);
908         }
909       else if (_dbus_string_starts_with_c_str (&line,
910                                                "UINT32_ARRAY"))
911         {
912           SAVE_FOR_UNALIGN (dest, 4);
913           int i, len, allocated;
914           dbus_uint32_t *values;
915           long val;
916           unsigned char b;
917
918           allocated = 4;
919           values = dbus_new (dbus_uint32_t, allocated);
920           if (!values)
921             {
922               _dbus_warn ("could not allocate memory for UINT32_ARRAY\n");
923               goto parse_failed;
924             }
925           
926           len = 0;
927           
928           _dbus_string_delete_first_word (&line);
929           _dbus_string_skip_blank (&line, 0, &i);
930           b = _dbus_string_get_byte (&line, i++);
931
932           if (b != '{')
933             goto parse_failed;
934
935           while (i < _dbus_string_get_length (&line))
936             {
937               _dbus_string_skip_blank (&line, i, &i);
938
939               if (!_dbus_string_parse_int (&line, i, &val, &i))
940                 {
941                   _dbus_warn ("could not parse integer for UINT32_ARRAY\n");
942                   goto parse_failed;
943                 }
944
945               values[len++] = val;
946               if (len == allocated)
947                 {
948                   allocated *= 2;
949                   values = dbus_realloc (values, allocated * sizeof (dbus_uint32_t));
950                   if (!values)
951                     {
952                       _dbus_warn ("could not allocate memory for UINT32_ARRAY\n");
953                       goto parse_failed;
954                     }
955                 }
956               
957               _dbus_string_skip_blank (&line, i, &i);
958               
959               b = _dbus_string_get_byte (&line, i++);
960
961               if (b == '}')
962                 break;
963               else if (b != ',')
964                 goto parse_failed;
965             }
966
967           if (!_dbus_marshal_uint32_array (dest, endian, values, len))
968             {
969               _dbus_warn ("failed to append UINT32_ARRAY\n");
970               goto parse_failed;
971             }
972           dbus_free (values);
973           
974           PERFORM_UNALIGN (dest);
975         }
976       else if (_dbus_string_starts_with_c_str (&line,
977                                                "DOUBLE_ARRAY"))
978         {
979           SAVE_FOR_UNALIGN (dest, 8);
980           int i, len, allocated;
981           double *values;
982           double val;
983           unsigned char b;
984
985           allocated = 4;
986           values = dbus_new (double, allocated);
987           if (!values)
988             {
989               _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
990               goto parse_failed;
991             }
992           
993           len = 0;
994           
995           _dbus_string_delete_first_word (&line);
996           _dbus_string_skip_blank (&line, 0, &i);
997           b = _dbus_string_get_byte (&line, i++);
998
999           if (b != '{')
1000             goto parse_failed;
1001
1002           while (i < _dbus_string_get_length (&line))
1003             {
1004               _dbus_string_skip_blank (&line, i, &i);
1005
1006               if (!_dbus_string_parse_double (&line, i, &val, &i))
1007                 {
1008                   _dbus_warn ("could not parse double for DOUBLE_ARRAY\n");
1009                   goto parse_failed;
1010                 }
1011
1012               values[len++] = val;
1013               if (len == allocated)
1014                 {
1015                   allocated *= 2;
1016                   values = dbus_realloc (values, allocated * sizeof (double));
1017                   if (!values)
1018                     {
1019                       _dbus_warn ("could not allocate memory for DOUBLE_ARRAY\n");
1020                       goto parse_failed;
1021                     }
1022                 }
1023               
1024               _dbus_string_skip_blank (&line, i, &i);
1025               
1026               b = _dbus_string_get_byte (&line, i++);
1027
1028               if (b == '}')
1029                 break;
1030               else if (b != ',')
1031                 goto parse_failed;
1032             }
1033
1034           if (!_dbus_marshal_double_array (dest, endian, values, len))
1035             {
1036               _dbus_warn ("failed to append DOUBLE_ARRAY\n");
1037               goto parse_failed;
1038             }
1039           dbus_free (values);
1040           
1041           PERFORM_UNALIGN (dest);
1042         }
1043       else if (_dbus_string_starts_with_c_str (&line,
1044                                                "STRING_ARRAY"))
1045         {
1046           SAVE_FOR_UNALIGN (dest, 4);
1047           int i, len, allocated;
1048           char **values;
1049           char *val;
1050           DBusString val_str;
1051           unsigned char b;
1052
1053           allocated = 4;
1054           values = dbus_new (char *, allocated);
1055           if (!values)
1056             {
1057               _dbus_warn ("could not allocate memory for STRING_ARRAY\n");
1058               goto parse_failed;
1059             }
1060           
1061           len = 0;
1062           
1063           _dbus_string_delete_first_word (&line);
1064           _dbus_string_skip_blank (&line, 0, &i);
1065           b = _dbus_string_get_byte (&line, i++);
1066
1067           if (b != '{')
1068             goto parse_failed;
1069
1070           _dbus_string_init (&val_str);
1071           while (i < _dbus_string_get_length (&line))
1072             {
1073               _dbus_string_skip_blank (&line, i, &i);
1074
1075               if (!append_quoted_string (&val_str, &line, i, &i))
1076                 {
1077                   _dbus_warn ("could not parse quoted string for STRING_ARRAY\n");
1078                   goto parse_failed;
1079                 }
1080               i++;
1081
1082               if (!_dbus_string_steal_data (&val_str, &val))
1083                 {
1084                   _dbus_warn ("could not allocate memory for STRING_ARRAY string\n");
1085                   goto parse_failed;
1086                 }
1087               
1088               values[len++] = val;
1089               if (len == allocated)
1090                 {
1091                   allocated *= 2;
1092                   values = dbus_realloc (values, allocated * sizeof (char *));
1093                   if (!values)
1094                     {
1095                       _dbus_warn ("could not allocate memory for STRING_ARRAY\n");
1096                       goto parse_failed;
1097                     }
1098                 }
1099               
1100               _dbus_string_skip_blank (&line, i, &i);
1101               
1102               b = _dbus_string_get_byte (&line, i++);
1103
1104               if (b == '}')
1105                 break;
1106               else if (b != ',')
1107                 {
1108                   _dbus_warn ("missing comma when parsing STRING_ARRAY\n");
1109                   goto parse_failed;
1110                 }
1111             }
1112           _dbus_string_free (&val_str);
1113           
1114           if (!_dbus_marshal_string_array (dest, endian, (const char **)values, len))
1115             {
1116               _dbus_warn ("failed to append STRING_ARRAY\n");
1117               goto parse_failed;
1118             }
1119
1120           values[len] = NULL;
1121           dbus_free_string_array (values);
1122           
1123           PERFORM_UNALIGN (dest);
1124         }
1125       else if (_dbus_string_starts_with_c_str (&line, "BYTE"))
1126         {
1127           unsigned char the_byte;
1128           
1129           _dbus_string_delete_first_word (&line);
1130
1131           if (_dbus_string_equal_c_str (&line, "'\\''"))
1132             the_byte = '\'';
1133           else if (_dbus_string_get_byte (&line, 0) == '\'' &&
1134                    _dbus_string_get_length (&line) >= 3 &&
1135                    _dbus_string_get_byte (&line, 2) == '\'')
1136             the_byte = _dbus_string_get_byte (&line, 1);
1137           else
1138             {
1139               long val;
1140               if (!_dbus_string_parse_int (&line, 0, &val, NULL))
1141                 {
1142                   _dbus_warn ("Failed to parse integer for BYTE\n");
1143                   goto parse_failed;
1144                 }
1145
1146               if (val > 255)
1147                 {
1148                   _dbus_warn ("A byte must be in range 0-255 not %ld\n",
1149                                  val);
1150                   goto parse_failed;
1151                 }
1152               the_byte = (unsigned char) val;
1153             }
1154
1155           _dbus_string_append_byte (dest, the_byte);
1156         }
1157       else if (_dbus_string_starts_with_c_str (&line,
1158                                                "BOOLEAN"))
1159         {
1160           unsigned char val;
1161
1162           _dbus_string_delete_first_word (&line);
1163
1164           if (_dbus_string_starts_with_c_str (&line, "true"))
1165             val = TRUE;
1166           else if (_dbus_string_starts_with_c_str (&line, "false"))
1167             val = FALSE;
1168           else
1169             {
1170               _dbus_warn ("could not parse BOOLEAN\n");
1171               goto parse_failed;
1172             }
1173           if (!_dbus_string_append_byte (dest, val))
1174             {
1175               _dbus_warn ("failed to append BOOLEAN\n");
1176               goto parse_failed;
1177             }
1178         }
1179       
1180       else if (_dbus_string_starts_with_c_str (&line,
1181                                                "INT32"))
1182         {
1183           SAVE_FOR_UNALIGN (dest, 4);
1184           long val;
1185           
1186           _dbus_string_delete_first_word (&line);
1187
1188           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
1189             {
1190               _dbus_warn ("could not parse integer for INT32\n");
1191               goto parse_failed;
1192             }
1193           
1194           if (!_dbus_marshal_int32 (dest, endian,
1195                                     val))
1196             {
1197               _dbus_warn ("failed to append INT32\n");
1198               goto parse_failed;
1199             }
1200
1201           PERFORM_UNALIGN (dest);
1202         }
1203       else if (_dbus_string_starts_with_c_str (&line,
1204                                                "UINT32"))
1205         {
1206           SAVE_FOR_UNALIGN (dest, 4);
1207           unsigned long val;
1208           
1209           _dbus_string_delete_first_word (&line);
1210
1211           if (!_dbus_string_parse_uint (&line, 0, &val, NULL))
1212             goto parse_failed;
1213           
1214           if (!_dbus_marshal_uint32 (dest, endian,
1215                                      val))
1216             {
1217               _dbus_warn ("failed to append UINT32\n");
1218               goto parse_failed;
1219             }
1220
1221           PERFORM_UNALIGN (dest);
1222         }
1223       else if (_dbus_string_starts_with_c_str (&line,
1224                                                "DOUBLE"))
1225         {
1226           SAVE_FOR_UNALIGN (dest, 8);
1227           double val;
1228           
1229           _dbus_string_delete_first_word (&line);
1230
1231           if (!_dbus_string_parse_double (&line, 0, &val, NULL))
1232             goto parse_failed;
1233           
1234           if (!_dbus_marshal_double (dest, endian,
1235                                      val))
1236             {
1237               _dbus_warn ("failed to append DOUBLE\n");
1238               goto parse_failed;
1239             }
1240
1241           PERFORM_UNALIGN (dest);
1242         }
1243       else if (_dbus_string_starts_with_c_str (&line,
1244                                                "STRING"))
1245         {
1246           SAVE_FOR_UNALIGN (dest, 4);
1247           int size_offset;
1248           int old_len;
1249           
1250           _dbus_string_delete_first_word (&line);
1251
1252           size_offset = _dbus_string_get_length (dest);
1253           size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
1254           if (!_dbus_marshal_uint32 (dest, endian, 0))
1255             {
1256               _dbus_warn ("Failed to append string size\n");
1257               goto parse_failed;
1258             }
1259
1260           old_len = _dbus_string_get_length (dest);
1261           if (!append_quoted_string (dest, &line, 0, NULL))
1262             {
1263               _dbus_warn ("Failed to append quoted string\n");
1264               goto parse_failed;
1265             }
1266
1267           _dbus_marshal_set_uint32 (dest, endian, size_offset,
1268                                     /* subtract 1 for nul */
1269                                     _dbus_string_get_length (dest) - old_len - 1);
1270           
1271           PERFORM_UNALIGN (dest);
1272         }
1273       else
1274         goto parse_failed;
1275       
1276       if (!just_set_unalign && unalign)
1277         {
1278           _dbus_warn ("UNALIGN prior to something that isn't aligned\n");
1279           goto parse_failed;
1280         }
1281
1282       goto next_iteration; /* skip parse_failed */
1283       
1284     parse_failed:
1285       {
1286         _dbus_warn ("couldn't process line %d \"%s\"\n",
1287                     line_no, _dbus_string_get_const_data (&line));
1288         goto out;
1289       }
1290     }
1291
1292   _dbus_hash_iter_init (length_hash, &iter);
1293   while (_dbus_hash_iter_next (&iter))
1294     {
1295       SavedLength *sl = _dbus_hash_iter_get_value (&iter);
1296       const char *s;
1297
1298       s = _dbus_string_get_const_data (&sl->name);
1299       
1300       if (sl->length < 0)
1301         {
1302           _dbus_warn ("Used LENGTH %s but never did END_LENGTH\n",
1303                       s);
1304           goto out;
1305         }
1306       else if (sl->offset < 0)
1307         {
1308           _dbus_warn ("Did END_LENGTH %s but never used LENGTH\n",
1309                       s);
1310           goto out;
1311         }
1312       else
1313         {
1314           if (sl->start < 0)
1315             sl->start = 0;
1316           
1317           _dbus_verbose ("Filling in length %s endian = %d offset = %d start = %d length = %d\n",
1318                          s, sl->endian, sl->offset, sl->start, sl->length);
1319           _dbus_marshal_set_int32 (dest,
1320                                    sl->endian,
1321                                    sl->offset,
1322                                    sl->length - sl->start);
1323         }
1324
1325       _dbus_hash_iter_remove_entry (&iter);
1326     }
1327   
1328   retval = TRUE;
1329
1330   _dbus_verbose_bytes_of_string (dest, 0, _dbus_string_get_length (dest));
1331   
1332  out:
1333   if (length_hash != NULL)
1334     _dbus_hash_table_unref (length_hash);
1335   
1336   _dbus_string_free (&file);
1337   _dbus_string_free (&line);
1338   return retval;
1339 }
1340
1341 /** @} */
1342 #endif /* DBUS_BUILD_TESTS */