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 if (n_fields_offsets == 0)
237 for (i=0; i < n_fields_offsets-1; i++)
239 dbus_uint64_t field = get_field_after (array_buffer, fields_offsets[i]);
240 header->fields[field].value_pos = _DBUS_ALIGN_VALUE(fields_offsets[i],8) +
241 FIELD_ID_SIZE + FIRST_GVARIANT_FIELD_OFFSET;
247 correct_header_padding (DBusHeader *header)
249 int unpadded_len = _dbus_string_get_length (&header->data);
250 if (!_dbus_string_align_length (&header->data, 8))
253 header->padding = _dbus_string_get_length (&header->data) - unpadded_len;
258 _dbus_header_gvariant_create (DBusHeader *header,
261 const char *destination,
263 const char *interface,
265 const char *error_name)
267 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
268 size_t n_fields_offsets = 0;
269 dbus_bool_t res = TRUE;
271 _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
272 byte_order == DBUS_BIG_ENDIAN);
273 _dbus_assert (((interface || type != DBUS_MESSAGE_TYPE_SIGNAL) && member) ||
275 !(interface || member || error_name));
276 _dbus_assert (_dbus_string_get_length (&header->data) == 0);
278 _dbus_header_toggle_gvariant (header, TRUE);
280 res = res && _dbus_string_append_byte (&header->data, byte_order);
281 res = res && _dbus_string_append_byte (&header->data, type);
282 res = res && _dbus_string_append_byte (&header->data, 0); /* flags */
283 res = res && _dbus_string_append_byte (&header->data, DBUS_PROTOCOL_VERSION_GVARIANT);
284 res = res && append_sized_value (&header->data, 0, sizeof(dbus_uint32_t)); /* reserved */
285 res = res && append_sized_value (&header->data, 0, sizeof(dbus_uint64_t)); /* cookie */
286 /* array of fields */
287 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_PATH, path, DBUS_TYPE_OBJECT_PATH,
288 fields_offsets, &n_fields_offsets);
289 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_DESTINATION, destination, DBUS_TYPE_STRING,
290 fields_offsets, &n_fields_offsets);
291 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_INTERFACE, interface, DBUS_TYPE_STRING,
292 fields_offsets, &n_fields_offsets);
293 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_MEMBER, member, DBUS_TYPE_STRING,
294 fields_offsets, &n_fields_offsets);
295 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_ERROR_NAME, error_name, DBUS_TYPE_STRING,
296 fields_offsets, &n_fields_offsets);
297 res = res && append_offsets (&header->data, fields_offsets, n_fields_offsets);
299 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
300 res = res && correct_header_padding (header);
306 marshal_gvariant_string (DBusString *str,
310 dbus_bool_t with_nul)
312 DBusString value_str;
313 size_t value_len = strlen(value);
318 _dbus_string_init_const_len (&value_str, value, value_len);
319 if (!_dbus_string_copy_len (&value_str, 0, value_len, str, insert_at))
325 *pos_after = insert_at + value_len;
331 _dbus_marshal_write_gvariant_basic (DBusString *str,
338 const DBusBasicValue *vp;
339 _dbus_assert (dbus_type_is_basic (type));
345 case DBUS_TYPE_STRING:
346 case DBUS_TYPE_OBJECT_PATH:
347 case DBUS_TYPE_SIGNATURE:
348 return marshal_gvariant_string (str, insert_at, vp->str, pos_after, TRUE);
349 case DBUS_TYPE_BOOLEAN:
352 return _dbus_string_insert_byte (str, insert_at, vp->u32 != FALSE);
354 return _dbus_marshal_write_basic (str, insert_at, type, value, byte_order, pos_after);
359 _dbus_marshal_read_gvariant_basic (const DBusString *str,
366 const char *str_data;
368 _dbus_assert (dbus_type_is_basic (type));
370 str_data = _dbus_string_get_const_data (str);
373 case DBUS_TYPE_STRING:
374 case DBUS_TYPE_OBJECT_PATH:
375 case DBUS_TYPE_SIGNATURE:
377 volatile char **vp = value;
378 *vp = (char*) str_data + pos;
379 pos += strlen (str_data+pos)+1;
382 case DBUS_TYPE_BOOLEAN:
384 volatile dbus_bool_t *vp = value;
385 *vp = (dbus_bool_t) _dbus_string_get_byte (str, pos);
390 _dbus_marshal_read_basic (str, pos, type, value, byte_order, new_pos);
399 get_offsets (const char *buffer, size_t container_size,
400 size_t *fields_offsets, size_t *n_fields_offsets,
403 *offset_size = bus_gvariant_determine_word_size (container_size, 0);
405 if (0 < container_size && 0 < *offset_size)
407 size_t last_offset_position = container_size - (*offset_size);
408 size_t last_offset = bus_gvariant_read_word_le (buffer + last_offset_position,
412 *n_fields_offsets = (container_size - last_offset) / (*offset_size);
414 if (*n_fields_offsets == 0 || *n_fields_offsets >= DBUS_HEADER_FIELD_LAST)
417 fields_offsets[(*n_fields_offsets)-1] = last_offset;
418 for (i = 0; i < (*n_fields_offsets)-1; i++)
420 fields_offsets[i] = bus_gvariant_read_word_le (buffer + last_offset + i*(*offset_size),
427 find_field (int field, const char *array_buffer, size_t *fields_offsets, size_t n_fields_offsets,
428 size_t *field_offset)
430 /* last_offset points to the offsets array, beyond the last element of the array container */
431 size_t last_offset = fields_offsets[n_fields_offsets-1];
433 size_t next_offset = 0;
435 while ( next_offset < last_offset &&
436 get_field_after (array_buffer, next_offset) != (dbus_uint64_t) field)
438 next_offset = fields_offsets[i];
441 if (next_offset < last_offset)
443 *field_offset = next_offset;
450 _dbus_header_gvariant_delete_field (DBusHeader *header,
453 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
454 size_t n_fields_offsets = 0;
455 size_t offset_size = 0;
456 const char *array_buffer;
458 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
460 array_buffer = get_header_const_array (header);
462 get_offsets (array_buffer,
463 get_header_array_size (header),
464 fields_offsets, &n_fields_offsets, &offset_size );
466 if (0 < n_fields_offsets)
468 /* check if the field is already in the header */
470 int field_index = find_field (field, array_buffer, fields_offsets, n_fields_offsets, &field_offset);
472 /* prepare for changing - remove array offsets and offsets */
473 _dbus_string_shorten (&header->data, n_fields_offsets*offset_size + header->padding);
475 if (field_index >= 0)
478 size_t field_len = 0;
479 size_t field_start = 0;
480 /* let's remove aligned block of the field, along with padding */
481 if (field_index == 0)
483 field_len = _DBUS_ALIGN_VALUE (fields_offsets[0],8);
487 field_len = _DBUS_ALIGN_VALUE (fields_offsets[field_index],8) -
488 _DBUS_ALIGN_VALUE (fields_offsets[field_index-1],8);
491 field_start = FIRST_GVARIANT_FIELD_OFFSET + _DBUS_ALIGN_VALUE (field_offset, 8);
493 /* if this is the last field, then there is no padding at the end */
494 if (field_start + field_len > (size_t)_dbus_string_get_length (&header->data))
496 field_len = _dbus_string_get_length (&header->data) - field_start;
499 /* remove the field */
500 _dbus_string_delete (&header->data, field_start, field_len);
501 header->fields[field].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT;
502 /* and update offsets */
503 for (; (size_t)field_index < n_fields_offsets-1; field_index++)
505 fields_offsets[field_index] = fields_offsets[field_index+1]-field_len;
509 /* remove padding from now-last field, if there is still any field */
510 if (n_fields_offsets > 0)
511 _dbus_string_shorten (&header->data,
512 _dbus_string_get_length(&header->data) -
513 (FIRST_GVARIANT_FIELD_OFFSET + fields_offsets[n_fields_offsets-1]));
519 /* It seems impossible for append_offsets() and correct_header_padding() to fail,
520 because space for offsets was already allocated */
521 if (!append_offsets(&header->data, fields_offsets, n_fields_offsets))
523 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
524 if (!correct_header_padding (header))
531 _dbus_header_set_field_basic_gvariant (DBusHeader *header,
536 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
537 size_t n_fields_offsets = 0;
538 dbus_bool_t result = TRUE;
539 const DBusBasicValue *vp = value;
540 size_t offset_size = 0;
541 const char *array_buffer;
543 _dbus_assert(field != DBUS_HEADER_FIELD_INVALID);
544 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
546 array_buffer = get_header_const_array (header);
548 result = result && _dbus_header_gvariant_delete_field (header, field);
550 /* now, we are sure that there is no such field (anymore) - so, simply append */
552 get_offsets (array_buffer,
553 get_header_array_size (header),
554 fields_offsets, &n_fields_offsets, &offset_size );
556 /* prepare for changing - remove array offsets and padding */
557 _dbus_string_shorten (&header->data, n_fields_offsets*offset_size + header->padding);
561 case DBUS_TYPE_STRING:
562 case DBUS_TYPE_OBJECT_PATH:
563 case DBUS_TYPE_SIGNATURE:
564 result = result && append_field_string (&header->data, field, vp->str, type,
565 fields_offsets, &n_fields_offsets);
567 case DBUS_TYPE_UINT32:
568 result = result && append_field_uint32 (&header->data, field, vp->u32,
569 fields_offsets, &n_fields_offsets);
571 case DBUS_TYPE_UINT64:
572 append_field_uint64 (&header->data, field, vp->u64,
573 fields_offsets, &n_fields_offsets);
577 _dbus_assert_not_reached("Not a basic type");
582 result = result && append_offsets(&header->data, fields_offsets, n_fields_offsets);
583 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
584 result = result && correct_header_padding (header);
590 _dbus_header_get_field_basic_gvariant (DBusHeader *header,
595 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
596 size_t n_fields_offsets = 0;
597 dbus_bool_t result = FALSE;
598 DBusBasicValue *vp = value;
599 size_t offset_size = 0;
600 const char *array_buffer;
602 _dbus_assert(field != DBUS_HEADER_FIELD_INVALID);
603 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
605 array_buffer = get_header_const_array (header);
607 get_offsets( array_buffer,
608 get_header_array_size (header),
609 fields_offsets, &n_fields_offsets, &offset_size );
611 if (0 < n_fields_offsets)
613 /* check if the field is already in the header */
615 int field_index = find_field (field, array_buffer, fields_offsets, n_fields_offsets, &field_offset);
616 if (0 <= field_index)
618 /* field found, get value */
619 const void *field_begin = array_buffer + _DBUS_ALIGN_VALUE(field_offset,8) + FIELD_ID_SIZE;
620 dbus_uint32_t byte_order = _dbus_header_get_byte_order (header);
624 case DBUS_TYPE_STRING:
625 case DBUS_TYPE_OBJECT_PATH:
626 case DBUS_TYPE_SIGNATURE:
628 vp->str = (char *)field_begin;
631 case DBUS_TYPE_UINT32:
633 vp->u32 = *(const dbus_uint32_t *)field_begin;
634 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
635 vp->u32 = DBUS_UINT32_SWAP_LE_BE (vp->u32);
638 case DBUS_TYPE_UINT64:
640 vp->u64 = *(const dbus_uint64_t *)field_begin;
641 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
642 vp->u64 = DBUS_UINT64_SWAP_LE_BE (vp->u64);
646 _dbus_assert_not_reached("Not a basic type");
657 _dbus_marshal_skip_gvariant_basic (const DBusString *str,
664 case DBUS_TYPE_STRING:
665 case DBUS_TYPE_OBJECT_PATH:
666 case DBUS_TYPE_SIGNATURE:
667 /* FIXME - this will require redesign... size should come from upper container */
668 *pos += strlen (_dbus_string_get_const_data (str) + *pos) + 1; /* length plus nul */
670 case DBUS_TYPE_BOOLEAN:
674 _dbus_marshal_skip_basic (str, type, byte_order, pos);
680 _dbus_header_load_gvariant (DBusHeader *header,
681 DBusValidity *validity)
683 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
684 size_t n_fields_offsets = 0;
685 size_t offset_size = 0;
686 const char *array_buffer = get_header_const_array (header);
688 get_offsets( array_buffer,
689 get_header_array_size (header),
690 fields_offsets, &n_fields_offsets, &offset_size );
692 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
697 _dbus_gvariant_raw_get_lengths (const DBusString *str,
698 dbus_uint32_t *fields_array_len_unsigned,
699 dbus_uint32_t *body_len_unsigned,
700 DBusValidity *validity)
702 size_t message_len = _dbus_string_get_length (str);
703 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 0);
704 const char *message_ptr = _dbus_string_get_const_data (str);
705 /* so, the offset of end of fields is written at offset str->len - body_offsets_size */
706 size_t end_of_fields = bus_gvariant_read_word_le (message_ptr + message_len - body_offsets_size,
708 *fields_array_len_unsigned = end_of_fields - FIRST_GVARIANT_FIELD_OFFSET;
710 *body_len_unsigned = message_len - _DBUS_ALIGN_VALUE (end_of_fields, 8);
715 _dbus_validate_gvariant_body_with_reason (const DBusString *expected_signature,
716 int expected_signature_start,
718 int *bytes_remaining,
719 const DBusString *value_str,
725 *bytes_remaining = 0;
730 _dbus_message_gvariant_get_signature (DBusMessage *message,
731 const DBusString **type_str_p,
735 size_t body_len = _dbus_string_get_length (&message->body);
736 size_t message_len = _dbus_string_get_length (&message->header.data) + body_len;
737 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 0);
738 const char *body_ptr = _dbus_string_get_const_data (&message->body);
739 const char *sig_end_ptr = body_ptr + body_len - body_offsets_size;
740 const char *sig_ptr = sig_end_ptr - 1;
742 while (sig_ptr >= body_ptr && (*sig_ptr) != 0)
747 if (sig_ptr < body_ptr)
750 if (type_str_p != NULL)
751 *type_str_p = &message->body;
752 *type_pos_p = sig_ptr - body_ptr + 1;
753 *type_str_len = sig_end_ptr - sig_ptr - 1;
759 _dbus_message_append_body_offset (DBusMessage *message)
761 size_t body_len = _dbus_string_get_length (&message->body);
762 size_t end_of_fields_offset = _dbus_string_get_length (&message->header.data) - message->header.padding;
763 size_t message_len = _dbus_string_get_length (&message->header.data) + body_len;
764 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 1);
766 return append_sized_value (&message->body, end_of_fields_offset, body_offsets_size);
770 _dbus_message_gvariant_add_signature (DBusMessage *message,
771 const DBusString *type_str)
773 dbus_bool_t res = _dbus_string_append_byte (&message->body, 0);
774 res = res && _dbus_string_append_byte (&message->body, '(');
775 res = res && marshal_gvariant_string (&message->body, _dbus_string_get_length (&message->body),
776 _dbus_string_get_const_data (type_str), NULL, FALSE);
777 res = res && _dbus_string_append_byte (&message->body, ')');
782 _dbus_message_gvariant_remove_body_offset (DBusMessage *message)
784 size_t offset_size = bus_gvariant_determine_word_size (_dbus_string_get_length (&message->header.data) +
785 _dbus_string_get_length (&message->body),
787 _dbus_string_shorten (&message->body, offset_size);
792 _dbus_message_finalize_gvariant (DBusMessage *message, dbus_bool_t remove_signature_from_header)
795 const DBusString *type_str;
797 dbus_bool_t fieldSignaturePresent;
798 dbus_bool_t res = TRUE;
800 _dbus_assert (!message->locked);
802 if (message->header.protocol_version != DBUS_PROTOCOL_VERSION_GVARIANT)
805 fieldSignaturePresent = _dbus_header_get_field_raw (&message->header,
806 DBUS_HEADER_FIELD_SIGNATURE,
809 if (fieldSignaturePresent)
811 /* if there is signature field, then we need to move this signature to body,
812 * and delete the field
814 const char *sig_ptr = _dbus_string_get_const_data (type_str) + type_pos;
818 _dbus_string_init_const (&str, sig_ptr);
820 /* There is a special case for structs of fixed size. They need to have size
821 * which is a multiply of required alignment.
822 * The root struct must be finalized just before adding signature and locking the message.
823 * Luckily, fixed size means that there are no offsets in the message body.
825 fixed_size = _dbus_reader_get_signature_fixed_size (type_str, &type_pos, &alignment, 1);
828 int current_length = _dbus_string_get_length (&message->body);
829 int diff = _DBUS_ALIGN_VALUE (current_length, alignment) - current_length;
831 _dbus_string_insert_bytes (&message->body, current_length, diff, 0);
836 /* If there is no signature field, then the body is empty.
837 * However, we need to add signature anyway, because body is a variant.
839 _dbus_string_init_const (&str, "");
842 /* Let's set the body also */
843 res = res && _dbus_string_set_length (&message->body, 0);
844 res = res && _dbus_string_append_byte (&message->body, 0);
847 res = res && _dbus_message_gvariant_add_signature (message, &str);
849 if (res && fieldSignaturePresent && remove_signature_from_header)
850 res = res && _dbus_header_gvariant_delete_field (&message->header, DBUS_HEADER_FIELD_SIGNATURE);
852 res = res && _dbus_message_append_body_offset (message);
857 /* returns length of the body inside the outermost variant
858 * that is, without offset and signature from the end of messages
861 _dbus_message_gvariant_get_body_length (DBusMessage *message)
867 body_len = _dbus_string_get_length (&message->body);
869 /* Unlocked messages don't have any body offset or signature appended yet. */
870 if (!message->locked)
873 /* We need to find where the root container actually ends.
874 * We know there are a zero-byte, a signature and a body offset appended.
875 * We check offset's size, skip it, and go back through the signature until
876 * the zero byte, which is one byte past the end of the root container.
878 message_len = body_len + _dbus_string_get_length (&message->header.data);
879 offset_size = bus_gvariant_determine_word_size (message_len, 0);
881 if (body_len <= offset_size)
884 body_len -= offset_size;
886 /* searching for variant's NULL byte */
887 while (body_len > 0 && _dbus_string_get_byte (&message->body, body_len) != 0)
894 get_max (int a, int b)
896 return (a>b) ? a : b;
900 update_size (int current_size, int size_of_element, int *alignment, int new_alignment)
902 *alignment = get_max (*alignment, new_alignment);
903 current_size = _DBUS_ALIGN_VALUE (current_size, *alignment);
904 return current_size + size_of_element;
908 _dbus_reader_get_signature_fixed_size (const DBusString *signature, int *pos, int *alignment,
912 int current_alignment = 1;
913 dbus_bool_t variable = FALSE;
914 int length = _dbus_string_get_length (signature);
916 char c = _dbus_string_get_byte (signature, *pos);
917 if (c == DBUS_STRUCT_BEGIN_CHAR || c == DBUS_DICT_ENTRY_BEGIN_CHAR)
924 switch (_dbus_string_get_byte (signature, *pos))
927 case DBUS_TYPE_BOOLEAN:
930 case DBUS_TYPE_INT16:
931 case DBUS_TYPE_UINT16:
932 res = update_size (res, 2, ¤t_alignment, 2);
934 case DBUS_TYPE_INT32:
935 case DBUS_TYPE_UINT32:
936 case DBUS_TYPE_UNIX_FD:
937 res = update_size (res, 4, ¤t_alignment, 4);
939 case DBUS_TYPE_INT64:
940 case DBUS_TYPE_UINT64:
941 case DBUS_TYPE_DOUBLE:
942 res = update_size (res, 8, ¤t_alignment, 8);
944 case DBUS_STRUCT_END_CHAR:
945 case DBUS_DICT_ENTRY_END_CHAR:
947 /* For fixed-size structs we need to account padding.
950 res = _DBUS_ALIGN_VALUE (res, current_alignment);
952 case DBUS_STRUCT_BEGIN_CHAR:
953 case DBUS_DICT_ENTRY_BEGIN_CHAR:
955 int alignment_recursive;
956 int res_recursive = _dbus_reader_get_signature_fixed_size (signature, pos, &alignment_recursive, 0);
957 if (res_recursive == 0)
958 variable = TRUE; /* variable size detected */
960 /* we need to update at least alignment */
961 res = update_size (res, res_recursive, ¤t_alignment, alignment_recursive);
964 case DBUS_TYPE_VARIANT:
965 current_alignment = 8;
968 case DBUS_TYPE_ARRAY:
970 int alignment_recursive;
971 int recursive_pos = *pos + 1;
972 int res_recursive = _dbus_reader_get_signature_fixed_size (signature, &recursive_pos, &alignment_recursive, 0);
974 variable = TRUE; /* variable size detected */
976 /* we need to update alignment */
977 res = update_size (res, res_recursive, ¤t_alignment, alignment_recursive);
979 /* and update position */
980 *pos = recursive_pos;
983 case DBUS_TYPE_INVALID:
987 variable = TRUE; /* variable size detected */
990 } while (depth > 0 && *pos < length);
992 /* we want to point it to the last character, to allow upper instance to skip it */
995 if (alignment != NULL)
996 *alignment = current_alignment;
998 return variable ? 0 : res;
1002 _dbus_reader_get_type_fixed_size (DBusTypeReader *reader, int *alignment)
1004 int pos = reader->type_pos;
1005 return _dbus_reader_get_signature_fixed_size (reader->type_str, &pos, alignment, 0);
1009 _dbus_type_gvariant_get_fixed_size (const DBusString *type_str, int type_pos, int *alignment)
1011 return _dbus_reader_get_signature_fixed_size (type_str, &type_pos, alignment, 0);
1015 get_current_type_types_only (const DBusTypeReader *reader)
1018 if (reader->finished)
1019 t = DBUS_TYPE_INVALID;
1021 t = _dbus_first_type_in_signature (reader->type_str,
1027 /* This is for structs and dict entries.
1028 * Counts variable elements inside a container.
1029 * This is equal to number of offsets embedded into the container.
1032 _dbus_reader_count_offsets (const DBusTypeReader *reader)
1036 dbus_bool_t prev_is_variable = FALSE;
1038 int ending_char = 0;
1040 _dbus_type_reader_init_types_only (&r,
1044 r.klass = reader->klass;
1046 /* In case we are in root container, we have signature without external parentheses.
1047 * We go until ending nul, starting with position 0.
1048 * Otherwise, we are in a container, so let's check what kind of container it is,
1049 * and set proper terminating character.
1053 /* Check what container we're in */
1054 switch (_dbus_string_get_byte (r.type_str, r.type_pos-1))
1056 case DBUS_STRUCT_BEGIN_CHAR:
1057 ending_char = DBUS_STRUCT_END_CHAR;
1059 case DBUS_DICT_ENTRY_BEGIN_CHAR:
1060 ending_char = DBUS_DICT_ENTRY_END_CHAR;
1063 _dbus_assert_not_reached ("function must be called inside structs or dict entries");
1067 r.finished = (_dbus_string_get_byte (r.type_str, r.type_pos) == ending_char);
1069 while ((current_type = get_current_type_types_only (&r)) != DBUS_TYPE_INVALID)
1071 int size = _dbus_reader_get_type_fixed_size (&r, NULL);
1072 if (prev_is_variable)
1074 prev_is_variable = (size == 0);
1075 _dbus_type_signature_next (_dbus_string_get_const_data(r.type_str), &r.type_pos);
1076 r.finished = (_dbus_string_get_byte (r.type_str, r.type_pos) == ending_char);
1082 _dbus_reader_get_offset_of_end_of_variable (DBusTypeReader *reader)
1084 if (reader->is_variant)
1086 /* variant has its end set to the separating 0 */
1087 return reader->value_end;
1091 const char *buffer = _dbus_string_get_const_data (reader->value_str) + reader->value_start;
1092 size_t container_size = reader->value_end - reader->value_start;
1093 size_t offset_size = bus_gvariant_determine_word_size (container_size, 0);
1094 int index_from_back = reader->offsets_from_back ?
1095 reader->variable_index :
1096 reader->n_offsets - 1 - reader->variable_index;
1098 if (0 < container_size && 0 <= index_from_back)
1100 size_t required_offset_position = container_size - (index_from_back+1)*offset_size;
1101 if (index_from_back < reader->n_offsets)
1102 return reader->value_start +
1103 bus_gvariant_read_word_le (buffer + required_offset_position,
1105 else if (reader->offsets_from_back)
1106 return reader->value_start +
1107 container_size - (reader->n_offsets * offset_size); /* this is end of internal container */
1111 return reader->value_start;
1115 _dbus_reader_count_array_elems (const DBusTypeReader *reader)
1117 /* To count the offsets we need to have offsets size and
1118 * the start and end of the offsets. The start of the offsets
1119 * is computed from the value of the last offset.
1121 const char *buffer = _dbus_string_get_const_data (reader->value_str) + reader->value_start;
1122 size_t container_size = reader->value_end - reader->value_start;
1123 size_t offset_size = bus_gvariant_determine_word_size (container_size, 0);
1124 size_t last_offset = container_size; /* this will give 0 if container is smaller than a single offset */
1125 if (container_size > offset_size)
1126 last_offset = bus_gvariant_read_word_le (buffer + container_size - offset_size, offset_size);
1127 return (container_size - last_offset) / offset_size;
1131 write_offset (DBusString *offsets,
1137 dbus_bool_t res = _dbus_string_init_preallocated (&str, offset_size);
1138 res = res && append_sized_value (&str, offset, offset_size);
1139 res = res && _dbus_string_copy_len (&str, 0, offset_size, offsets, insert_at);
1140 _dbus_string_free (&str);
1145 prepend_offset (DBusString *offsets,
1149 return write_offset (offsets, offset, offset_size, 0);
1153 append_offset (DBusString *offsets,
1157 return write_offset (offsets, offset, offset_size, _dbus_string_get_length(offsets));
1161 convert_offsets (DBusString *offsets,
1162 size_t old_offsets_size,
1163 size_t new_offsets_size)
1165 char *old_offsets = NULL;
1166 size_t n_offsets = _dbus_string_get_length (offsets) / old_offsets_size;
1167 dbus_bool_t result = _dbus_string_steal_data (offsets, &old_offsets);
1170 for (i = 0; i < n_offsets && result; i++)
1172 size_t offset = bus_gvariant_read_word_le (old_offsets + i*old_offsets_size, old_offsets_size);
1173 result = result && append_sized_value (offsets, offset, new_offsets_size);
1176 dbus_free (old_offsets);
1182 get_offsets_count (DBusString *offsets, size_t offsets_size)
1184 return _dbus_string_get_length (offsets) / offsets_size;
1188 check_offsets_for_adding (DBusTypeWriter *writer)
1190 size_t container_size = writer->value_pos - writer->value_start;
1191 size_t n_offsets = get_offsets_count (writer->offsets,
1192 writer->offsets_size);
1193 size_t offsets_size = bus_gvariant_determine_word_size (container_size, n_offsets + 1);
1194 if (offsets_size != writer->offsets_size)
1196 if (!convert_offsets (writer->offsets, writer->offsets_size, offsets_size))
1198 writer->offsets_size = offsets_size;
1204 convert_offsets_in_body (DBusTypeWriter *writer,
1205 size_t new_offsets_size)
1210 dbus_bool_t result = _dbus_string_init (&offsets);
1213 result = result && _dbus_string_move (writer->value_str, writer->value_pos, &offsets, 0);
1214 n_offsets = _dbus_string_get_length (&offsets) / writer->offsets_size;
1215 old_offsets = _dbus_string_get_data (&offsets);
1217 for (i = 0; i < n_offsets && result; i++)
1219 size_t offset = bus_gvariant_read_word_le (old_offsets + i*writer->offsets_size, writer->offsets_size);
1220 result = result && append_sized_value (writer->value_str, offset, new_offsets_size);
1223 _dbus_string_free (&offsets);
1228 check_offsets_in_body_for_adding (DBusTypeWriter *writer)
1230 size_t container_size = writer->value_pos - writer->value_start;
1231 size_t n_offsets = (_dbus_string_get_length (writer->value_str) - writer->value_pos) / writer->offsets_size;
1232 size_t offsets_size = bus_gvariant_determine_word_size (container_size, n_offsets + 1);
1233 if (offsets_size != writer->offsets_size)
1235 if (!convert_offsets_in_body (writer, offsets_size))
1237 writer->offsets_size = offsets_size;
1243 _dbus_writer_gvariant_add_offset_with_variability (DBusTypeWriter *writer,
1246 writer->is_fixed = writer->is_fixed && fixed;
1248 if (writer->body_container)
1250 check_offsets_in_body_for_adding (writer);
1252 if (*writer->u.root.last_offset != GVARIANT_LAST_OFFSET_NOT_SET)
1254 write_offset (writer->value_str,
1255 *writer->u.root.last_offset,
1256 writer->offsets_size,
1260 *writer->u.root.last_offset = writer->value_pos - writer->value_start;
1262 *writer->u.root.last_offset = GVARIANT_LAST_OFFSET_NOT_SET;
1264 else if (DBUS_TYPE_STRUCT == writer->container_type ||
1265 DBUS_TYPE_DICT_ENTRY == writer->container_type)
1267 check_offsets_for_adding (writer);
1269 if (writer->u.struct_or_dict.last_offset != GVARIANT_LAST_OFFSET_NOT_SET)
1271 prepend_offset (writer->offsets,
1272 writer->u.struct_or_dict.last_offset,
1273 writer->offsets_size);
1276 writer->u.struct_or_dict.last_offset = writer->value_pos - writer->value_start;
1278 writer->u.struct_or_dict.last_offset = GVARIANT_LAST_OFFSET_NOT_SET;
1280 else if (DBUS_TYPE_ARRAY == writer->container_type)
1282 if (writer->offsets_size > 0)
1284 check_offsets_for_adding (writer);
1286 if (!append_offset (writer->offsets,
1287 writer->value_pos - writer->value_start,
1288 writer->offsets_size))
1296 _dbus_writer_gvariant_add_offset (DBusTypeWriter *writer,
1299 return _dbus_writer_gvariant_add_offset_with_variability (writer, dbus_type_is_fixed (type));
1302 /* this function gets only known alignments - other are 1 */
1304 get_alignment (int type)
1308 case DBUS_TYPE_INT16:
1309 case DBUS_TYPE_UINT16:
1311 case DBUS_TYPE_INT32:
1312 case DBUS_TYPE_UINT32:
1313 case DBUS_TYPE_UNIX_FD:
1315 case DBUS_TYPE_INT64:
1316 case DBUS_TYPE_UINT64:
1317 case DBUS_TYPE_DOUBLE:
1318 case DBUS_TYPE_VARIANT:
1327 fix_struct_alignment_value (DBusTypeWriter *writer, int alignment)
1329 dbus_bool_t result = TRUE;
1330 int old_alignment = writer->alignment;
1331 if (old_alignment < alignment)
1333 int diff = _DBUS_ALIGN_VALUE (writer->value_start, alignment) - writer->value_start;
1334 result = _dbus_string_insert_bytes (writer->value_str, writer->value_start, diff, 0);
1335 writer->value_start += diff;
1336 writer->value_pos += diff;
1337 writer->alignment = alignment;
1343 fix_struct_alignment (DBusTypeWriter *writer, int type)
1345 return fix_struct_alignment_value (writer, get_alignment (type));
1349 update_root_last_pos (DBusTypeWriter *writer)
1351 if (writer->body_container)
1352 *writer->u.root.last_pos = writer->value_pos;
1356 _dbus_type_writer_gvariant_write_basic_no_typecode (DBusTypeWriter *writer,
1360 dbus_bool_t result = TRUE;
1362 if (writer->container_type == DBUS_TYPE_STRUCT || writer->container_type == DBUS_TYPE_DICT_ENTRY)
1363 result = fix_struct_alignment (writer, type);
1365 result = result && _dbus_marshal_write_gvariant_basic (writer->value_str,
1370 &writer->value_pos);
1372 update_root_last_pos (writer);
1374 result = result && _dbus_writer_gvariant_add_offset (writer, type);
1379 write_offsets (DBusString *dest, size_t insert_at, DBusString *offsets)
1381 return _dbus_string_copy (offsets, 0, dest, insert_at);
1385 _dbus_writer_unrecurse_gvariant_write (DBusTypeWriter *writer,
1386 DBusTypeWriter *sub)
1388 dbus_bool_t result = TRUE;
1390 if (writer->alignment < sub->alignment)
1391 writer->alignment = sub->alignment;
1393 switch (sub->container_type) {
1394 case DBUS_TYPE_STRUCT:
1395 case DBUS_TYPE_DICT_ENTRY:
1400 if (NULL != sub->offsets)
1402 write_offsets (sub->value_str, sub->value_pos, sub->offsets);
1404 _dbus_string_free (sub->offsets);
1405 dbus_free (sub->offsets);
1408 diff = _DBUS_ALIGN_VALUE (writer->value_pos, sub->alignment) - writer->value_pos;
1410 result = _dbus_string_insert_bytes (writer->value_str, writer->value_pos, diff, 0);
1411 writer->value_pos += diff;
1412 sub_len = _dbus_string_get_length (sub->value_str);
1413 result = result && _dbus_string_copy_len (sub->value_str, 0,
1417 writer->value_pos += sub_len;
1419 /* Structs may have padding if they are fixed-size structs.
1420 * This is because of requirement that struct size must be a multiply
1421 * of required alignment.
1425 diff = _DBUS_ALIGN_VALUE (sub_len, sub->alignment) - sub_len;
1426 result = result && _dbus_string_insert_bytes (writer->value_str, writer->value_pos, diff, 0);
1427 writer->value_pos += diff;
1430 _dbus_string_free (sub->value_str);
1431 dbus_free (sub->value_str);
1435 case DBUS_TYPE_VARIANT:
1439 /* write separating nul byte */
1440 result = _dbus_string_insert_byte (sub->value_str, sub->value_pos, 0);
1441 sub->value_pos += 1;
1443 /* write signature */
1444 sub_type_len = _dbus_string_get_length (sub->type_str);
1445 result = result && _dbus_string_copy_len (sub->type_str, 0,
1449 sub->value_pos += sub_type_len;
1451 /* free type string allocated in writer_recurse_variant() */
1452 _dbus_string_free (sub->type_str);
1453 dbus_free (sub->type_str);
1455 /* update parent's string pointer */
1456 writer->value_pos = sub->value_pos;
1460 case DBUS_TYPE_ARRAY:
1461 writer->value_pos = sub->value_pos;
1462 if (NULL != sub->offsets)
1464 write_offsets (sub->value_str, sub->value_pos, sub->offsets);
1466 writer->value_pos += _dbus_string_get_length (sub->offsets);
1468 _dbus_string_free (sub->offsets);
1469 dbus_free (sub->offsets);
1474 _dbus_assert_not_reached("Invalid container type");
1477 update_root_last_pos (writer);
1479 /* well, we don't know where in the type string beginning of current container is */
1480 result = result && _dbus_writer_gvariant_add_offset_with_variability (writer, sub->is_fixed);
1486 _dbus_type_reader_gvariant_init (DBusTypeReader *reader,
1487 DBusMessage *message)
1489 reader->gvariant = TRUE;
1490 /* GVariant wraps contents into struct, but in this place type is already
1491 * stripped off the parentheses (see get_const_signature()).
1494 reader->value_end = _dbus_message_gvariant_get_body_length (message);
1495 reader->n_offsets = _dbus_reader_count_offsets (reader);
1499 _dbus_message_gvariant_convert_to_unlocked (DBusMessage *message)
1501 const char *signature;
1502 DBusTypeReader reader;
1503 DBusString signature_str;
1504 int count_variable_sized = 0;
1506 _dbus_assert (_dbus_message_is_gvariant (message));
1507 _dbus_assert (message->locked);
1509 /* Differences between locked and unlocked GVariant messages:
1511 * - body contains footer (zero byte, signature in parentheses, body offset);
1512 * - there is no signature field in header;
1513 * - 'signature' member is set if the signature was needed;
1514 * - 'gvariant_body_last_'* members are unused.
1516 * - body ends with root container offsets, if any;
1517 * - header contains signature field;
1518 * - 'signature' member is NULL;
1519 * - 'gvariant_body_last_'* members are set to proper values.
1521 * So, to convert to unlocked we need to:
1522 * - check if the last type is a variable-size type; if so, we need
1523 * to remember its end position for adding it as an offset to the body
1524 * on first append (set 'gvariant_body_last_offset');
1525 * - set 'gvariant_body_last_pos' to correct writing position (just before the offsets);
1526 * - extract signature from the body and move it to the header field;
1527 * - ensure the 'signature' member is NULL;
1528 * - shrink body length to end just after the offsets.
1531 /* Get the signature C-string, we'll need it to move it from the body
1532 * to the header field, and for iterating over types.
1533 * We need to clear message->signature later, as the function sets it.
1535 signature = dbus_message_get_signature (message);
1538 _dbus_string_free (message->signature);
1539 message->signature = NULL;
1543 /* Initialize 'reader' for iterating over types from the signature.
1545 _dbus_string_init_const (&signature_str, signature);
1546 reader.type_str = &signature_str;
1547 reader.type_pos = 0;
1549 _dbus_type_reader_gvariant_init (&reader, message);
1551 /* If the last value is variable-sized, then the last offset is equal to the writing position
1552 * The writing position is just before offsets. */
1553 message->gvariant_body_last_pos = reader.value_end -
1554 (reader.n_offsets * bus_gvariant_determine_word_size (reader.value_end, 0));
1556 /* Count variable-sized types on the root container level. */
1557 while (_dbus_string_get_byte (reader.type_str, reader.type_pos) != 0)
1559 if (_dbus_reader_get_type_fixed_size (&reader, NULL) == 0)
1560 count_variable_sized++;
1561 _dbus_type_signature_next (_dbus_string_get_const_data(reader.type_str), &reader.type_pos);
1564 /* Check if all the offsets are present in the body.
1565 * If not, then the last type is of variable size, and will be a subject to add to the body
1566 * on the first append to this message.
1568 if (count_variable_sized == reader.n_offsets)
1569 message->gvariant_body_last_offset = GVARIANT_LAST_OFFSET_NOT_SET;
1571 message->gvariant_body_last_offset = message->gvariant_body_last_pos;
1573 /* Convert to unlocked. We'll modify our message now. */
1574 message->locked = FALSE;
1576 /* Copy signature to the header */
1577 if (!_dbus_header_set_field_basic (&message->header,
1578 DBUS_HEADER_FIELD_SIGNATURE,
1579 DBUS_TYPE_SIGNATURE,
1582 _dbus_string_free (message->signature);
1583 message->signature = NULL;
1587 /* Unlocked DBusMessage needs to have NULL 'signature' member, since it has the above header field
1588 * for signatures. Our 'message' has the member set, because dbus_message_get_signature() added it.
1589 * Let's get rid of it.
1591 _dbus_assert (message->signature);
1592 _dbus_string_free (message->signature);
1593 message->signature = NULL;
1595 /* Unlocked messages have no signature, variant's zero byte, and final offset in the body.
1596 * Cut them off. Luckily, _dbus_type_reader_gvariant_init() has already computed the correct
1599 _dbus_string_set_length (&message->body, reader.value_end);