2003-01-27 Havoc Pennington <hp@pobox.com>
[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 static dbus_bool_t
44 pop_line (DBusString *source,
45           DBusString *dest)
46 {
47   int eol;
48   dbus_bool_t have_newline;
49   
50   _dbus_string_set_length (dest, 0);
51   
52   eol = 0;
53   if (_dbus_string_find (source, 0, "\n", &eol))
54     {
55       have_newline = TRUE;
56       eol += 1; /* include newline */
57     }
58   else
59     {
60       eol = _dbus_string_get_length (source);
61       have_newline = FALSE;
62     }
63
64   if (eol == 0)
65     return FALSE; /* eof */
66   
67   if (!_dbus_string_move_len (source, 0, eol,
68                               dest, 0))
69     {
70       _dbus_warn ("failed to pop line\n");
71       return FALSE;
72     }
73
74   /* dump the newline */
75   if (have_newline)
76     {
77       _dbus_assert (_dbus_string_get_length (dest) > 0);
78       _dbus_string_set_length (dest,
79                                _dbus_string_get_length (dest) - 1);
80     }
81   
82   return TRUE;
83 }
84
85 static void
86 strip_command_name (DBusString *str)
87 {
88   int i;
89   
90   i = 0;
91   if (_dbus_string_find_blank (str, 0, &i))
92     _dbus_string_skip_blank (str, i, &i);
93
94   _dbus_string_delete (str, 0, i);
95 }
96
97 static void
98 strip_leading_space (DBusString *str)
99 {
100   int i;
101   
102   i = 0;
103   _dbus_string_skip_blank (str, 0, &i);
104
105   if (i > 0)
106     _dbus_string_delete (str, 0, i);
107 }
108
109 typedef struct
110 {
111   DBusString name;
112   int start;  /**< Calculate length since here */
113   int length; /**< length to write */
114   int offset; /**< where to write it into the data */
115   int endian; /**< endianness to write with */
116 } SavedLength;
117
118 static void
119 free_saved_length (void *data)
120 {
121   SavedLength *sl = data;
122
123   if (sl == NULL)
124     return; /* all hash free functions have to accept NULL */
125   
126   _dbus_string_free (&sl->name);
127   dbus_free (sl);
128 }
129
130 static SavedLength*
131 ensure_saved_length (DBusHashTable    *hash,
132                      const DBusString *name)
133 {
134   SavedLength *sl;
135   const char *s;
136
137   _dbus_string_get_const_data (name, &s);
138
139   sl = _dbus_hash_table_lookup_string (hash, s);
140   if (sl != NULL)
141     return sl;
142   
143   sl = dbus_new0 (SavedLength, 1);
144
145   if (!_dbus_string_init (&sl->name, _DBUS_INT_MAX))
146     {
147       dbus_free (sl);
148       return NULL;
149     }
150
151   if (!_dbus_string_copy (name, 0, &sl->name, 0))
152     goto failed;
153
154   _dbus_string_get_const_data (&sl->name, &s);
155
156   if (!_dbus_hash_table_insert_string (hash, (char*)s, sl))
157     goto failed;
158
159   sl->start = -1;
160   sl->length = -1;
161   sl->offset = -1;
162   sl->endian = -1;
163   
164   return sl;
165   
166  failed:
167   free_saved_length (sl);
168   return NULL;
169 }
170
171 static dbus_bool_t
172 save_start (DBusHashTable    *hash,
173             const DBusString *name,
174             int               start)
175 {
176   SavedLength *sl;
177
178   sl = ensure_saved_length (hash, name);
179
180   if (sl == NULL)
181     return FALSE;
182   else if (sl->start >= 0)
183     {
184       _dbus_warn ("Same START_LENGTH given twice\n");
185       return FALSE;
186     }
187   else
188     sl->start = start;
189
190   return TRUE;
191 }
192
193 static dbus_bool_t
194 save_length (DBusHashTable    *hash,
195              const DBusString *name,
196              int               length)
197 {
198   SavedLength *sl;
199
200   sl = ensure_saved_length (hash, name);
201
202   if (sl == NULL)
203     return FALSE;
204   else if (sl->length >= 0)
205     {
206       _dbus_warn ("Same END_LENGTH given twice\n");
207       return FALSE;
208     }
209   else
210     sl->length = length;
211
212   return TRUE;
213 }
214
215 static dbus_bool_t
216 save_offset (DBusHashTable    *hash,
217              const DBusString *name,
218              int               offset,
219              int               endian)
220 {
221   SavedLength *sl;
222
223   sl = ensure_saved_length (hash, name);
224
225   if (sl == NULL)
226     return FALSE;
227   else if (sl->offset >= 0)
228     {
229       _dbus_warn ("Same LENGTH given twice\n");
230       return FALSE;
231     }
232   else
233     {
234       sl->offset = offset;
235       sl->endian = endian;
236     }
237
238   return TRUE;
239 }
240
241 /** Saves the segment to delete in order to unalign the next item */
242 #define SAVE_FOR_UNALIGN(str, boundary)                                 \
243   int align_pad_start = _dbus_string_get_length (str);                  \
244   int align_pad_end = _DBUS_ALIGN_VALUE (align_pad_start, (boundary))
245
246 /** Deletes the alignment padding */
247 #define PERFORM_UNALIGN(str)                                    \
248   if (unalign)                                                  \
249     {                                                           \
250       _dbus_string_delete ((str), align_pad_start,              \
251                            align_pad_end - align_pad_start);    \
252       unalign = FALSE;                                          \
253     }
254
255
256 static dbus_bool_t
257 append_quoted_string (DBusString       *dest,
258                       const DBusString *quoted)
259 {
260   dbus_bool_t in_quotes = FALSE;
261   int i;
262
263   i = 0;
264   while (i < _dbus_string_get_length (quoted))
265     {
266       unsigned char b;
267
268       b = _dbus_string_get_byte (quoted, i);
269       
270       if (in_quotes)
271         {
272           if (b == '\'')
273             in_quotes = FALSE;
274           else
275             {
276               if (!_dbus_string_append_byte (dest, b))
277                 return FALSE;
278             }
279         }
280       else
281         {
282           if (b == '\'')
283             in_quotes = TRUE;
284           else if (b == ' ' || b == '\n' || b == '\t')
285             break; /* end on whitespace if not quoted */
286           else
287             {
288               if (!_dbus_string_append_byte (dest, b))
289                 return FALSE;
290             }
291         }
292       
293       ++i;
294     }
295
296   if (!_dbus_string_append_byte (dest, '\0'))
297     return FALSE;
298   return TRUE;
299 }
300
301 static dbus_bool_t
302 append_saved_length (DBusString       *dest,
303                      DBusHashTable    *length_hash,
304                      const DBusString *name,
305                      int               offset,
306                      int               endian)
307 {
308   if (!save_offset (length_hash, name,
309                     offset, endian))
310     {
311       _dbus_warn ("failed to save offset to LENGTH\n");
312       return FALSE;
313     }
314   
315   if (!_dbus_marshal_int32 (dest, endian,
316                             -1))
317     {
318       _dbus_warn ("failed to append a length\n");
319       return FALSE;
320     }
321
322   return TRUE;
323 }
324
325 /**
326  * Reads the given filename, which should be in "message description
327  * language" (look at some examples), and builds up the message data
328  * from it.  The message data may be invalid, or valid.
329  *
330  * The parser isn't very strict, it's just a hack for test programs.
331  * 
332  * The file format is:
333  * @code
334  *   VALID_HEADER normal header; byte order, padding, header len, body len, serial
335  *   BIG_ENDIAN switch to big endian
336  *   LITTLE_ENDIAN switch to little endian
337  *   OPPOSITE_ENDIAN switch to opposite endian
338  *   ALIGN <N> aligns to the given value
339  *   UNALIGN skips alignment for the next marshal
340  *   BYTE <N> inserts the given integer in [0,255] or char in 'a' format
341  *   START_LENGTH <name> marks the start of a length to measure
342  *   END_LENGTH <name> records the length since START_LENGTH under the given name
343  *                     (or if no START_LENGTH, absolute length)
344  *   LENGTH <name> inserts the saved length of the same name
345  *   CHOP <N> chops last N bytes off the data
346  *   FIELD_NAME <abcd> inserts 4-byte field name
347  *   TYPE <typename> inserts a typecode byte 
348  * @endcode
349  * 
350  * Following commands insert aligned data unless
351  * preceded by "UNALIGN":
352  * @code
353  *   INT32 <N> marshals an INT32
354  *   UINT32 <N> marshals a UINT32
355  *   DOUBLE <N> marshals a double
356  *   STRING 'Foo' marshals a string
357  * @endcode
358  *
359  * @todo add support for array types INT32_ARRAY { 3, 4, 5, 6 }
360  * and so forth.
361  * 
362  * @param dest the string to append the message data to
363  * @param filename the filename to load
364  * @returns #TRUE on success
365  */
366 dbus_bool_t
367 _dbus_message_data_load (DBusString       *dest,
368                          const DBusString *filename)
369 {
370   DBusString file;
371   DBusResultCode result;
372   DBusString line;
373   dbus_bool_t retval;
374   int line_no;
375   dbus_bool_t unalign;
376   DBusHashTable *length_hash;
377   int endian;
378   DBusHashIter iter;
379   
380   retval = FALSE;
381   length_hash = NULL;
382   
383   if (!_dbus_string_init (&file, _DBUS_INT_MAX))
384     return FALSE;
385
386   if (!_dbus_string_init (&line, _DBUS_INT_MAX))
387     {
388       _dbus_string_free (&file);
389       return FALSE;
390     }
391   
392   if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS)
393     {
394       const char *s;
395       _dbus_string_get_const_data (filename, &s);
396       _dbus_warn ("Getting contents of %s failed: %s\n",
397                      s, dbus_result_to_string (result));
398                      
399       goto out;
400     }
401
402   length_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
403                                       NULL,
404                                       free_saved_length);
405   if (length_hash == NULL)
406     goto out;
407   
408   endian = DBUS_COMPILER_BYTE_ORDER;
409   unalign = FALSE;
410   line_no = 0;
411  next_iteration:
412   while (pop_line (&file, &line))
413     {
414       dbus_bool_t just_set_unalign;
415
416       just_set_unalign = FALSE;
417       line_no += 1;
418
419       strip_leading_space (&line);
420
421       if (_dbus_string_get_length (&line) == 0)
422         {
423           /* empty line */
424           goto next_iteration;
425         }
426       else if (_dbus_string_starts_with_c_str (&line,
427                                                "#"))
428         {
429           /* Ignore this comment */
430           goto next_iteration;
431         }
432       else if (_dbus_string_starts_with_c_str (&line,
433                                                "VALID_HEADER"))
434         {
435           int i;
436           DBusString name;
437           
438           if (!_dbus_string_append_byte (dest, endian))
439             {
440               _dbus_warn ("could not append endianness\n");
441               goto parse_failed;
442             }
443
444           i = 0;
445           while (i < 3)
446             {
447               if (!_dbus_string_append_byte (dest, '\0'))
448                 {
449                   _dbus_warn ("could not append nul pad\n");
450                   goto parse_failed;
451                 }
452               ++i;
453             }
454
455           _dbus_string_init_const (&name, "Header");
456           if (!append_saved_length (dest, length_hash,
457                                     &name, _dbus_string_get_length (dest),
458                                     endian))
459             goto parse_failed;
460
461           _dbus_string_init_const (&name, "Body");
462           if (!append_saved_length (dest, length_hash,
463                                     &name, _dbus_string_get_length (dest),
464                                     endian))
465             goto parse_failed;
466           
467           /* client serial */
468           if (!_dbus_marshal_int32 (dest, endian, 1))
469             {
470               _dbus_warn ("couldn't append client serial\n");
471               goto parse_failed;
472             }
473         }
474       else if (_dbus_string_starts_with_c_str (&line,
475                                                "BIG_ENDIAN"))
476         {
477           endian = DBUS_BIG_ENDIAN;
478         }
479       else if (_dbus_string_starts_with_c_str (&line,
480                                                "LITTLE_ENDIAN"))
481         {
482           endian = DBUS_LITTLE_ENDIAN;
483         }
484       else if (_dbus_string_starts_with_c_str (&line,
485                                                "OPPOSITE_ENDIAN"))
486         {
487           if (endian == DBUS_BIG_ENDIAN)
488             endian = DBUS_LITTLE_ENDIAN;
489           else
490             endian = DBUS_BIG_ENDIAN;
491         }
492       else if (_dbus_string_starts_with_c_str (&line,
493                                                "ALIGN"))
494         {
495           long val;
496
497           strip_command_name (&line);
498
499           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
500             {
501               _dbus_warn ("Failed to parse integer\n");
502               goto parse_failed;
503             }
504
505           if (val > 16)
506             {
507               _dbus_warn ("Aligning to %ld boundary is crack\n",
508                           val);
509               goto parse_failed;
510             }
511           
512           if (!_dbus_string_align_length (dest, val))
513             goto parse_failed;
514         }
515       else if (_dbus_string_starts_with_c_str (&line, "UNALIGN"))
516         {
517           unalign = TRUE;
518           just_set_unalign = TRUE;
519         }
520       else if (_dbus_string_starts_with_c_str (&line, "CHOP"))
521         {
522           long val;
523
524           /* FIXME if you CHOP the offset for a LENGTH
525            * command, we segfault.
526            */
527           
528           strip_command_name (&line);
529
530           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
531             {
532               _dbus_warn ("Failed to parse integer to chop\n");
533               goto parse_failed;
534             }
535
536           if (val > _dbus_string_get_length (dest))
537             {
538               _dbus_warn ("Trying to chop %ld bytes but we only have %d\n",
539                           val,
540                           _dbus_string_get_length (dest));
541               goto parse_failed;
542             }
543           
544           _dbus_string_shorten (dest, val);
545         }
546       else if (_dbus_string_starts_with_c_str (&line, "BYTE"))
547         {
548           unsigned char the_byte;
549           
550           strip_command_name (&line);
551
552           if (_dbus_string_equal_c_str (&line, "'\\''"))
553             the_byte = '\'';
554           else if (_dbus_string_get_byte (&line, 0) == '\'' &&
555                    _dbus_string_get_length (&line) >= 3 &&
556                    _dbus_string_get_byte (&line, 2) == '\'')
557             the_byte = _dbus_string_get_byte (&line, 1);
558           else
559             {
560               long val;
561               if (!_dbus_string_parse_int (&line, 0, &val, NULL))
562                 {
563                   _dbus_warn ("Failed to parse integer for BYTE\n");
564                   goto parse_failed;
565                 }
566
567               if (val > 255)
568                 {
569                   _dbus_warn ("A byte must be in range 0-255 not %ld\n",
570                                  val);
571                   goto parse_failed;
572                 }
573               the_byte = (unsigned char) val;
574             }
575
576           _dbus_string_append_byte (dest, the_byte);
577         }
578       else if (_dbus_string_starts_with_c_str (&line,
579                                                "START_LENGTH"))
580         {
581           strip_command_name (&line);
582
583           if (!save_start (length_hash, &line,
584                            _dbus_string_get_length (dest)))
585             {
586               _dbus_warn ("failed to save length start\n");
587               goto parse_failed;
588             }
589         }
590       else if (_dbus_string_starts_with_c_str (&line,
591                                                "END_LENGTH"))
592         {
593           strip_command_name (&line);
594
595           if (!save_length (length_hash, &line,
596                             _dbus_string_get_length (dest)))
597             {
598               _dbus_warn ("failed to save length end\n");
599               goto parse_failed;
600             }
601         }
602       else if (_dbus_string_starts_with_c_str (&line,
603                                                "LENGTH"))
604         {
605           SAVE_FOR_UNALIGN (dest, 4);
606           
607           strip_command_name (&line);
608
609           if (!append_saved_length (dest, length_hash,
610                                     &line,
611                                     unalign ? align_pad_start : align_pad_end,
612                                     endian))
613             {
614               _dbus_warn ("failed to add LENGTH\n");
615               goto parse_failed;
616             }
617
618           PERFORM_UNALIGN (dest);
619         }
620       else if (_dbus_string_starts_with_c_str (&line,
621                                                "FIELD_NAME"))
622         {
623           strip_command_name (&line);
624
625           if (_dbus_string_get_length (&line) != 4)
626             {
627               const char *s;
628               _dbus_string_get_const_data (&line, &s);
629               _dbus_warn ("Field name must be four characters not \"%s\"\n",
630                              s);
631               goto parse_failed;
632             }
633
634           if (unalign)
635             unalign = FALSE;
636           else
637             _dbus_string_align_length (dest, 4);
638           
639           if (!_dbus_string_copy (&line, 0, dest,
640                                   _dbus_string_get_length (dest)))
641             goto parse_failed;
642         }
643       else if (_dbus_string_starts_with_c_str (&line,
644                                                "TYPE"))
645         {
646           int code;
647           
648           strip_command_name (&line);          
649
650           if (_dbus_string_starts_with_c_str (&line, "INVALID"))
651             code = DBUS_TYPE_INVALID;
652           else if (_dbus_string_starts_with_c_str (&line, "NIL"))
653             code = DBUS_TYPE_NIL;
654           else if (_dbus_string_starts_with_c_str (&line, "INT32"))
655             code = DBUS_TYPE_INT32;
656           else if (_dbus_string_starts_with_c_str (&line, "UINT32"))
657             code = DBUS_TYPE_UINT32;
658           else if (_dbus_string_starts_with_c_str (&line, "DOUBLE"))
659             code = DBUS_TYPE_DOUBLE;
660           else if (_dbus_string_starts_with_c_str (&line, "STRING"))
661             code = DBUS_TYPE_STRING;
662           else if (_dbus_string_starts_with_c_str (&line, "INT32_ARRAY"))
663             code = DBUS_TYPE_INT32_ARRAY;
664           else if (_dbus_string_starts_with_c_str (&line, "UINT32_ARRAY"))
665             code = DBUS_TYPE_UINT32_ARRAY;
666           else if (_dbus_string_starts_with_c_str (&line, "DOUBLE_ARRAY"))
667             code = DBUS_TYPE_DOUBLE_ARRAY;
668           else if (_dbus_string_starts_with_c_str (&line, "BYTE_ARRAY"))
669             code = DBUS_TYPE_BYTE_ARRAY;
670           else if (_dbus_string_starts_with_c_str (&line, "STRING_ARRAY"))
671             code = DBUS_TYPE_STRING_ARRAY;
672           else
673             {
674               const char *s;
675               _dbus_string_get_const_data (&line, &s);
676               _dbus_warn ("%s is not a valid type name\n", s);
677               goto parse_failed;
678             }
679
680           if (!_dbus_string_append_byte (dest, code))
681             {
682               _dbus_warn ("could not append typecode byte\n");
683               goto parse_failed;
684             }
685         }
686       else if (_dbus_string_starts_with_c_str (&line,
687                                                "INT32"))
688         {
689           SAVE_FOR_UNALIGN (dest, 4);
690           long val;
691           
692           strip_command_name (&line);
693
694           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
695             {
696               _dbus_warn ("could not parse integer for INT32\n");
697               goto parse_failed;
698             }
699           
700           if (!_dbus_marshal_int32 (dest, endian,
701                                     val))
702             {
703               _dbus_warn ("failed to append INT32\n");
704               goto parse_failed;
705             }
706
707           PERFORM_UNALIGN (dest);
708         }
709       else if (_dbus_string_starts_with_c_str (&line,
710                                                "UINT32"))
711         {
712           SAVE_FOR_UNALIGN (dest, 4);
713           long val;
714           
715           strip_command_name (&line);
716
717           /* FIXME should have _dbus_string_parse_uint32 */
718           if (!_dbus_string_parse_int (&line, 0, &val, NULL))
719             goto parse_failed;
720           
721           if (!_dbus_marshal_uint32 (dest, endian,
722                                      val))
723             {
724               _dbus_warn ("failed to append UINT32\n");
725               goto parse_failed;
726             }
727
728           PERFORM_UNALIGN (dest);
729         }
730       else if (_dbus_string_starts_with_c_str (&line,
731                                                "DOUBLE"))
732         {
733           SAVE_FOR_UNALIGN (dest, 8);
734           double val;
735           
736           strip_command_name (&line);
737
738           if (!_dbus_string_parse_double (&line, 0, &val, NULL))
739             goto parse_failed;
740           
741           if (!_dbus_marshal_double (dest, endian,
742                                      val))
743             {
744               _dbus_warn ("failed to append DOUBLE\n");
745               goto parse_failed;
746             }
747
748           PERFORM_UNALIGN (dest);
749         }
750       else if (_dbus_string_starts_with_c_str (&line,
751                                                "STRING"))
752         {
753           SAVE_FOR_UNALIGN (dest, 4);
754           int size_offset;
755           int old_len;
756           
757           strip_command_name (&line);
758
759           size_offset = _dbus_string_get_length (dest);
760           size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
761           if (!_dbus_marshal_uint32 (dest, endian, 0))
762             {
763               _dbus_warn ("Failed to append string size\n");
764               goto parse_failed;
765             }
766
767           old_len = _dbus_string_get_length (dest);
768           if (!append_quoted_string (dest, &line))
769             {
770               _dbus_warn ("Failed to append quoted string\n");
771               goto parse_failed;
772             }
773
774           _dbus_marshal_set_uint32 (dest, endian, size_offset,
775                                     /* subtract 1 for nul */
776                                     _dbus_string_get_length (dest) - old_len - 1);
777           
778           PERFORM_UNALIGN (dest);
779         }
780       else
781         goto parse_failed;
782       
783       if (!just_set_unalign && unalign)
784         {
785           _dbus_warn ("UNALIGN prior to something that isn't aligned\n");
786           goto parse_failed;
787         }
788
789       goto next_iteration; /* skip parse_failed */
790       
791     parse_failed:
792       {
793         const char *s;
794         _dbus_string_get_const_data (&line, &s);
795         _dbus_warn ("couldn't process line %d \"%s\"\n",
796                     line_no, s);
797         goto out;
798       }
799     }
800
801   _dbus_hash_iter_init (length_hash, &iter);
802   while (_dbus_hash_iter_next (&iter))
803     {
804       SavedLength *sl = _dbus_hash_iter_get_value (&iter);
805       const char *s;
806
807       _dbus_string_get_const_data (&sl->name, &s);
808       
809       if (sl->length < 0)
810         {
811           _dbus_warn ("Used LENGTH %s but never did END_LENGTH\n",
812                       s);
813           goto out;
814         }
815       else if (sl->offset < 0)
816         {
817           _dbus_warn ("Did END_LENGTH %s but never used LENGTH\n",
818                       s);
819           goto out;
820         }
821       else
822         {
823           if (sl->start < 0)
824             sl->start = 0;
825           
826           _dbus_verbose ("Filling in length %s endian = %d offset = %d start = %d length = %d\n",
827                          s, sl->endian, sl->offset, sl->start, sl->length);
828           _dbus_marshal_set_int32 (dest,
829                                    sl->endian,
830                                    sl->offset,
831                                    sl->length - sl->start);
832         }
833     }
834   
835   retval = TRUE;
836   
837  out:
838   if (length_hash != NULL)
839     _dbus_hash_table_unref (length_hash);
840   
841   _dbus_string_free (&file);
842   _dbus_string_free (&line);
843   return retval;
844 }
845
846 /** @} */
847 #endif /* DBUS_BUILD_TESTS */