1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message-builder.c Build messages from text files for testing (internal to D-BUS implementation)
4 * Copyright (C) 2003 Red Hat, Inc.
6 * Licensed under the Academic Free License version 1.2
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.
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.
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
25 #ifdef DBUS_BUILD_TESTS
27 #include "dbus-message-builder.h"
28 #include "dbus-hash.h"
29 #include "dbus-internals.h"
30 #include "dbus-marshal.h"
33 * @defgroup DBusMessageBuilder code for loading test message data
34 * @ingroup DBusInternals
35 * @brief code for loading up test data for unit tests
37 * The code in here is used for unit testing, it loads
38 * up message data from a description in a file.
44 pop_line (DBusString *source,
49 _dbus_string_set_length (dest, 0);
52 if (_dbus_string_find (source, 0, "\n", &eol))
53 eol += 1; /* include newline */
55 eol = _dbus_string_get_length (source);
59 _dbus_verbose ("no more data in file\n");
63 if (!_dbus_string_move_len (source, 0, eol,
66 _dbus_warn ("failed to pop line\n");
70 /* dump the newline */
71 _dbus_string_set_length (dest,
72 _dbus_string_get_length (dest) - 1);
78 strip_command_name (DBusString *str)
83 if (_dbus_string_find_blank (str, 0, &i))
84 _dbus_string_skip_blank (str, i, &i);
86 _dbus_string_delete (str, 0, i);
90 strip_leading_space (DBusString *str)
95 _dbus_string_skip_blank (str, 0, &i);
98 _dbus_string_delete (str, 0, i);
104 int length; /**< length to write */
105 int offset; /**< where to write it into the data */
106 int endian; /**< endianness to write with */
110 free_saved_length (void *data)
112 SavedLength *sl = data;
114 _dbus_string_free (&sl->name);
119 ensure_saved_length (DBusHashTable *hash,
120 const DBusString *name)
125 _dbus_string_get_const_data (name, &s);
127 sl = _dbus_hash_table_lookup_string (hash, s);
131 sl = dbus_new0 (SavedLength, 1);
133 if (!_dbus_string_init (&sl->name, _DBUS_INT_MAX))
139 if (!_dbus_string_copy (name, 0, &sl->name, 0))
142 _dbus_string_get_const_data (&sl->name, &s);
144 if (!_dbus_hash_table_insert_string (hash, (char*)s, sl))
154 free_saved_length (sl);
159 save_length (DBusHashTable *hash,
160 const DBusString *name,
165 sl = ensure_saved_length (hash, name);
169 else if (sl->length >= 0)
171 _dbus_warn ("Same SAVE_LENGTH given twice\n");
181 save_offset (DBusHashTable *hash,
182 const DBusString *name,
188 sl = ensure_saved_length (hash, name);
192 else if (sl->offset >= 0)
194 _dbus_warn ("Same LENGTH given twice\n");
206 /** Saves the segment to delete in order to unalign the next item */
207 #define SAVE_FOR_UNALIGN(str, boundary) \
208 int align_pad_start = _dbus_string_get_length (str); \
209 int align_pad_end = _DBUS_ALIGN_VALUE (align_pad_start, (boundary))
211 /** Deletes the alignment padding */
212 #define PERFORM_UNALIGN(str) \
215 _dbus_string_delete ((str), align_pad_start, \
216 align_pad_end - align_pad_start); \
222 append_quoted_string (DBusString *dest,
223 const DBusString *quoted)
225 dbus_bool_t in_quotes = FALSE;
229 while (i < _dbus_string_get_length (quoted))
233 b = _dbus_string_get_byte (quoted, i);
241 if (!_dbus_string_append_byte (dest, b))
249 else if (b == ' ' || b == '\n' || b == '\t')
250 break; /* end on whitespace if not quoted */
253 if (!_dbus_string_append_byte (dest, b))
261 if (!_dbus_string_append_byte (dest, '\0'))
267 append_saved_length (DBusString *dest,
268 DBusHashTable *length_hash,
269 const DBusString *name,
273 if (!save_offset (length_hash, name,
276 _dbus_warn ("failed to save offset to LENGTH\n");
280 if (!_dbus_marshal_int32 (dest, endian,
283 _dbus_warn ("failed to append a length\n");
291 * Reads the given filename, which should be in "message description
292 * language" (look at some examples), and builds up the message data
293 * from it. The message data may be invalid, or valid.
295 * The parser isn't very strict, it's just a hack for test programs.
297 * The file format is:
299 * VALID_HEADER normal header; byte order, padding, header len, body len, serial
300 * BIG_ENDIAN switch to big endian
301 * LITTLE_ENDIAN switch to little endian
302 * OPPOSITE_ENDIAN switch to opposite endian
303 * ALIGN <N> aligns to the given value
304 * UNALIGN skips alignment for the next marshal
305 * BYTE <N> inserts the given integer in [0,255] or char in 'a' format
306 * SAVE_LENGTH <name> records the current length under the given name
307 * LENGTH <name> inserts the saved length of the same name
308 * CHOP <N> chops last N bytes off the data
309 * FIELD_NAME <abcd> inserts 4-byte field name
310 * TYPE <typename> inserts a typecode byte
313 * Following commands insert aligned data unless
314 * preceded by "UNALIGN":
316 * INT32 <N> marshals an INT32
317 * UINT32 <N> marshals a UINT32
318 * DOUBLE <N> marshals a double
319 * STRING 'Foo' marshals a string
322 * @todo add support for array types INT32_ARRAY { 3, 4, 5, 6 }
325 * @param dest the string to append the message data to
326 * @param filename the filename to load
327 * @returns #TRUE on success
330 _dbus_message_data_load (DBusString *dest,
331 const DBusString *filename)
334 DBusResultCode result;
339 DBusHashTable *length_hash;
346 if (!_dbus_string_init (&file, _DBUS_INT_MAX))
349 if (!_dbus_string_init (&line, _DBUS_INT_MAX))
351 _dbus_string_free (&file);
355 if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS)
358 _dbus_string_get_const_data (filename, &s);
359 _dbus_warn ("Getting contents of %s failed: %s\n",
360 s, dbus_result_to_string (result));
365 length_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
368 if (length_hash == NULL)
371 endian = DBUS_COMPILER_BYTE_ORDER;
375 while (pop_line (&file, &line))
377 dbus_bool_t just_set_unalign;
379 just_set_unalign = FALSE;
382 strip_leading_space (&line);
384 if (_dbus_string_starts_with_c_str (&line,
387 /* Ignore this comment */
390 else if (_dbus_string_starts_with_c_str (&line,
396 if (!_dbus_string_append_byte (dest, endian))
398 _dbus_warn ("could not append endianness\n");
405 if (!_dbus_string_append_byte (dest, '\0'))
407 _dbus_warn ("could not append nul pad\n");
413 _dbus_string_init_const (&name, "Header");
414 if (!append_saved_length (dest, length_hash,
415 &name, _dbus_string_get_length (dest),
419 _dbus_string_init_const (&name, "Body");
420 if (!append_saved_length (dest, length_hash,
421 &name, _dbus_string_get_length (dest),
426 if (!_dbus_marshal_int32 (dest, endian, 1))
428 _dbus_warn ("couldn't append client serial\n");
432 else if (_dbus_string_starts_with_c_str (&line,
435 endian = DBUS_BIG_ENDIAN;
437 else if (_dbus_string_starts_with_c_str (&line,
440 endian = DBUS_LITTLE_ENDIAN;
442 else if (_dbus_string_starts_with_c_str (&line,
445 if (endian == DBUS_BIG_ENDIAN)
446 endian = DBUS_LITTLE_ENDIAN;
448 endian = DBUS_BIG_ENDIAN;
450 else if (_dbus_string_starts_with_c_str (&line,
455 strip_command_name (&line);
457 if (!_dbus_string_parse_int (&line, 0, &val, NULL))
462 _dbus_warn ("Aligning to %ld boundary is crack\n",
467 if (!_dbus_string_align_length (dest, val))
470 else if (_dbus_string_starts_with_c_str (&line, "UNALIGN"))
473 just_set_unalign = TRUE;
475 else if (_dbus_string_starts_with_c_str (&line, "CHOP"))
479 /* FIXME if you CHOP the offset for a LENGTH
480 * command, we segfault.
483 strip_command_name (&line);
485 if (!_dbus_string_parse_int (&line, 0, &val, NULL))
488 if (val > _dbus_string_get_length (dest))
490 _dbus_warn ("Trying to chop %ld bytes but we only have %d\n",
492 _dbus_string_get_length (dest));
496 _dbus_string_shorten (dest, val);
498 else if (_dbus_string_starts_with_c_str (&line, "BYTE"))
500 unsigned char the_byte;
502 strip_command_name (&line);
504 if (_dbus_string_equal_c_str (&line, "'\\''"))
506 else if (_dbus_string_get_byte (&line, 0) == '\'' &&
507 _dbus_string_get_length (&line) >= 3 &&
508 _dbus_string_get_byte (&line, 2) == '\'')
509 the_byte = _dbus_string_get_byte (&line, 1);
513 if (!_dbus_string_parse_int (&line, 0, &val, NULL))
517 _dbus_warn ("A byte must be in range 0-255 not %ld\n",
521 the_byte = (unsigned char) val;
524 _dbus_string_append_byte (dest, the_byte);
526 else if (_dbus_string_starts_with_c_str (&line,
529 strip_command_name (&line);
531 if (!save_length (length_hash, &line,
532 _dbus_string_get_length (dest)))
534 _dbus_warn ("failed to save length\n");
538 else if (_dbus_string_starts_with_c_str (&line,
541 SAVE_FOR_UNALIGN (dest, 4);
543 strip_command_name (&line);
545 if (!append_saved_length (dest, length_hash,
547 unalign ? align_pad_start : align_pad_end,
550 _dbus_warn ("failed to add LENGTH\n");
554 PERFORM_UNALIGN (dest);
556 else if (_dbus_string_starts_with_c_str (&line,
559 strip_command_name (&line);
561 if (_dbus_string_get_length (&line) != 4)
564 _dbus_string_get_const_data (&line, &s);
565 _dbus_warn ("Field name must be four characters not \"%s\"\n",
573 _dbus_string_align_length (dest, 4);
575 if (!_dbus_string_copy (&line, 0, dest,
576 _dbus_string_get_length (dest)))
579 else if (_dbus_string_starts_with_c_str (&line,
584 strip_command_name (&line);
586 if (_dbus_string_starts_with_c_str (&line, "INVALID"))
587 code = DBUS_TYPE_INVALID;
588 else if (_dbus_string_starts_with_c_str (&line, "NIL"))
589 code = DBUS_TYPE_NIL;
590 else if (_dbus_string_starts_with_c_str (&line, "INT32"))
591 code = DBUS_TYPE_INT32;
592 else if (_dbus_string_starts_with_c_str (&line, "UINT32"))
593 code = DBUS_TYPE_UINT32;
594 else if (_dbus_string_starts_with_c_str (&line, "DOUBLE"))
595 code = DBUS_TYPE_DOUBLE;
596 else if (_dbus_string_starts_with_c_str (&line, "STRING"))
597 code = DBUS_TYPE_STRING;
598 else if (_dbus_string_starts_with_c_str (&line, "INT32_ARRAY"))
599 code = DBUS_TYPE_INT32_ARRAY;
600 else if (_dbus_string_starts_with_c_str (&line, "UINT32_ARRAY"))
601 code = DBUS_TYPE_UINT32_ARRAY;
602 else if (_dbus_string_starts_with_c_str (&line, "DOUBLE_ARRAY"))
603 code = DBUS_TYPE_DOUBLE_ARRAY;
604 else if (_dbus_string_starts_with_c_str (&line, "BYTE_ARRAY"))
605 code = DBUS_TYPE_BYTE_ARRAY;
606 else if (_dbus_string_starts_with_c_str (&line, "STRING_ARRAY"))
607 code = DBUS_TYPE_STRING_ARRAY;
611 _dbus_string_get_const_data (&line, &s);
612 _dbus_warn ("%s is not a valid type name\n", s);
616 if (!_dbus_string_append_byte (dest, code))
618 _dbus_warn ("could not append typecode byte\n");
622 else if (_dbus_string_starts_with_c_str (&line,
625 SAVE_FOR_UNALIGN (dest, 4);
628 strip_command_name (&line);
630 if (!_dbus_string_parse_int (&line, 0, &val, NULL))
633 if (!_dbus_marshal_int32 (dest, endian,
636 _dbus_warn ("failed to append INT32\n");
640 PERFORM_UNALIGN (dest);
642 else if (_dbus_string_starts_with_c_str (&line,
645 SAVE_FOR_UNALIGN (dest, 4);
648 strip_command_name (&line);
650 /* FIXME should have _dbus_string_parse_uint32 */
651 if (!_dbus_string_parse_int (&line, 0, &val, NULL))
654 if (!_dbus_marshal_uint32 (dest, endian,
657 _dbus_warn ("failed to append UINT32\n");
661 PERFORM_UNALIGN (dest);
663 else if (_dbus_string_starts_with_c_str (&line,
666 SAVE_FOR_UNALIGN (dest, 8);
669 strip_command_name (&line);
671 if (!_dbus_string_parse_double (&line, 0, &val, NULL))
674 if (!_dbus_marshal_double (dest, endian,
677 _dbus_warn ("failed to append DOUBLE\n");
681 PERFORM_UNALIGN (dest);
683 else if (_dbus_string_starts_with_c_str (&line,
686 SAVE_FOR_UNALIGN (dest, 4);
690 strip_command_name (&line);
692 size_offset = _dbus_string_get_length (dest);
693 size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
694 if (!_dbus_marshal_uint32 (dest, endian, 0))
696 _dbus_warn ("Failed to append string size\n");
700 old_len = _dbus_string_get_length (dest);
701 if (!append_quoted_string (dest, &line))
703 _dbus_warn ("Failed to append quoted string\n");
707 _dbus_marshal_set_uint32 (dest, endian, size_offset,
708 /* subtract 1 for nul */
709 _dbus_string_get_length (dest) - old_len - 1);
711 PERFORM_UNALIGN (dest);
716 if (!just_set_unalign && unalign)
718 _dbus_warn ("UNALIGN prior to something that isn't aligned\n");
722 goto next_iteration; /* skip parse_failed */
727 _dbus_string_get_const_data (&line, &s);
728 _dbus_warn ("couldn't process line %d \"%s\"\n",
734 _dbus_hash_iter_init (length_hash, &iter);
735 while (_dbus_hash_iter_next (&iter))
737 SavedLength *sl = _dbus_hash_iter_get_value (&iter);
740 _dbus_string_get_const_data (&sl->name, &s);
744 _dbus_warn ("Used LENGTH %s but never did SAVE_LENGTH\n",
748 else if (sl->offset < 0)
750 _dbus_warn ("Did SAVE_LENGTH %s but never used LENGTH\n",
756 _dbus_verbose ("Filling in length %s endian = %d offset = %d length = %d\n",
757 s, sl->endian, sl->offset, sl->length);
758 _dbus_marshal_set_int32 (dest,
768 if (length_hash != NULL)
769 _dbus_hash_table_unref (length_hash);
771 _dbus_string_free (&file);
772 _dbus_string_free (&line);
777 #endif /* DBUS_BUILD_TESTS */