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 _dbus_demarshal_byte_array (DBusString *str,
412 unsigned char *retval;
415 len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
417 retval = dbus_malloc (len);
422 _dbus_string_get_const_data_len (str, &data, pos, len);
427 memcpy (retval, data, len);
430 *new_pos = pos + len;
439 * Returns the position right after the end position
440 * end position of a field
442 * @todo warns on invalid type in a message, but
443 * probably the whole message needs to be dumped,
444 * or we might even drop the connection due
445 * to bad protocol. Needs better error handling.
446 * Possible security issue.
448 * @param str a string
449 * @param byte_order the byte order to use
450 * @param pos the pos where the field starts
451 * @param end_pos pointer where the position right
452 * after the end position will follow
453 * @returns TRUE if more data exists after the field
456 _dbus_marshal_get_field_end_pos (DBusString *str,
463 if (pos >= _dbus_string_get_length (str))
466 _dbus_string_get_const_data_len (str, &data, pos, 1);
470 case DBUS_TYPE_INVALID:
474 case DBUS_TYPE_INT32:
475 *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_int32_t)) + sizeof (dbus_int32_t);
479 case DBUS_TYPE_UINT32:
480 *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_uint32_t)) + sizeof (dbus_uint32_t);
484 case DBUS_TYPE_DOUBLE:
485 *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (double)) + sizeof (double);
489 case DBUS_TYPE_STRING:
493 /* Demarshal the length */
494 len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
496 *end_pos = new_pos + len + 1;
501 case DBUS_TYPE_BYTE_ARRAY:
505 /* Demarshal the length */
506 len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
508 *end_pos = new_pos + len;
514 _dbus_warn ("Unknown message field type %d\n", *data);
518 if (*end_pos >= _dbus_string_get_length (str))
525 * If in verbose mode, print a block of binary data.
527 * @todo right now it prints even if not in verbose mode
529 * @param data the data
530 * @param len the length of the data
533 _dbus_verbose_bytes (const unsigned char *data,
537 const unsigned char *aligned;
539 /* Print blanks on first row if appropriate */
540 aligned = _DBUS_ALIGN_ADDRESS (data, 4);
543 _dbus_assert (aligned <= data);
547 _dbus_verbose ("%5d\t%p: ", - (data - aligned), aligned);
548 while (aligned != data)
555 /* now print the bytes */
559 if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
561 _dbus_verbose ("%5d\t%p: ",
567 _dbus_verbose (" '%c' ", data[i]);
569 _dbus_verbose ("0x%s%x ",
570 data[i] <= 0xf ? "0" : "", data[i]);
574 if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
577 _dbus_verbose ("big: %d little: %d",
578 _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
579 _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
581 _dbus_verbose ("\n");
585 _dbus_verbose ("\n");
589 * Dump the given part of the string to verbose log.
591 * @param str the string
592 * @param start the start of range to dump
593 * @param len length of range
596 _dbus_verbose_bytes_of_string (const DBusString *str,
602 _dbus_string_get_const_data_len (str, &d, start, len);
604 _dbus_verbose_bytes (d, len);
609 #ifdef DBUS_BUILD_TESTS
610 #include "dbus-test.h"
614 _dbus_marshal_test (void)
620 if (!_dbus_string_init (&str, _DBUS_INT_MAX))
621 _dbus_assert_not_reached ("failed to init string");
624 /* Marshal doubles */
625 if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14))
626 _dbus_assert_not_reached ("could not marshal double value");
627 _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14);
629 if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
630 _dbus_assert_not_reached ("could not marshal double value");
631 _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14);
633 /* Marshal signed integers */
634 if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678))
635 _dbus_assert_not_reached ("could not marshal signed integer value");
636 _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678);
638 if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678))
639 _dbus_assert_not_reached ("could not marshal signed integer value");
640 _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678);
642 /* Marshal unsigned integers */
643 if (!_dbus_marshal_uint32 (&str, DBUS_BIG_ENDIAN, 0x12345678))
644 _dbus_assert_not_reached ("could not marshal signed integer value");
645 _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == 0x12345678);
647 if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678))
648 _dbus_assert_not_reached ("could not marshal signed integer value");
649 _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678);
651 /* Marshal strings */
652 tmp1 = "This is the dbus test string";
653 if (!_dbus_marshal_string (&str, DBUS_BIG_ENDIAN, tmp1))
654 _dbus_assert_not_reached ("could not marshal string");
655 tmp2 = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, pos, &pos);
656 _dbus_assert (strcmp (tmp1, tmp2) == 0);
659 tmp1 = "This is the dbus test string";
660 if (!_dbus_marshal_string (&str, DBUS_LITTLE_ENDIAN, tmp1))
661 _dbus_assert_not_reached ("could not marshal string");
662 tmp2 = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, pos, &pos);
663 _dbus_assert (strcmp (tmp1, tmp2) == 0);
666 _dbus_string_free (&str);
671 #endif /* DBUS_BUILD_TESTS */