1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-marshal.c Marshalling routines
4 * Copyright (C) 2002 CodeFactory AB
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
24 #include "dbus-marshal.h"
25 #include "dbus-internals.h"
31 swap_bytes (unsigned char *data,
34 unsigned char *p1 = data;
35 unsigned char *p2 = data + len - 1;
39 unsigned char tmp = *p1;
49 * @defgroup DBusMarshal marshaling and unmarshaling
50 * @ingroup DBusInternals
51 * @brief functions to marshal/unmarshal data from the wire
53 * Types and functions related to converting primitive data types from
54 * wire format to native machine format, and vice versa.
60 * Unpacks a 32 bit unsigned integer from a data pointer
62 * @param byte_order The byte order to use
63 * @param data the data pointer
64 * @returns the integer
67 _dbus_unpack_uint32 (int byte_order,
68 const unsigned char *data)
70 _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
72 if (byte_order == DBUS_LITTLE_ENDIAN)
73 return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
75 return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
79 * Unpacks a 32 bit signed integer from a data pointer
81 * @param byte_order The byte order to use
82 * @param data the data pointer
83 * @returns the integer
86 _dbus_unpack_int32 (int byte_order,
87 const unsigned char *data)
89 _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
91 if (byte_order == DBUS_LITTLE_ENDIAN)
92 return DBUS_INT32_FROM_LE (*(dbus_int32_t*)data);
94 return DBUS_INT32_FROM_BE (*(dbus_int32_t*)data);
98 * Packs a 32 bit unsigned integer into a data pointer.
100 * @param value the value
101 * @param byte_order the byte order to use
102 * @param data the data pointer
105 _dbus_pack_uint32 (dbus_uint32_t value,
109 _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
111 if ((byte_order) == DBUS_LITTLE_ENDIAN)
112 *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_LE (value);
114 *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_BE (value);
118 * Packs a 32 bit signed integer into a data pointer.
120 * @param value the value
121 * @param byte_order the byte order to use
122 * @param data the data pointer
125 _dbus_pack_int32 (dbus_int32_t value,
129 _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
131 if ((byte_order) == DBUS_LITTLE_ENDIAN)
132 *((dbus_int32_t*)(data)) = DBUS_INT32_TO_LE (value);
134 *((dbus_int32_t*)(data)) = DBUS_INT32_TO_BE (value);
138 * Marshals a double value.
140 * @param str the string to append the marshalled value to
141 * @param byte_order the byte order to use
142 * @param value the value
143 * @returns #TRUE on success
146 _dbus_marshal_double (DBusString *str,
150 _dbus_assert (sizeof (double) == 8);
152 if (!_dbus_string_set_length (str,
153 _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
157 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
158 swap_bytes ((unsigned char *)&value, sizeof (double));
160 return _dbus_string_append_len (str, (const char *)&value, sizeof (double));
164 * Marshals a 32 bit signed integer value.
166 * @param str the string to append the marshalled value to
167 * @param byte_order the byte order to use
168 * @param value the value
169 * @returns #TRUE on success
172 _dbus_marshal_int32 (DBusString *str,
176 if (!_dbus_string_set_length (str,
177 _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
178 sizeof (dbus_int32_t))))
181 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
182 swap_bytes ((unsigned char *)&value, sizeof (dbus_int32_t));
184 return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_int32_t));
188 * Marshals a 32 bit unsigned integer value.
190 * @param str the string to append the marshalled value to
191 * @param byte_order the byte order to use
192 * @param value the value
193 * @returns #TRUE on success
196 _dbus_marshal_uint32 (DBusString *str,
200 if (!_dbus_string_set_length (str,
201 _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
202 sizeof (dbus_uint32_t))))
205 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
206 swap_bytes ((unsigned char *)&value, sizeof (dbus_uint32_t));
208 return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t));
212 * Marshals a UTF-8 string
214 * @param str the string to append the marshalled value to
215 * @param byte_order the byte order to use
216 * @param value the string
217 * @returns #TRUE on success
220 _dbus_marshal_string (DBusString *str,
224 int len, old_string_len;
226 old_string_len = _dbus_string_get_length (str);
228 len = strlen (value);
230 if (!_dbus_marshal_uint32 (str, byte_order, len))
232 /* Restore the previous length */
233 _dbus_string_set_length (str, old_string_len);
238 return _dbus_string_append_len (str, value, len + 1);
242 * Marshals a byte array
244 * @param str the string to append the marshalled value to
245 * @param byte_order the byte order to use
246 * @param value the byte array
247 * @param len the length of the byte array
248 * @returns #TRUE on success
251 _dbus_marshal_byte_array (DBusString *str,
253 const unsigned char *value,
258 old_string_len = _dbus_string_get_length (str);
260 if (!_dbus_marshal_uint32 (str, byte_order, len))
262 /* Restore the previous length */
263 _dbus_string_set_length (str, old_string_len);
268 return _dbus_string_append_len (str, value, len);
272 * Demarshals a double.
274 * @param str the string containing the data
275 * @param byte_order the byte order
276 * @param pos the position in the string
277 * @param new_pos the new position of the string
278 * @returns the demarshaled double.
281 _dbus_demarshal_double (DBusString *str,
289 pos = _DBUS_ALIGN_VALUE (pos, sizeof (double));
291 _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (double));
293 retval = *(double *)buffer;
295 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
296 swap_bytes ((unsigned char *)&retval, sizeof (double));
299 *new_pos = pos + sizeof (double);
305 * Demarshals a 32 bit signed integer.
307 * @param str the string containing the data
308 * @param byte_order the byte order
309 * @param pos the position in the string
310 * @param new_pos the new position of the string
311 * @returns the demarshaled integer.
314 _dbus_demarshal_int32 (DBusString *str,
321 pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t));
323 _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_int32_t));
326 *new_pos = pos + sizeof (dbus_int32_t);
328 return _dbus_unpack_int32 (byte_order, buffer);
332 * Demarshals a 32 bit unsigned integer.
334 * @param str the string containing the data
335 * @param byte_order the byte order
336 * @param pos the position in the string
337 * @param new_pos the new position of the string
338 * @returns the demarshaled integer.
341 _dbus_demarshal_uint32 (DBusString *str,
348 pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
350 _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_uint32_t));
353 *new_pos = pos + sizeof (dbus_uint32_t);
355 return _dbus_unpack_uint32 (byte_order, buffer);
359 * Demarshals an UTF-8 string.
361 * @todo Should we check the string to make sure
362 * that it's valid UTF-8, and maybe "fix" the string
365 * @todo Should probably demarshal to a DBusString,
366 * having memcpy() in here is Evil(tm).
368 * @param str the string containing the data
369 * @param byte_order the byte order
370 * @param pos the position in the string
371 * @param new_pos the new position of the string
372 * @returns the demarshaled string.
375 _dbus_demarshal_string (DBusString *str,
384 len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
386 retval = dbus_malloc (len + 1);
391 _dbus_string_get_const_data_len (str, &data, pos, len);
396 memcpy (retval, data, len + 1);
399 *new_pos = pos + len + 1;
405 * Demarshals a byte array.
407 * @todo Should probably demarshal to a DBusString,
408 * having memcpy() in here is Evil(tm).
410 * @param str the string containing the data
411 * @param byte_order the byte order
412 * @param pos the position in the string
413 * @param new_pos the new position of the string
414 * @param array_len length of the demarshaled data
415 * @returns the demarshaled data.
418 _dbus_demarshal_byte_array (DBusString *str,
425 unsigned char *retval;
428 len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
430 retval = dbus_malloc (len);
435 _dbus_string_get_const_data_len (str, &data, pos, len);
440 memcpy (retval, data, len);
443 *new_pos = pos + len;
452 * Returns the position right after the end position
453 * end position of a field
455 * @todo warns on invalid type in a message, but
456 * probably the whole message needs to be dumped,
457 * or we might even drop the connection due
458 * to bad protocol. Needs better error handling.
459 * Possible security issue.
461 * @param str a string
462 * @param byte_order the byte order to use
463 * @param pos the pos where the field starts
464 * @param end_pos pointer where the position right
465 * after the end position will follow
466 * @returns TRUE if more data exists after the field
469 _dbus_marshal_get_field_end_pos (DBusString *str,
476 if (pos >= _dbus_string_get_length (str))
479 _dbus_string_get_const_data_len (str, &data, pos, 1);
483 case DBUS_TYPE_INVALID:
487 case DBUS_TYPE_INT32:
488 *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_int32_t)) + sizeof (dbus_int32_t);
492 case DBUS_TYPE_UINT32:
493 *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_uint32_t)) + sizeof (dbus_uint32_t);
497 case DBUS_TYPE_DOUBLE:
498 *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (double)) + sizeof (double);
502 case DBUS_TYPE_STRING:
506 /* Demarshal the length */
507 len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
509 *end_pos = new_pos + len + 1;
514 case DBUS_TYPE_BYTE_ARRAY:
518 /* Demarshal the length */
519 len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
521 *end_pos = new_pos + len;
527 _dbus_warn ("Unknown message field type %d\n", *data);
531 if (*end_pos >= _dbus_string_get_length (str))
538 * If in verbose mode, print a block of binary data.
540 * @todo right now it prints even if not in verbose mode
542 * @param data the data
543 * @param len the length of the data
546 _dbus_verbose_bytes (const unsigned char *data,
550 const unsigned char *aligned;
552 /* Print blanks on first row if appropriate */
553 aligned = _DBUS_ALIGN_ADDRESS (data, 4);
556 _dbus_assert (aligned <= data);
560 _dbus_verbose ("%5d\t%p: ", - (data - aligned), aligned);
561 while (aligned != data)
568 /* now print the bytes */
572 if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
574 _dbus_verbose ("%5d\t%p: ",
580 _dbus_verbose (" '%c' ", data[i]);
582 _dbus_verbose ("0x%s%x ",
583 data[i] <= 0xf ? "0" : "", data[i]);
587 if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
590 _dbus_verbose ("big: %d little: %d",
591 _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
592 _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
594 _dbus_verbose ("\n");
598 _dbus_verbose ("\n");
602 * Dump the given part of the string to verbose log.
604 * @param str the string
605 * @param start the start of range to dump
606 * @param len length of range
609 _dbus_verbose_bytes_of_string (const DBusString *str,
615 _dbus_string_get_const_data_len (str, &d, start, len);
617 _dbus_verbose_bytes (d, len);
622 #ifdef DBUS_BUILD_TESTS
623 #include "dbus-test.h"
627 _dbus_marshal_test (void)
633 if (!_dbus_string_init (&str, _DBUS_INT_MAX))
634 _dbus_assert_not_reached ("failed to init string");
637 /* Marshal doubles */
638 if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14))
639 _dbus_assert_not_reached ("could not marshal double value");
640 _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14);
642 if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
643 _dbus_assert_not_reached ("could not marshal double value");
644 _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14);
646 /* Marshal signed integers */
647 if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678))
648 _dbus_assert_not_reached ("could not marshal signed integer value");
649 _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678);
651 if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678))
652 _dbus_assert_not_reached ("could not marshal signed integer value");
653 _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678);
655 /* Marshal unsigned integers */
656 if (!_dbus_marshal_uint32 (&str, DBUS_BIG_ENDIAN, 0x12345678))
657 _dbus_assert_not_reached ("could not marshal signed integer value");
658 _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == 0x12345678);
660 if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678))
661 _dbus_assert_not_reached ("could not marshal signed integer value");
662 _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678);
664 /* Marshal strings */
665 tmp1 = "This is the dbus test string";
666 if (!_dbus_marshal_string (&str, DBUS_BIG_ENDIAN, tmp1))
667 _dbus_assert_not_reached ("could not marshal string");
668 tmp2 = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, pos, &pos);
669 _dbus_assert (strcmp (tmp1, tmp2) == 0);
672 tmp1 = "This is the dbus test string";
673 if (!_dbus_marshal_string (&str, DBUS_LITTLE_ENDIAN, tmp1))
674 _dbus_assert_not_reached ("could not marshal string");
675 tmp2 = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, pos, &pos);
676 _dbus_assert (strcmp (tmp1, tmp2) == 0);
679 _dbus_string_free (&str);
684 #endif /* DBUS_BUILD_TESTS */