1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-marshal-gvariant.c Marshalling routines for GVariant protocol
4 * Copyright (C) 2015 Samsung Electronics
6 * Licensed under the Academic Free License version 2.1
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "dbus-internals.h"
26 #include "dbus-marshal-gvariant.h"
27 #include "dbus-protocol-gvariant.h"
28 #include "dbus-marshal-basic.h"
29 #include "dbus-message-private.h"
30 #include "dbus-signature.h"
31 #include "dbus-connection-internal.h"
34 /** Static #DBusString containing the signature of a message header */
35 _DBUS_STRING_DEFINE_STATIC(_dbus_header_gvariant_signature_str, DBUS_HEADER_GVARIANT_SIGNATURE);
38 _dbus_reader_get_signature_fixed_size (const DBusString *signature, int *pos, int *alignment, int depth);
40 #define FIELD_ID_SIZE sizeof(dbus_uint64_t)
43 _dbus_get_gvariant_header_signature_str (void)
45 return &_dbus_header_gvariant_signature_str;
49 append_sized_value (DBusString *str,
53 /* always write as little endian */
55 for (i = 0; i < value_size; i++)
58 dbus_uint64_t mask = 0xFFull << move;
59 if (!_dbus_string_append_byte(str, (value & mask) >> move))
65 #define MAX_OFFSET_SIZE 8
66 #define MAX_VALUE_FOR_OFFSET_SIZE(o) ((1ULL<<(8*(o)))-1)
68 /* taken from systemd */
70 bus_gvariant_determine_word_size(size_t sz, size_t extra)
72 if (sz + extra <= 0xFF)
74 else if (sz + extra*2 <= 0xFFFF)
76 else if (sz + extra*4 <= 0xFFFFFFFF)
82 /* taken from systemd */
84 bus_gvariant_read_word_le (const void *p, size_t sz)
101 return le16toh(x.u16);
103 return le32toh(x.u32);
105 return le64toh(x.u64);
110 get_header_const_array (DBusHeader *header)
112 return _dbus_string_get_const_data (&header->data) + FIRST_GVARIANT_FIELD_OFFSET;
116 get_header_array_size (DBusHeader *header)
118 return _dbus_string_get_length (&header->data) - FIRST_GVARIANT_FIELD_OFFSET - header->padding;
122 append_offsets (DBusString *str,
123 size_t *fields_offsets,
124 size_t n_fields_offsets)
127 size_t array_size = _dbus_string_get_length (str) - FIRST_GVARIANT_FIELD_OFFSET;
128 size_t offset_size = bus_gvariant_determine_word_size (array_size, n_fields_offsets);
130 for (i = 0; i < n_fields_offsets; i++)
132 if (!append_sized_value (str, fields_offsets[i], offset_size))
139 append_field_string (DBusString *str,
143 size_t *fields_offsets,
144 size_t *n_fields_offsets)
146 dbus_bool_t res = TRUE;
148 if (*n_fields_offsets >= DBUS_HEADER_FIELD_LAST)
153 res = res && _dbus_string_align_length(str, 8);
154 res = res && append_sized_value(str, field, FIELD_ID_SIZE);
155 res = res && _dbus_string_append_len(str, value, strlen(value)+1);
156 res = res && _dbus_string_append_byte(str, 0); /* variant value-signature separator */
157 res = res && _dbus_string_append_byte(str, type);
158 fields_offsets[(*n_fields_offsets)++] = _dbus_string_get_length(str) - FIRST_GVARIANT_FIELD_OFFSET;
164 append_field_uint64 (DBusString *str,
167 size_t *fields_offsets,
168 size_t *n_fields_offsets)
170 dbus_bool_t res = TRUE;
172 if (*n_fields_offsets >= DBUS_HEADER_FIELD_LAST)
175 res = res && _dbus_string_align_length(str, 8);
176 res = res && append_sized_value(str, field, FIELD_ID_SIZE);
177 res = res && append_sized_value(str, value, 8);
178 res = res && _dbus_string_append_byte(str, 0); /* variant value-signature separator */
179 res = res && _dbus_string_append_byte(str, DBUS_TYPE_UINT64);
180 fields_offsets[(*n_fields_offsets)++] = _dbus_string_get_length(str) - FIRST_GVARIANT_FIELD_OFFSET;
185 append_field_uint32 (DBusString *str,
188 size_t *fields_offsets,
189 size_t *n_fields_offsets)
191 dbus_bool_t res = TRUE;
193 if (*n_fields_offsets >= DBUS_HEADER_FIELD_LAST)
196 res = res && _dbus_string_align_length(str, 8);
197 res = res && append_sized_value(str, field, FIELD_ID_SIZE);
198 res = res && append_sized_value(str, value, 4);
199 res = res && _dbus_string_append_byte(str, 0); /* variant value-signature separator */
200 res = res && _dbus_string_append_byte(str, DBUS_TYPE_UINT32);
201 fields_offsets[(*n_fields_offsets)++] = _dbus_string_get_length(str) - FIRST_GVARIANT_FIELD_OFFSET;
206 _dbus_header_toggle_gvariant (DBusHeader *header, dbus_bool_t gvariant)
208 header->protocol_version = gvariant ? DBUS_PROTOCOL_VERSION_GVARIANT : DBUS_MAJOR_PROTOCOL_VERSION;
212 get_next_field_address (const char *array_buffer, size_t offset)
214 return (uintptr_t)array_buffer + _DBUS_ALIGN_VALUE(offset, 8);
218 get_field_after (const char *array_buffer, size_t offset)
220 return *(dbus_uint64_t*)(get_next_field_address(array_buffer, offset));
224 _dbus_header_fill_cache (DBusHeader *header,
225 size_t *fields_offsets,
226 size_t n_fields_offsets)
228 const char *array_buffer = get_header_const_array (header);
231 if (get_header_array_size (header) > 0)
233 header->fields[get_field_after (array_buffer, 0)].value_pos = FIELD_ID_SIZE + FIRST_GVARIANT_FIELD_OFFSET;
234 for (i=0; i < n_fields_offsets-1; i++)
236 dbus_uint64_t field = get_field_after (array_buffer, fields_offsets[i]);
237 header->fields[field].value_pos = _DBUS_ALIGN_VALUE(fields_offsets[i],8) +
238 FIELD_ID_SIZE + FIRST_GVARIANT_FIELD_OFFSET;
244 correct_header_padding (DBusHeader *header)
246 int unpadded_len = _dbus_string_get_length (&header->data);
247 if (!_dbus_string_align_length (&header->data, 8))
250 header->padding = _dbus_string_get_length (&header->data) - unpadded_len;
255 _dbus_header_gvariant_create (DBusHeader *header,
258 const char *destination,
260 const char *interface,
262 const char *error_name)
264 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
265 size_t n_fields_offsets = 0;
266 dbus_bool_t res = TRUE;
268 _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
269 byte_order == DBUS_BIG_ENDIAN);
270 _dbus_assert (((interface || type != DBUS_MESSAGE_TYPE_SIGNAL) && member) ||
272 !(interface || member || error_name));
273 _dbus_assert (_dbus_string_get_length (&header->data) == 0);
275 _dbus_header_toggle_gvariant (header, TRUE);
277 res = res && _dbus_string_append_byte (&header->data, byte_order);
278 res = res && _dbus_string_append_byte (&header->data, type);
279 res = res && _dbus_string_append_byte (&header->data, 0); /* flags */
280 res = res && _dbus_string_append_byte (&header->data, DBUS_PROTOCOL_VERSION_GVARIANT);
281 res = res && append_sized_value (&header->data, 0, sizeof(dbus_uint32_t)); /* reserved */
282 res = res && append_sized_value (&header->data, 0, sizeof(dbus_uint64_t)); /* cookie */
283 /* array of fields */
284 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_PATH, path, DBUS_TYPE_OBJECT_PATH,
285 fields_offsets, &n_fields_offsets);
286 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_DESTINATION, destination, DBUS_TYPE_STRING,
287 fields_offsets, &n_fields_offsets);
288 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_INTERFACE, interface, DBUS_TYPE_STRING,
289 fields_offsets, &n_fields_offsets);
290 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_MEMBER, member, DBUS_TYPE_STRING,
291 fields_offsets, &n_fields_offsets);
292 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_ERROR_NAME, error_name, DBUS_TYPE_STRING,
293 fields_offsets, &n_fields_offsets);
294 res = res && append_offsets (&header->data, fields_offsets, n_fields_offsets);
296 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
297 res = res && correct_header_padding (header);
303 marshal_gvariant_string (DBusString *str,
307 dbus_bool_t with_nul)
309 DBusString value_str;
310 size_t value_len = strlen(value);
315 _dbus_string_init_const_len (&value_str, value, value_len);
316 if (!_dbus_string_copy_len (&value_str, 0, value_len, str, insert_at))
322 *pos_after = insert_at + value_len;
328 _dbus_marshal_write_gvariant_basic (DBusString *str,
335 const DBusBasicValue *vp;
336 _dbus_assert (dbus_type_is_basic (type));
342 case DBUS_TYPE_STRING:
343 case DBUS_TYPE_OBJECT_PATH:
344 case DBUS_TYPE_SIGNATURE:
345 return marshal_gvariant_string (str, insert_at, vp->str, pos_after, TRUE);
346 case DBUS_TYPE_BOOLEAN:
349 return _dbus_string_insert_byte (str, insert_at, vp->u32 != FALSE);
351 return _dbus_marshal_write_basic (str, insert_at, type, value, byte_order, pos_after);
356 _dbus_marshal_read_gvariant_basic (const DBusString *str,
363 const char *str_data;
365 _dbus_assert (dbus_type_is_basic (type));
367 str_data = _dbus_string_get_const_data (str);
370 case DBUS_TYPE_STRING:
371 case DBUS_TYPE_OBJECT_PATH:
372 case DBUS_TYPE_SIGNATURE:
374 volatile char **vp = value;
375 *vp = (char*) str_data + pos;
376 pos += strlen (str_data+pos)+1;
379 case DBUS_TYPE_BOOLEAN:
381 volatile dbus_bool_t *vp = value;
382 *vp = (dbus_bool_t) _dbus_string_get_byte (str, pos);
387 _dbus_marshal_read_basic (str, pos, type, value, byte_order, new_pos);
396 get_offsets (const char *buffer, size_t container_size,
397 size_t *fields_offsets, size_t *n_fields_offsets,
400 *offset_size = bus_gvariant_determine_word_size (container_size, 0);
402 if (0 < container_size && 0 < *offset_size)
404 size_t last_offset_position = container_size - (*offset_size);
405 size_t last_offset = bus_gvariant_read_word_le (buffer + last_offset_position,
409 *n_fields_offsets = (container_size - last_offset) / (*offset_size);
411 if (*n_fields_offsets == 0 || *n_fields_offsets >= DBUS_HEADER_FIELD_LAST)
414 fields_offsets[(*n_fields_offsets)-1] = last_offset;
415 for (i = 0; i < (*n_fields_offsets)-1; i++)
417 fields_offsets[i] = bus_gvariant_read_word_le (buffer + last_offset + i*(*offset_size),
424 find_field (int field, const char *array_buffer, size_t *fields_offsets, size_t n_fields_offsets,
425 size_t *field_offset)
427 /* last_offset points to the offsets array, beyond the last element of the array container */
428 size_t last_offset = fields_offsets[n_fields_offsets-1];
430 size_t next_offset = 0;
432 while ( next_offset < last_offset &&
433 get_field_after (array_buffer, next_offset) != (dbus_uint64_t) field)
435 next_offset = fields_offsets[i];
438 if (next_offset < last_offset)
440 *field_offset = next_offset;
447 _dbus_header_gvariant_delete_field (DBusHeader *header,
450 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
451 size_t n_fields_offsets = 0;
452 size_t offset_size = 0;
453 const char *array_buffer;
455 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
457 array_buffer = get_header_const_array (header);
459 get_offsets (array_buffer,
460 get_header_array_size (header),
461 fields_offsets, &n_fields_offsets, &offset_size );
463 if (0 < n_fields_offsets)
465 /* check if the field is already in the header */
467 int field_index = find_field (field, array_buffer, fields_offsets, n_fields_offsets, &field_offset);
469 /* prepare for changing - remove array offsets and offsets */
470 _dbus_string_shorten (&header->data, n_fields_offsets*offset_size + header->padding);
472 if (field_index >= 0)
475 size_t field_len = 0;
476 size_t field_start = 0;
477 /* let's remove aligned block of the field, along with padding */
478 if (field_index == 0)
480 field_len = _DBUS_ALIGN_VALUE (fields_offsets[0],8);
484 field_len = _DBUS_ALIGN_VALUE (fields_offsets[field_index],8) -
485 _DBUS_ALIGN_VALUE (fields_offsets[field_index-1],8);
488 field_start = FIRST_GVARIANT_FIELD_OFFSET + _DBUS_ALIGN_VALUE (field_offset, 8);
490 /* if this is the last field, then there is no padding at the end */
491 if (field_start + field_len > (size_t)_dbus_string_get_length (&header->data))
493 field_len = _dbus_string_get_length (&header->data) - field_start;
496 /* remove the field */
497 _dbus_string_delete (&header->data, field_start, field_len);
498 header->fields[field].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT;
499 /* and update offsets */
500 for (; (size_t)field_index < n_fields_offsets-1; field_index++)
502 fields_offsets[field_index] = fields_offsets[field_index+1]-field_len;
506 /* remove padding from now-last field, if there is still any field */
507 if (n_fields_offsets > 0)
508 _dbus_string_shorten (&header->data,
509 _dbus_string_get_length(&header->data) -
510 (FIRST_GVARIANT_FIELD_OFFSET + fields_offsets[n_fields_offsets-1]));
516 /* It seems impossible for append_offsets() and correct_header_padding() to fail,
517 because space for offsets was already allocated */
518 if (!append_offsets(&header->data, fields_offsets, n_fields_offsets))
520 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
521 if (!correct_header_padding (header))
528 _dbus_header_set_field_basic_gvariant (DBusHeader *header,
533 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
534 size_t n_fields_offsets = 0;
535 dbus_bool_t result = TRUE;
536 const DBusBasicValue *vp = value;
537 size_t offset_size = 0;
538 const char *array_buffer;
540 _dbus_assert(field != DBUS_HEADER_FIELD_INVALID);
541 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
543 array_buffer = get_header_const_array (header);
545 result = result && _dbus_header_gvariant_delete_field (header, field);
547 /* now, we are sure that there is no such field (anymore) - so, simply append */
549 get_offsets (array_buffer,
550 get_header_array_size (header),
551 fields_offsets, &n_fields_offsets, &offset_size );
553 /* prepare for changing - remove array offsets and padding */
554 _dbus_string_shorten (&header->data, n_fields_offsets*offset_size + header->padding);
558 case DBUS_TYPE_STRING:
559 case DBUS_TYPE_OBJECT_PATH:
560 case DBUS_TYPE_SIGNATURE:
561 result = result && append_field_string (&header->data, field, vp->str, type,
562 fields_offsets, &n_fields_offsets);
564 case DBUS_TYPE_UINT32:
565 result = result && append_field_uint32 (&header->data, field, vp->u32,
566 fields_offsets, &n_fields_offsets);
568 case DBUS_TYPE_UINT64:
569 append_field_uint64 (&header->data, field, vp->u64,
570 fields_offsets, &n_fields_offsets);
574 _dbus_assert_not_reached("Not a basic type");
579 result = result && append_offsets(&header->data, fields_offsets, n_fields_offsets);
580 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
581 result = result && correct_header_padding (header);
587 _dbus_header_get_field_basic_gvariant (DBusHeader *header,
592 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
593 size_t n_fields_offsets = 0;
594 dbus_bool_t result = FALSE;
595 DBusBasicValue *vp = value;
596 size_t offset_size = 0;
597 const char *array_buffer;
599 _dbus_assert(field != DBUS_HEADER_FIELD_INVALID);
600 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
602 array_buffer = get_header_const_array (header);
604 get_offsets( array_buffer,
605 get_header_array_size (header),
606 fields_offsets, &n_fields_offsets, &offset_size );
608 if (0 < n_fields_offsets)
610 /* check if the field is already in the header */
612 int field_index = find_field (field, array_buffer, fields_offsets, n_fields_offsets, &field_offset);
613 if (0 <= field_index)
615 /* field found, get value */
616 const void *field_begin = array_buffer + _DBUS_ALIGN_VALUE(field_offset,8) + FIELD_ID_SIZE;
617 dbus_uint32_t byte_order = _dbus_header_get_byte_order (header);
621 case DBUS_TYPE_STRING:
622 case DBUS_TYPE_OBJECT_PATH:
623 case DBUS_TYPE_SIGNATURE:
625 vp->str = (char *)field_begin;
628 case DBUS_TYPE_UINT32:
630 vp->u32 = *(const dbus_uint32_t *)field_begin;
631 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
632 vp->u32 = DBUS_UINT32_SWAP_LE_BE (vp->u32);
635 case DBUS_TYPE_UINT64:
637 vp->u64 = *(const dbus_uint64_t *)field_begin;
638 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
639 vp->u64 = DBUS_UINT64_SWAP_LE_BE (vp->u64);
643 _dbus_assert_not_reached("Not a basic type");
654 _dbus_marshal_skip_gvariant_basic (const DBusString *str,
661 case DBUS_TYPE_STRING:
662 case DBUS_TYPE_OBJECT_PATH:
663 case DBUS_TYPE_SIGNATURE:
664 /* FIXME - this will require redesign... size should come from upper container */
665 *pos += strlen (_dbus_string_get_const_data (str) + *pos) + 1; /* length plus nul */
667 case DBUS_TYPE_BOOLEAN:
671 _dbus_marshal_skip_basic (str, type, byte_order, pos);
677 _dbus_header_load_gvariant (DBusHeader *header,
678 DBusValidity *validity)
680 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
681 size_t n_fields_offsets = 0;
682 size_t offset_size = 0;
683 const char *array_buffer = get_header_const_array (header);
685 get_offsets( array_buffer,
686 get_header_array_size (header),
687 fields_offsets, &n_fields_offsets, &offset_size );
689 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
694 _dbus_gvariant_raw_get_lengths (const DBusString *str,
695 dbus_uint32_t *fields_array_len_unsigned,
696 dbus_uint32_t *body_len_unsigned,
697 DBusValidity *validity)
699 size_t message_len = _dbus_string_get_length (str);
700 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 0);
701 const char *message_ptr = _dbus_string_get_const_data (str);
702 /* so, the offset of end of fields is written at offset str->len - body_offsets_size */
703 size_t end_of_fields = bus_gvariant_read_word_le (message_ptr + message_len - body_offsets_size,
705 *fields_array_len_unsigned = end_of_fields - FIRST_GVARIANT_FIELD_OFFSET;
707 *body_len_unsigned = message_len - _DBUS_ALIGN_VALUE (end_of_fields, 8);
712 _dbus_validate_gvariant_body_with_reason (const DBusString *expected_signature,
713 int expected_signature_start,
715 int *bytes_remaining,
716 const DBusString *value_str,
722 *bytes_remaining = 0;
727 _dbus_message_gvariant_get_signature (DBusMessage *message,
728 const DBusString **type_str_p,
732 size_t body_len = _dbus_string_get_length (&message->body);
733 size_t message_len = _dbus_string_get_length (&message->header.data) + body_len;
734 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 0);
735 const char *body_ptr = _dbus_string_get_const_data (&message->body);
736 const char *sig_end_ptr = body_ptr + body_len - body_offsets_size;
737 const char *sig_ptr = sig_end_ptr - 1;
739 while (sig_ptr >= body_ptr && (*sig_ptr) != 0)
744 if (sig_ptr < body_ptr)
747 if (type_str_p != NULL)
748 *type_str_p = &message->body;
749 *type_pos_p = sig_ptr - body_ptr + 1;
750 *type_str_len = sig_end_ptr - sig_ptr - 1;
756 _dbus_message_append_body_offset (DBusMessage *message)
758 size_t body_len = _dbus_string_get_length (&message->body);
759 size_t end_of_fields_offset = _dbus_string_get_length (&message->header.data) - message->header.padding;
760 size_t message_len = _dbus_string_get_length (&message->header.data) + body_len;
761 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 1);
763 return append_sized_value (&message->body, end_of_fields_offset, body_offsets_size);
767 _dbus_message_gvariant_add_signature (DBusMessage *message,
768 const DBusString *type_str)
770 dbus_bool_t res = _dbus_string_append_byte (&message->body, 0);
771 res = res && _dbus_string_append_byte (&message->body, '(');
772 res = res && marshal_gvariant_string (&message->body, _dbus_string_get_length (&message->body),
773 _dbus_string_get_const_data (type_str), NULL, FALSE);
774 res = res && _dbus_string_append_byte (&message->body, ')');
779 _dbus_message_gvariant_remove_body_offset (DBusMessage *message)
781 size_t offset_size = bus_gvariant_determine_word_size (_dbus_string_get_length (&message->header.data) +
782 _dbus_string_get_length (&message->body),
784 _dbus_string_shorten (&message->body, offset_size);
789 _dbus_message_finalize_gvariant (DBusMessage *message, dbus_bool_t remove_signature_from_header)
792 const DBusString *type_str;
794 dbus_bool_t fieldSignaturePresent;
795 dbus_bool_t res = TRUE;
797 _dbus_assert (!message->locked);
799 if (message->header.protocol_version != DBUS_PROTOCOL_VERSION_GVARIANT)
802 fieldSignaturePresent = _dbus_header_get_field_raw (&message->header,
803 DBUS_HEADER_FIELD_SIGNATURE,
806 if (fieldSignaturePresent)
808 /* if there is signature field, then we need to move this signature to body,
809 * and delete the field
811 const char *sig_ptr = _dbus_string_get_const_data (type_str) + type_pos;
815 _dbus_string_init_const (&str, sig_ptr);
817 /* There is a special case for structs of fixed size. They need to have size
818 * which is a multiply of required alignment.
819 * The root struct must be finalized just before adding signature and locking the message.
820 * Luckily, fixed size means that there are no offsets in the message body.
822 fixed_size = _dbus_reader_get_signature_fixed_size (type_str, &type_pos, &alignment, 1);
825 int current_length = _dbus_string_get_length (&message->body);
826 int diff = _DBUS_ALIGN_VALUE (current_length, alignment) - current_length;
828 _dbus_string_insert_bytes (&message->body, current_length, diff, 0);
833 /* If there is no signature field, then the body is empty.
834 * However, we need to add signature anyway, because body is a variant.
836 _dbus_string_init_const (&str, "");
839 /* Let's set the body also */
840 res = res && _dbus_string_set_length (&message->body, 0);
841 res = res && _dbus_string_append_byte (&message->body, 0);
844 res = res && _dbus_message_gvariant_add_signature (message, &str);
846 if (res && fieldSignaturePresent && remove_signature_from_header)
847 res = res && _dbus_header_gvariant_delete_field (&message->header, DBUS_HEADER_FIELD_SIGNATURE);
849 res = res && _dbus_message_append_body_offset (message);
854 /* returns length of the body inside the outermost variant
855 * that is, without offset and signature from the end of messages
858 _dbus_message_gvariant_get_body_length (DBusMessage *message)
860 size_t body_len = _dbus_string_get_length (&message->body);
861 size_t message_len = body_len + _dbus_string_get_length (&message->header.data);
862 size_t offset_size = bus_gvariant_determine_word_size (message_len, 0);
864 if (body_len <= offset_size)
867 body_len -= offset_size;
869 /* searching for variant's NULL byte */
870 while (body_len > 0 && _dbus_string_get_byte (&message->body, body_len) != 0)
877 get_max (int a, int b)
879 return (a>b) ? a : b;
883 update_size (int current_size, int size_of_element, int *alignment, int new_alignment)
885 *alignment = get_max (*alignment, new_alignment);
886 current_size = _DBUS_ALIGN_VALUE (current_size, *alignment);
887 return current_size + size_of_element;
891 _dbus_reader_get_signature_fixed_size (const DBusString *signature, int *pos, int *alignment,
895 int current_alignment = 1;
896 dbus_bool_t variable = FALSE;
897 int length = _dbus_string_get_length (signature);
899 char c = _dbus_string_get_byte (signature, *pos);
900 if (c == DBUS_STRUCT_BEGIN_CHAR || c == DBUS_DICT_ENTRY_BEGIN_CHAR)
907 switch (_dbus_string_get_byte (signature, *pos))
910 case DBUS_TYPE_BOOLEAN:
913 case DBUS_TYPE_INT16:
914 case DBUS_TYPE_UINT16:
915 res = update_size (res, 2, ¤t_alignment, 2);
917 case DBUS_TYPE_INT32:
918 case DBUS_TYPE_UINT32:
919 case DBUS_TYPE_UNIX_FD:
920 res = update_size (res, 4, ¤t_alignment, 4);
922 case DBUS_TYPE_INT64:
923 case DBUS_TYPE_UINT64:
924 case DBUS_TYPE_DOUBLE:
925 res = update_size (res, 8, ¤t_alignment, 8);
927 case DBUS_STRUCT_END_CHAR:
928 case DBUS_DICT_ENTRY_END_CHAR:
930 /* For fixed-size structs we need to account padding.
933 res = _DBUS_ALIGN_VALUE (res, current_alignment);
935 case DBUS_STRUCT_BEGIN_CHAR:
936 case DBUS_DICT_ENTRY_BEGIN_CHAR:
938 int alignment_recursive;
939 int res_recursive = _dbus_reader_get_signature_fixed_size (signature, pos, &alignment_recursive, 0);
940 if (res_recursive == 0)
941 variable = TRUE; /* variable size detected */
943 /* we need to update at least alignment */
944 res = update_size (res, res_recursive, ¤t_alignment, alignment_recursive);
947 case DBUS_TYPE_VARIANT:
948 current_alignment = 8;
951 case DBUS_TYPE_ARRAY:
953 int alignment_recursive;
954 int recursive_pos = *pos + 1;
955 int res_recursive = _dbus_reader_get_signature_fixed_size (signature, &recursive_pos, &alignment_recursive, 0);
957 variable = TRUE; /* variable size detected */
959 /* we need to update alignment */
960 res = update_size (res, res_recursive, ¤t_alignment, alignment_recursive);
962 /* and update position */
963 *pos = recursive_pos;
966 case DBUS_TYPE_INVALID:
970 variable = TRUE; /* variable size detected */
973 } while (depth > 0 && *pos < length);
975 /* we want to point it to the last character, to allow upper instance to skip it */
978 if (alignment != NULL)
979 *alignment = current_alignment;
981 return variable ? 0 : res;
985 _dbus_reader_get_type_fixed_size (DBusTypeReader *reader, int *alignment)
987 int pos = reader->type_pos;
988 return _dbus_reader_get_signature_fixed_size (reader->type_str, &pos, alignment, 0);
992 _dbus_type_gvariant_get_fixed_size (const DBusString *type_str, int type_pos, int *alignment)
994 return _dbus_reader_get_signature_fixed_size (type_str, &type_pos, alignment, 0);
998 get_current_type_types_only (const DBusTypeReader *reader)
1001 if (reader->finished)
1002 t = DBUS_TYPE_INVALID;
1004 t = _dbus_first_type_in_signature (reader->type_str,
1010 /* This is for structs and dict entries.
1011 * Counts variable elements inside a container.
1012 * This is equal to number of offsets embedded into the container.
1015 _dbus_reader_count_offsets (const DBusTypeReader *reader)
1019 dbus_bool_t prev_is_variable = FALSE;
1021 int ending_char = 0;
1023 _dbus_type_reader_init_types_only (&r,
1027 r.klass = reader->klass;
1029 /* In case we are in root container, we have signature without external parentheses.
1030 * We go until ending nul, starting with position 0.
1031 * Otherwise, we are in a container, so let's check what kind of container it is,
1032 * and set proper terminating character.
1036 /* Check what container we're in */
1037 switch (_dbus_string_get_byte (r.type_str, r.type_pos-1))
1039 case DBUS_STRUCT_BEGIN_CHAR:
1040 ending_char = DBUS_STRUCT_END_CHAR;
1042 case DBUS_DICT_ENTRY_BEGIN_CHAR:
1043 ending_char = DBUS_DICT_ENTRY_END_CHAR;
1046 _dbus_assert_not_reached ("function must be called inside structs or dict entries");
1050 r.finished = (_dbus_string_get_byte (r.type_str, r.type_pos) == ending_char);
1052 while ((current_type = get_current_type_types_only (&r)) != DBUS_TYPE_INVALID)
1054 int size = _dbus_reader_get_type_fixed_size (&r, NULL);
1055 if (prev_is_variable)
1057 prev_is_variable = (size == 0);
1058 _dbus_type_signature_next (_dbus_string_get_const_data(r.type_str), &r.type_pos);
1059 r.finished = (_dbus_string_get_byte (r.type_str, r.type_pos) == ending_char);
1065 _dbus_reader_get_offset_of_end_of_variable (DBusTypeReader *reader)
1067 if (reader->is_variant)
1069 /* variant has its end set to the separating 0 */
1070 return reader->value_end;
1074 const char *buffer = _dbus_string_get_const_data (reader->value_str) + reader->value_start;
1075 size_t container_size = reader->value_end - reader->value_start;
1076 size_t offset_size = bus_gvariant_determine_word_size (container_size, 0);
1077 int index_from_back = reader->offsets_from_back ?
1078 reader->variable_index :
1079 reader->n_offsets - 1 - reader->variable_index;
1081 if (0 < container_size && 0 <= index_from_back)
1083 size_t required_offset_position = container_size - (index_from_back+1)*offset_size;
1084 if (index_from_back < reader->n_offsets)
1085 return reader->value_start +
1086 bus_gvariant_read_word_le (buffer + required_offset_position,
1088 else if (reader->offsets_from_back)
1089 return reader->value_start +
1090 container_size - (reader->n_offsets * offset_size); /* this is end of internal container */
1094 return reader->value_start;
1098 _dbus_reader_count_array_elems (const DBusTypeReader *reader)
1100 /* To count the offsets we need to have offsets size and
1101 * the start and end of the offsets. The start of the offsets
1102 * is computed from the value of the last offset.
1104 const char *buffer = _dbus_string_get_const_data (reader->value_str) + reader->value_start;
1105 size_t container_size = reader->value_end - reader->value_start;
1106 size_t offset_size = bus_gvariant_determine_word_size (container_size, 0);
1107 size_t last_offset = container_size; /* this will give 0 if container is smaller than a single offset */
1108 if (container_size > offset_size)
1109 last_offset = bus_gvariant_read_word_le (buffer + container_size - offset_size, offset_size);
1110 return (container_size - last_offset) / offset_size;
1114 write_offset (DBusString *offsets,
1120 dbus_bool_t res = _dbus_string_init_preallocated (&str, offset_size);
1121 res = res && append_sized_value (&str, offset, offset_size);
1122 res = res && _dbus_string_copy_len (&str, 0, offset_size, offsets, insert_at);
1123 _dbus_string_free (&str);
1128 prepend_offset (DBusString *offsets,
1132 return write_offset (offsets, offset, offset_size, 0);
1136 append_offset (DBusString *offsets,
1140 return write_offset (offsets, offset, offset_size, _dbus_string_get_length(offsets));
1144 convert_offsets (DBusString *offsets,
1145 size_t old_offsets_size,
1146 size_t new_offsets_size)
1148 char *old_offsets = NULL;
1149 size_t n_offsets = _dbus_string_get_length (offsets) / old_offsets_size;
1150 dbus_bool_t result = _dbus_string_steal_data (offsets, &old_offsets);
1153 for (i = 0; i < n_offsets && result; i++)
1155 size_t offset = bus_gvariant_read_word_le (old_offsets + i*old_offsets_size, old_offsets_size);
1156 result = result && append_sized_value (offsets, offset, new_offsets_size);
1159 dbus_free (old_offsets);
1165 get_offsets_count (DBusString *offsets, size_t offsets_size)
1167 return _dbus_string_get_length (offsets) / offsets_size;
1171 check_offsets_for_adding (DBusTypeWriter *writer)
1173 size_t container_size = writer->value_pos - writer->value_start;
1174 size_t n_offsets = get_offsets_count (writer->offsets,
1175 writer->offsets_size);
1176 size_t offsets_size = bus_gvariant_determine_word_size (container_size, n_offsets + 1);
1177 if (offsets_size != writer->offsets_size)
1179 if (!convert_offsets (writer->offsets, writer->offsets_size, offsets_size))
1181 writer->offsets_size = offsets_size;
1187 convert_offsets_in_body (DBusTypeWriter *writer,
1188 size_t new_offsets_size)
1193 dbus_bool_t result = _dbus_string_init (&offsets);
1196 result = result && _dbus_string_move (writer->value_str, writer->value_pos, &offsets, 0);
1197 n_offsets = _dbus_string_get_length (&offsets) / writer->offsets_size;
1198 old_offsets = _dbus_string_get_data (&offsets);
1200 for (i = 0; i < n_offsets && result; i++)
1202 size_t offset = bus_gvariant_read_word_le (old_offsets + i*writer->offsets_size, writer->offsets_size);
1203 result = result && append_sized_value (writer->value_str, offset, new_offsets_size);
1206 _dbus_string_free (&offsets);
1211 check_offsets_in_body_for_adding (DBusTypeWriter *writer)
1213 size_t container_size = writer->value_pos - writer->value_start;
1214 size_t n_offsets = (_dbus_string_get_length (writer->value_str) - writer->value_pos) / writer->offsets_size;
1215 size_t offsets_size = bus_gvariant_determine_word_size (container_size, n_offsets + 1);
1216 if (offsets_size != writer->offsets_size)
1218 if (!convert_offsets_in_body (writer, offsets_size))
1220 writer->offsets_size = offsets_size;
1226 _dbus_writer_gvariant_add_offset_with_variability (DBusTypeWriter *writer,
1229 writer->is_fixed = writer->is_fixed && fixed;
1231 if (writer->body_container)
1233 check_offsets_in_body_for_adding (writer);
1235 if (*writer->u.root.last_offset != GVARIANT_LAST_OFFSET_NOT_SET)
1237 write_offset (writer->value_str,
1238 *writer->u.root.last_offset,
1239 writer->offsets_size,
1243 *writer->u.root.last_offset = writer->value_pos - writer->value_start;
1245 *writer->u.root.last_offset = GVARIANT_LAST_OFFSET_NOT_SET;
1247 else if (DBUS_TYPE_STRUCT == writer->container_type ||
1248 DBUS_TYPE_DICT_ENTRY == writer->container_type)
1250 check_offsets_for_adding (writer);
1252 if (writer->u.struct_or_dict.last_offset != GVARIANT_LAST_OFFSET_NOT_SET)
1254 prepend_offset (writer->offsets,
1255 writer->u.struct_or_dict.last_offset,
1256 writer->offsets_size);
1259 writer->u.struct_or_dict.last_offset = writer->value_pos - writer->value_start;
1261 writer->u.struct_or_dict.last_offset = GVARIANT_LAST_OFFSET_NOT_SET;
1263 else if (DBUS_TYPE_ARRAY == writer->container_type)
1265 if (writer->offsets_size > 0)
1267 check_offsets_for_adding (writer);
1269 if (!append_offset (writer->offsets,
1270 writer->value_pos - writer->value_start,
1271 writer->offsets_size))
1279 _dbus_writer_gvariant_add_offset (DBusTypeWriter *writer,
1282 return _dbus_writer_gvariant_add_offset_with_variability (writer, dbus_type_is_fixed (type));
1285 /* this function gets only known alignments - other are 1 */
1287 get_alignment (int type)
1291 case DBUS_TYPE_INT16:
1292 case DBUS_TYPE_UINT16:
1294 case DBUS_TYPE_INT32:
1295 case DBUS_TYPE_UINT32:
1296 case DBUS_TYPE_UNIX_FD:
1298 case DBUS_TYPE_INT64:
1299 case DBUS_TYPE_UINT64:
1300 case DBUS_TYPE_DOUBLE:
1301 case DBUS_TYPE_VARIANT:
1310 fix_struct_alignment_value (DBusTypeWriter *writer, int alignment)
1312 dbus_bool_t result = TRUE;
1313 int old_alignment = writer->alignment;
1314 if (old_alignment < alignment)
1316 int diff = _DBUS_ALIGN_VALUE (writer->value_start, alignment) - writer->value_start;
1317 result = _dbus_string_insert_bytes (writer->value_str, writer->value_start, diff, 0);
1318 writer->value_start += diff;
1319 writer->value_pos += diff;
1320 writer->alignment = alignment;
1326 fix_struct_alignment (DBusTypeWriter *writer, int type)
1328 return fix_struct_alignment_value (writer, get_alignment (type));
1332 update_root_last_pos (DBusTypeWriter *writer)
1334 if (writer->body_container)
1335 *writer->u.root.last_pos = writer->value_pos;
1339 _dbus_type_writer_gvariant_write_basic_no_typecode (DBusTypeWriter *writer,
1343 dbus_bool_t result = TRUE;
1345 if (writer->container_type == DBUS_TYPE_STRUCT || writer->container_type == DBUS_TYPE_DICT_ENTRY)
1346 result = fix_struct_alignment (writer, type);
1348 result = result && _dbus_marshal_write_gvariant_basic (writer->value_str,
1353 &writer->value_pos);
1355 update_root_last_pos (writer);
1357 result = result && _dbus_writer_gvariant_add_offset (writer, type);
1362 write_offsets (DBusString *dest, size_t insert_at, DBusString *offsets)
1364 return _dbus_string_copy (offsets, 0, dest, insert_at);
1368 _dbus_writer_unrecurse_gvariant_write (DBusTypeWriter *writer,
1369 DBusTypeWriter *sub)
1371 dbus_bool_t result = TRUE;
1373 if (writer->alignment < sub->alignment)
1374 writer->alignment = sub->alignment;
1376 switch (sub->container_type) {
1377 case DBUS_TYPE_STRUCT:
1378 case DBUS_TYPE_DICT_ENTRY:
1383 if (NULL != sub->offsets)
1385 write_offsets (sub->value_str, sub->value_pos, sub->offsets);
1387 _dbus_string_free (sub->offsets);
1388 dbus_free (sub->offsets);
1391 diff = _DBUS_ALIGN_VALUE (writer->value_pos, sub->alignment) - writer->value_pos;
1393 result = _dbus_string_insert_bytes (writer->value_str, writer->value_pos, diff, 0);
1394 writer->value_pos += diff;
1395 sub_len = _dbus_string_get_length (sub->value_str);
1396 result = result && _dbus_string_copy_len (sub->value_str, 0,
1400 writer->value_pos += sub_len;
1402 /* Structs may have padding if they are fixed-size structs.
1403 * This is because of requirement that struct size must be a multiply
1404 * of required alignment.
1408 diff = _DBUS_ALIGN_VALUE (sub_len, sub->alignment) - sub_len;
1409 result = result && _dbus_string_insert_bytes (writer->value_str, writer->value_pos, diff, 0);
1410 writer->value_pos += diff;
1413 _dbus_string_free (sub->value_str);
1414 dbus_free (sub->value_str);
1418 case DBUS_TYPE_VARIANT:
1422 /* write separating nul byte */
1423 result = _dbus_string_insert_byte (sub->value_str, sub->value_pos, 0);
1424 sub->value_pos += 1;
1426 /* write signature */
1427 sub_type_len = _dbus_string_get_length (sub->type_str);
1428 result = result && _dbus_string_copy_len (sub->type_str, 0,
1432 sub->value_pos += sub_type_len;
1434 /* free type string allocated in writer_recurse_variant() */
1435 _dbus_string_free (sub->type_str);
1436 dbus_free (sub->type_str);
1438 /* update parent's string pointer */
1439 writer->value_pos = sub->value_pos;
1443 case DBUS_TYPE_ARRAY:
1444 writer->value_pos = sub->value_pos;
1445 if (NULL != sub->offsets)
1447 write_offsets (sub->value_str, sub->value_pos, sub->offsets);
1449 writer->value_pos += _dbus_string_get_length (sub->offsets);
1451 _dbus_string_free (sub->offsets);
1452 dbus_free (sub->offsets);
1457 _dbus_assert_not_reached("Invalid container type");
1460 update_root_last_pos (writer);
1462 /* well, we don't know where in the type string beginning of current container is */
1463 result = result && _dbus_writer_gvariant_add_offset_with_variability (writer, sub->is_fixed);
1469 _dbus_type_reader_gvariant_init (DBusTypeReader *reader,
1470 DBusMessage *message)
1472 #ifndef DBUS_DISABLE_CHECKS
1473 if (!message->locked)
1474 _dbus_warn ("Warning: do not use dbus_message_iter_init() on an unlocked message; lock it first with dbus_message_lock()\n");
1476 reader->gvariant = TRUE;
1477 /* GVariant wraps contents into struct, but in this place type is already
1478 * stripped off the parentheses (see get_const_signature()).
1481 reader->value_end = _dbus_message_gvariant_get_body_length (message);
1482 reader->n_offsets = _dbus_reader_count_offsets (reader);