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,
48 dbus_bool_t have_newline;
50 _dbus_string_set_length (dest, 0);
53 if (_dbus_string_find (source, 0, "\n", &eol))
56 eol += 1; /* include newline */
60 eol = _dbus_string_get_length (source);
65 return FALSE; /* eof */
67 if (!_dbus_string_move_len (source, 0, eol,
70 _dbus_warn ("failed to pop line\n");
74 /* dump the newline */
77 _dbus_assert (_dbus_string_get_length (dest) > 0);
78 _dbus_string_set_length (dest,
79 _dbus_string_get_length (dest) - 1);
86 strip_command_name (DBusString *str)
91 if (_dbus_string_find_blank (str, 0, &i))
92 _dbus_string_skip_blank (str, i, &i);
94 _dbus_string_delete (str, 0, i);
98 strip_leading_space (DBusString *str)
103 _dbus_string_skip_blank (str, 0, &i);
106 _dbus_string_delete (str, 0, i);
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 */
119 free_saved_length (void *data)
121 SavedLength *sl = data;
124 return; /* all hash free functions have to accept NULL */
126 _dbus_string_free (&sl->name);
131 ensure_saved_length (DBusHashTable *hash,
132 const DBusString *name)
137 _dbus_string_get_const_data (name, &s);
139 sl = _dbus_hash_table_lookup_string (hash, s);
143 sl = dbus_new0 (SavedLength, 1);
145 if (!_dbus_string_init (&sl->name, _DBUS_INT_MAX))
151 if (!_dbus_string_copy (name, 0, &sl->name, 0))
154 _dbus_string_get_const_data (&sl->name, &s);
156 if (!_dbus_hash_table_insert_string (hash, (char*)s, sl))
167 free_saved_length (sl);
172 save_start (DBusHashTable *hash,
173 const DBusString *name,
178 sl = ensure_saved_length (hash, name);
182 else if (sl->start >= 0)
184 _dbus_warn ("Same START_LENGTH given twice\n");
194 save_length (DBusHashTable *hash,
195 const DBusString *name,
200 sl = ensure_saved_length (hash, name);
204 else if (sl->length >= 0)
206 _dbus_warn ("Same END_LENGTH given twice\n");
216 save_offset (DBusHashTable *hash,
217 const DBusString *name,
223 sl = ensure_saved_length (hash, name);
227 else if (sl->offset >= 0)
229 _dbus_warn ("Same LENGTH given twice\n");
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))
246 /** Deletes the alignment padding */
247 #define PERFORM_UNALIGN(str) \
250 _dbus_string_delete ((str), align_pad_start, \
251 align_pad_end - align_pad_start); \
257 append_quoted_string (DBusString *dest,
258 const DBusString *quoted)
260 dbus_bool_t in_quotes = FALSE;
264 while (i < _dbus_string_get_length (quoted))
268 b = _dbus_string_get_byte (quoted, i);
276 if (!_dbus_string_append_byte (dest, b))
284 else if (b == ' ' || b == '\n' || b == '\t')
285 break; /* end on whitespace if not quoted */
288 if (!_dbus_string_append_byte (dest, b))
296 if (!_dbus_string_append_byte (dest, '\0'))
302 append_saved_length (DBusString *dest,
303 DBusHashTable *length_hash,
304 const DBusString *name,
308 if (!save_offset (length_hash, name,
311 _dbus_warn ("failed to save offset to LENGTH\n");
315 if (!_dbus_marshal_int32 (dest, endian,
318 _dbus_warn ("failed to append a length\n");
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.
330 * The parser isn't very strict, it's just a hack for test programs.
332 * The file format is:
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
350 * Following commands insert aligned data unless
351 * preceded by "UNALIGN":
353 * INT32 <N> marshals an INT32
354 * UINT32 <N> marshals a UINT32
355 * DOUBLE <N> marshals a double
356 * STRING 'Foo' marshals a string
359 * @todo add support for array types INT32_ARRAY { 3, 4, 5, 6 }
362 * @param dest the string to append the message data to
363 * @param filename the filename to load
364 * @returns #TRUE on success
367 _dbus_message_data_load (DBusString *dest,
368 const DBusString *filename)
371 DBusResultCode result;
376 DBusHashTable *length_hash;
383 if (!_dbus_string_init (&file, _DBUS_INT_MAX))
386 if (!_dbus_string_init (&line, _DBUS_INT_MAX))
388 _dbus_string_free (&file);
392 if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS)
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));
402 length_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
405 if (length_hash == NULL)
408 endian = DBUS_COMPILER_BYTE_ORDER;
412 while (pop_line (&file, &line))
414 dbus_bool_t just_set_unalign;
416 just_set_unalign = FALSE;
419 strip_leading_space (&line);
421 if (_dbus_string_get_length (&line) == 0)
426 else if (_dbus_string_starts_with_c_str (&line,
429 /* Ignore this comment */
432 else if (_dbus_string_starts_with_c_str (&line,
438 if (!_dbus_string_append_byte (dest, endian))
440 _dbus_warn ("could not append endianness\n");
447 if (!_dbus_string_append_byte (dest, '\0'))
449 _dbus_warn ("could not append nul pad\n");
455 _dbus_string_init_const (&name, "Header");
456 if (!append_saved_length (dest, length_hash,
457 &name, _dbus_string_get_length (dest),
461 _dbus_string_init_const (&name, "Body");
462 if (!append_saved_length (dest, length_hash,
463 &name, _dbus_string_get_length (dest),
468 if (!_dbus_marshal_int32 (dest, endian, 1))
470 _dbus_warn ("couldn't append client serial\n");
474 else if (_dbus_string_starts_with_c_str (&line,
477 endian = DBUS_BIG_ENDIAN;
479 else if (_dbus_string_starts_with_c_str (&line,
482 endian = DBUS_LITTLE_ENDIAN;
484 else if (_dbus_string_starts_with_c_str (&line,
487 if (endian == DBUS_BIG_ENDIAN)
488 endian = DBUS_LITTLE_ENDIAN;
490 endian = DBUS_BIG_ENDIAN;
492 else if (_dbus_string_starts_with_c_str (&line,
497 strip_command_name (&line);
499 if (!_dbus_string_parse_int (&line, 0, &val, NULL))
501 _dbus_warn ("Failed to parse integer\n");
507 _dbus_warn ("Aligning to %ld boundary is crack\n",
512 if (!_dbus_string_align_length (dest, val))
515 else if (_dbus_string_starts_with_c_str (&line, "UNALIGN"))
518 just_set_unalign = TRUE;
520 else if (_dbus_string_starts_with_c_str (&line, "CHOP"))
524 /* FIXME if you CHOP the offset for a LENGTH
525 * command, we segfault.
528 strip_command_name (&line);
530 if (!_dbus_string_parse_int (&line, 0, &val, NULL))
532 _dbus_warn ("Failed to parse integer to chop\n");
536 if (val > _dbus_string_get_length (dest))
538 _dbus_warn ("Trying to chop %ld bytes but we only have %d\n",
540 _dbus_string_get_length (dest));
544 _dbus_string_shorten (dest, val);
546 else if (_dbus_string_starts_with_c_str (&line, "BYTE"))
548 unsigned char the_byte;
550 strip_command_name (&line);
552 if (_dbus_string_equal_c_str (&line, "'\\''"))
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);
561 if (!_dbus_string_parse_int (&line, 0, &val, NULL))
563 _dbus_warn ("Failed to parse integer for BYTE\n");
569 _dbus_warn ("A byte must be in range 0-255 not %ld\n",
573 the_byte = (unsigned char) val;
576 _dbus_string_append_byte (dest, the_byte);
578 else if (_dbus_string_starts_with_c_str (&line,
581 strip_command_name (&line);
583 if (!save_start (length_hash, &line,
584 _dbus_string_get_length (dest)))
586 _dbus_warn ("failed to save length start\n");
590 else if (_dbus_string_starts_with_c_str (&line,
593 strip_command_name (&line);
595 if (!save_length (length_hash, &line,
596 _dbus_string_get_length (dest)))
598 _dbus_warn ("failed to save length end\n");
602 else if (_dbus_string_starts_with_c_str (&line,
605 SAVE_FOR_UNALIGN (dest, 4);
607 strip_command_name (&line);
609 if (!append_saved_length (dest, length_hash,
611 unalign ? align_pad_start : align_pad_end,
614 _dbus_warn ("failed to add LENGTH\n");
618 PERFORM_UNALIGN (dest);
620 else if (_dbus_string_starts_with_c_str (&line,
623 strip_command_name (&line);
625 if (_dbus_string_get_length (&line) != 4)
628 _dbus_string_get_const_data (&line, &s);
629 _dbus_warn ("Field name must be four characters not \"%s\"\n",
637 _dbus_string_align_length (dest, 4);
639 if (!_dbus_string_copy (&line, 0, dest,
640 _dbus_string_get_length (dest)))
643 else if (_dbus_string_starts_with_c_str (&line,
648 strip_command_name (&line);
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;
675 _dbus_string_get_const_data (&line, &s);
676 _dbus_warn ("%s is not a valid type name\n", s);
680 if (!_dbus_string_append_byte (dest, code))
682 _dbus_warn ("could not append typecode byte\n");
686 else if (_dbus_string_starts_with_c_str (&line,
689 SAVE_FOR_UNALIGN (dest, 4);
692 strip_command_name (&line);
694 if (!_dbus_string_parse_int (&line, 0, &val, NULL))
696 _dbus_warn ("could not parse integer for INT32\n");
700 if (!_dbus_marshal_int32 (dest, endian,
703 _dbus_warn ("failed to append INT32\n");
707 PERFORM_UNALIGN (dest);
709 else if (_dbus_string_starts_with_c_str (&line,
712 SAVE_FOR_UNALIGN (dest, 4);
715 strip_command_name (&line);
717 /* FIXME should have _dbus_string_parse_uint32 */
718 if (!_dbus_string_parse_int (&line, 0, &val, NULL))
721 if (!_dbus_marshal_uint32 (dest, endian,
724 _dbus_warn ("failed to append UINT32\n");
728 PERFORM_UNALIGN (dest);
730 else if (_dbus_string_starts_with_c_str (&line,
733 SAVE_FOR_UNALIGN (dest, 8);
736 strip_command_name (&line);
738 if (!_dbus_string_parse_double (&line, 0, &val, NULL))
741 if (!_dbus_marshal_double (dest, endian,
744 _dbus_warn ("failed to append DOUBLE\n");
748 PERFORM_UNALIGN (dest);
750 else if (_dbus_string_starts_with_c_str (&line,
753 SAVE_FOR_UNALIGN (dest, 4);
757 strip_command_name (&line);
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))
763 _dbus_warn ("Failed to append string size\n");
767 old_len = _dbus_string_get_length (dest);
768 if (!append_quoted_string (dest, &line))
770 _dbus_warn ("Failed to append quoted string\n");
774 _dbus_marshal_set_uint32 (dest, endian, size_offset,
775 /* subtract 1 for nul */
776 _dbus_string_get_length (dest) - old_len - 1);
778 PERFORM_UNALIGN (dest);
783 if (!just_set_unalign && unalign)
785 _dbus_warn ("UNALIGN prior to something that isn't aligned\n");
789 goto next_iteration; /* skip parse_failed */
794 _dbus_string_get_const_data (&line, &s);
795 _dbus_warn ("couldn't process line %d \"%s\"\n",
801 _dbus_hash_iter_init (length_hash, &iter);
802 while (_dbus_hash_iter_next (&iter))
804 SavedLength *sl = _dbus_hash_iter_get_value (&iter);
807 _dbus_string_get_const_data (&sl->name, &s);
811 _dbus_warn ("Used LENGTH %s but never did END_LENGTH\n",
815 else if (sl->offset < 0)
817 _dbus_warn ("Did END_LENGTH %s but never used LENGTH\n",
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,
831 sl->length - sl->start);
838 if (length_hash != NULL)
839 _dbus_hash_table_unref (length_hash);
841 _dbus_string_free (&file);
842 _dbus_string_free (&line);
847 #endif /* DBUS_BUILD_TESTS */