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-marshal-recursive.h"
30 #include "dbus-message-private.h"
31 #include "dbus-signature.h"
32 #include "dbus-connection-internal.h"
35 /** Static #DBusString containing the signature of a message header */
36 _DBUS_STRING_DEFINE_STATIC(_dbus_header_gvariant_signature_str, DBUS_HEADER_GVARIANT_SIGNATURE);
39 _dbus_reader_get_signature_fixed_size (const DBusString *signature, int *pos, int *alignment, int depth);
41 #define FIELD_ID_SIZE sizeof(dbus_uint64_t)
44 _dbus_get_gvariant_header_signature_str (void)
46 return &_dbus_header_gvariant_signature_str;
50 append_sized_value (DBusString *str,
54 /* always write as little endian */
56 for (i = 0; i < value_size; i++)
59 dbus_uint64_t mask = 0xFFull << move;
60 if (!_dbus_string_append_byte(str, (value & mask) >> move))
66 #define MAX_OFFSET_SIZE 8
67 #define MAX_VALUE_FOR_OFFSET_SIZE(o) ((1ULL<<(8*(o)))-1)
69 /* taken from systemd */
71 bus_gvariant_determine_word_size(size_t sz, size_t extra)
73 if (sz + extra <= 0xFF)
75 else if (sz + extra*2 <= 0xFFFF)
77 else if (sz + extra*4 <= 0xFFFFFFFF)
83 /* taken from systemd */
85 bus_gvariant_read_word_le (const void *p, size_t sz)
102 return le16toh(x.u16);
104 return le32toh(x.u32);
106 return le64toh(x.u64);
111 get_header_const_array (DBusHeader *header)
113 return _dbus_string_get_const_data (&header->data) + FIRST_GVARIANT_FIELD_OFFSET;
117 get_header_array_size (DBusHeader *header)
119 return _dbus_string_get_length (&header->data) - FIRST_GVARIANT_FIELD_OFFSET - header->padding;
123 append_offsets (DBusString *str,
124 size_t *fields_offsets,
125 size_t n_fields_offsets)
128 size_t array_size = _dbus_string_get_length (str) - FIRST_GVARIANT_FIELD_OFFSET;
129 size_t offset_size = bus_gvariant_determine_word_size (array_size, n_fields_offsets);
131 for (i = 0; i < n_fields_offsets; i++)
133 if (!append_sized_value (str, fields_offsets[i], offset_size))
140 append_field_string (DBusString *str,
144 size_t *fields_offsets,
145 size_t *n_fields_offsets)
147 dbus_bool_t res = TRUE;
149 if (*n_fields_offsets >= DBUS_HEADER_FIELD_LAST)
154 res = res && _dbus_string_align_length(str, 8);
155 res = res && append_sized_value(str, field, FIELD_ID_SIZE);
156 res = res && _dbus_string_append_len(str, value, strlen(value)+1);
157 res = res && _dbus_string_append_byte(str, 0); /* variant value-signature separator */
158 res = res && _dbus_string_append_byte(str, type);
159 fields_offsets[(*n_fields_offsets)++] = _dbus_string_get_length(str) - FIRST_GVARIANT_FIELD_OFFSET;
165 append_field_uint64 (DBusString *str,
168 size_t *fields_offsets,
169 size_t *n_fields_offsets)
171 dbus_bool_t res = TRUE;
173 if (*n_fields_offsets >= DBUS_HEADER_FIELD_LAST)
176 res = res && _dbus_string_align_length(str, 8);
177 res = res && append_sized_value(str, field, FIELD_ID_SIZE);
178 res = res && append_sized_value(str, value, 8);
179 res = res && _dbus_string_append_byte(str, 0); /* variant value-signature separator */
180 res = res && _dbus_string_append_byte(str, DBUS_TYPE_UINT64);
181 fields_offsets[(*n_fields_offsets)++] = _dbus_string_get_length(str) - FIRST_GVARIANT_FIELD_OFFSET;
186 append_field_uint32 (DBusString *str,
189 size_t *fields_offsets,
190 size_t *n_fields_offsets)
192 dbus_bool_t res = TRUE;
194 if (*n_fields_offsets >= DBUS_HEADER_FIELD_LAST)
197 res = res && _dbus_string_align_length(str, 8);
198 res = res && append_sized_value(str, field, FIELD_ID_SIZE);
199 res = res && append_sized_value(str, value, 4);
200 res = res && _dbus_string_append_byte(str, 0); /* variant value-signature separator */
201 res = res && _dbus_string_append_byte(str, DBUS_TYPE_UINT32);
202 fields_offsets[(*n_fields_offsets)++] = _dbus_string_get_length(str) - FIRST_GVARIANT_FIELD_OFFSET;
207 _dbus_header_toggle_gvariant (DBusHeader *header, dbus_bool_t gvariant)
209 header->protocol_version = gvariant ? DBUS_PROTOCOL_VERSION_GVARIANT : DBUS_MAJOR_PROTOCOL_VERSION;
213 get_next_field_address (const char *array_buffer, size_t offset)
215 return (uintptr_t)array_buffer + _DBUS_ALIGN_VALUE(offset, 8);
219 get_field_after (const char *array_buffer, size_t offset)
221 return *(dbus_uint64_t*)(get_next_field_address(array_buffer, offset));
225 _dbus_header_fill_cache (DBusHeader *header,
226 size_t *fields_offsets,
227 size_t n_fields_offsets)
229 const char *array_buffer = get_header_const_array (header);
232 if (get_header_array_size (header) > 0)
234 header->fields[get_field_after (array_buffer, 0)].value_pos = FIELD_ID_SIZE + FIRST_GVARIANT_FIELD_OFFSET;
235 if (n_fields_offsets == 0)
238 for (i=0; i < n_fields_offsets-1; i++)
240 dbus_uint64_t field = get_field_after (array_buffer, fields_offsets[i]);
241 header->fields[field].value_pos = _DBUS_ALIGN_VALUE(fields_offsets[i],8) +
242 FIELD_ID_SIZE + FIRST_GVARIANT_FIELD_OFFSET;
248 correct_header_padding (DBusHeader *header)
250 int unpadded_len = _dbus_string_get_length (&header->data);
251 if (!_dbus_string_align_length (&header->data, 8))
254 header->padding = _dbus_string_get_length (&header->data) - unpadded_len;
259 _dbus_header_gvariant_create (DBusHeader *header,
262 const char *destination,
264 const char *interface,
266 const char *error_name)
268 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
269 size_t n_fields_offsets = 0;
270 dbus_bool_t res = TRUE;
272 _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
273 byte_order == DBUS_BIG_ENDIAN);
274 _dbus_assert (((interface || type != DBUS_MESSAGE_TYPE_SIGNAL) && member) ||
276 !(interface || member || error_name));
277 _dbus_assert (_dbus_string_get_length (&header->data) == 0);
279 _dbus_header_toggle_gvariant (header, TRUE);
281 res = res && _dbus_string_append_byte (&header->data, byte_order);
282 res = res && _dbus_string_append_byte (&header->data, type);
283 res = res && _dbus_string_append_byte (&header->data, 0); /* flags */
284 res = res && _dbus_string_append_byte (&header->data, DBUS_PROTOCOL_VERSION_GVARIANT);
285 res = res && append_sized_value (&header->data, 0, sizeof(dbus_uint32_t)); /* reserved */
286 res = res && append_sized_value (&header->data, 0, sizeof(dbus_uint64_t)); /* cookie */
287 /* array of fields */
288 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_PATH, path, DBUS_TYPE_OBJECT_PATH,
289 fields_offsets, &n_fields_offsets);
290 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_DESTINATION, destination, DBUS_TYPE_STRING,
291 fields_offsets, &n_fields_offsets);
292 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_INTERFACE, interface, DBUS_TYPE_STRING,
293 fields_offsets, &n_fields_offsets);
294 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_MEMBER, member, DBUS_TYPE_STRING,
295 fields_offsets, &n_fields_offsets);
296 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_ERROR_NAME, error_name, DBUS_TYPE_STRING,
297 fields_offsets, &n_fields_offsets);
298 res = res && append_offsets (&header->data, fields_offsets, n_fields_offsets);
300 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
301 res = res && correct_header_padding (header);
307 marshal_gvariant_string (DBusString *str,
311 dbus_bool_t with_nul)
313 DBusString value_str;
314 size_t value_len = strlen(value);
319 _dbus_string_init_const_len (&value_str, value, value_len);
320 if (!_dbus_string_copy_len (&value_str, 0, value_len, str, insert_at))
326 *pos_after = insert_at + value_len;
332 _dbus_marshal_write_gvariant_basic (DBusString *str,
339 const DBusBasicValue *vp;
340 _dbus_assert (dbus_type_is_basic (type));
346 case DBUS_TYPE_STRING:
347 case DBUS_TYPE_OBJECT_PATH:
348 case DBUS_TYPE_SIGNATURE:
349 return marshal_gvariant_string (str, insert_at, vp->str, pos_after, TRUE);
350 case DBUS_TYPE_BOOLEAN:
353 return _dbus_string_insert_byte (str, insert_at, vp->u32 != FALSE);
355 return _dbus_marshal_write_basic (str, insert_at, type, value, byte_order, pos_after);
360 _dbus_marshal_read_gvariant_basic (const DBusString *str,
367 const char *str_data;
369 _dbus_assert (dbus_type_is_basic (type));
371 str_data = _dbus_string_get_const_data (str);
374 case DBUS_TYPE_STRING:
375 case DBUS_TYPE_OBJECT_PATH:
376 case DBUS_TYPE_SIGNATURE:
378 volatile char **vp = value;
379 *vp = (char*) str_data + pos;
380 pos += strlen (str_data+pos)+1;
383 case DBUS_TYPE_BOOLEAN:
385 volatile dbus_bool_t *vp = value;
386 *vp = (dbus_bool_t) _dbus_string_get_byte (str, pos);
391 _dbus_marshal_read_basic (str, pos, type, value, byte_order, new_pos);
400 get_offsets (const char *buffer, size_t container_size,
401 size_t *fields_offsets, size_t *n_fields_offsets,
404 *offset_size = bus_gvariant_determine_word_size (container_size, 0);
406 if (0 < container_size && 0 < *offset_size)
408 size_t last_offset_position = container_size - (*offset_size);
409 size_t last_offset = bus_gvariant_read_word_le (buffer + last_offset_position,
413 *n_fields_offsets = (container_size - last_offset) / (*offset_size);
415 if (*n_fields_offsets == 0 || *n_fields_offsets >= DBUS_HEADER_FIELD_LAST)
418 fields_offsets[(*n_fields_offsets)-1] = last_offset;
419 for (i = 0; i < (*n_fields_offsets)-1; i++)
421 fields_offsets[i] = bus_gvariant_read_word_le (buffer + last_offset + i*(*offset_size),
428 find_field (int field, const char *array_buffer, size_t *fields_offsets, size_t n_fields_offsets,
429 size_t *field_offset)
431 /* last_offset points to the offsets array, beyond the last element of the array container */
432 size_t last_offset = fields_offsets[n_fields_offsets-1];
434 size_t next_offset = 0;
436 while ( next_offset < last_offset &&
437 get_field_after (array_buffer, next_offset) != (dbus_uint64_t) field)
439 next_offset = fields_offsets[i];
442 if (next_offset < last_offset)
444 *field_offset = next_offset;
451 _dbus_header_gvariant_delete_field (DBusHeader *header,
454 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
455 size_t n_fields_offsets = 0;
456 size_t offset_size = 0;
457 const char *array_buffer;
459 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
461 array_buffer = get_header_const_array (header);
463 get_offsets (array_buffer,
464 get_header_array_size (header),
465 fields_offsets, &n_fields_offsets, &offset_size );
467 if (0 < n_fields_offsets)
469 /* check if the field is already in the header */
471 int field_index = find_field (field, array_buffer, fields_offsets, n_fields_offsets, &field_offset);
473 /* prepare for changing - remove array offsets and offsets */
474 _dbus_string_shorten (&header->data, n_fields_offsets*offset_size + header->padding);
476 if (field_index >= 0)
479 size_t field_len = 0;
480 size_t field_start = 0;
481 /* let's remove aligned block of the field, along with padding */
482 if (field_index == 0)
484 field_len = _DBUS_ALIGN_VALUE (fields_offsets[0],8);
488 field_len = _DBUS_ALIGN_VALUE (fields_offsets[field_index],8) -
489 _DBUS_ALIGN_VALUE (fields_offsets[field_index-1],8);
492 field_start = FIRST_GVARIANT_FIELD_OFFSET + _DBUS_ALIGN_VALUE (field_offset, 8);
494 /* if this is the last field, then there is no padding at the end */
495 if (field_start + field_len > (size_t)_dbus_string_get_length (&header->data))
497 field_len = _dbus_string_get_length (&header->data) - field_start;
500 /* remove the field */
501 _dbus_string_delete (&header->data, field_start, field_len);
502 header->fields[field].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT;
503 /* and update offsets */
504 for (; (size_t)field_index < n_fields_offsets-1; field_index++)
506 fields_offsets[field_index] = fields_offsets[field_index+1]-field_len;
510 /* remove padding from now-last field, if there is still any field */
511 if (n_fields_offsets > 0)
512 _dbus_string_shorten (&header->data,
513 _dbus_string_get_length(&header->data) -
514 (FIRST_GVARIANT_FIELD_OFFSET + fields_offsets[n_fields_offsets-1]));
520 /* It seems impossible for append_offsets() and correct_header_padding() to fail,
521 because space for offsets was already allocated */
522 if (!append_offsets(&header->data, fields_offsets, n_fields_offsets))
524 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
525 if (!correct_header_padding (header))
532 _dbus_header_set_field_basic_gvariant (DBusHeader *header,
537 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
538 size_t n_fields_offsets = 0;
539 dbus_bool_t result = TRUE;
540 const DBusBasicValue *vp = value;
541 size_t offset_size = 0;
542 const char *array_buffer;
544 _dbus_assert(field != DBUS_HEADER_FIELD_INVALID);
545 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
547 array_buffer = get_header_const_array (header);
549 result = result && _dbus_header_gvariant_delete_field (header, field);
551 /* now, we are sure that there is no such field (anymore) - so, simply append */
553 get_offsets (array_buffer,
554 get_header_array_size (header),
555 fields_offsets, &n_fields_offsets, &offset_size );
557 /* prepare for changing - remove array offsets and padding */
558 _dbus_string_shorten (&header->data, n_fields_offsets*offset_size + header->padding);
562 case DBUS_TYPE_STRING:
563 case DBUS_TYPE_OBJECT_PATH:
564 case DBUS_TYPE_SIGNATURE:
565 result = result && append_field_string (&header->data, field, vp->str, type,
566 fields_offsets, &n_fields_offsets);
568 case DBUS_TYPE_UINT32:
569 result = result && append_field_uint32 (&header->data, field, vp->u32,
570 fields_offsets, &n_fields_offsets);
572 case DBUS_TYPE_UINT64:
573 append_field_uint64 (&header->data, field, vp->u64,
574 fields_offsets, &n_fields_offsets);
578 _dbus_assert_not_reached("Not a basic type");
583 result = result && append_offsets(&header->data, fields_offsets, n_fields_offsets);
584 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
585 result = result && correct_header_padding (header);
591 _dbus_header_get_field_basic_gvariant (DBusHeader *header,
596 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
597 size_t n_fields_offsets = 0;
598 dbus_bool_t result = FALSE;
599 DBusBasicValue *vp = value;
600 size_t offset_size = 0;
601 const char *array_buffer;
603 _dbus_assert(field != DBUS_HEADER_FIELD_INVALID);
604 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
606 array_buffer = get_header_const_array (header);
608 get_offsets( array_buffer,
609 get_header_array_size (header),
610 fields_offsets, &n_fields_offsets, &offset_size );
612 if (0 < n_fields_offsets)
614 /* check if the field is already in the header */
616 int field_index = find_field (field, array_buffer, fields_offsets, n_fields_offsets, &field_offset);
617 if (0 <= field_index)
619 /* field found, get value */
620 const void *field_begin = array_buffer + _DBUS_ALIGN_VALUE(field_offset,8) + FIELD_ID_SIZE;
621 dbus_uint32_t byte_order = _dbus_header_get_byte_order (header);
625 case DBUS_TYPE_STRING:
626 case DBUS_TYPE_OBJECT_PATH:
627 case DBUS_TYPE_SIGNATURE:
629 vp->str = (char *)field_begin;
632 case DBUS_TYPE_UINT32:
634 vp->u32 = *(const dbus_uint32_t *)field_begin;
635 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
636 vp->u32 = DBUS_UINT32_SWAP_LE_BE (vp->u32);
639 case DBUS_TYPE_UINT64:
641 vp->u64 = *(const dbus_uint64_t *)field_begin;
642 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
643 vp->u64 = DBUS_UINT64_SWAP_LE_BE (vp->u64);
647 _dbus_assert_not_reached("Not a basic type");
658 _dbus_marshal_skip_gvariant_basic (const DBusString *str,
665 case DBUS_TYPE_STRING:
666 case DBUS_TYPE_OBJECT_PATH:
667 case DBUS_TYPE_SIGNATURE:
668 /* FIXME - this will require redesign... size should come from upper container */
669 *pos += strlen (_dbus_string_get_const_data (str) + *pos) + 1; /* length plus nul */
671 case DBUS_TYPE_BOOLEAN:
675 _dbus_marshal_skip_basic (str, type, byte_order, pos);
681 _dbus_header_load_gvariant (DBusHeader *header,
682 DBusValidity *validity)
684 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
685 size_t n_fields_offsets = 0;
686 size_t offset_size = 0;
687 const char *array_buffer = get_header_const_array (header);
689 get_offsets( array_buffer,
690 get_header_array_size (header),
691 fields_offsets, &n_fields_offsets, &offset_size );
693 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
698 _dbus_gvariant_raw_get_lengths (const DBusString *str,
699 dbus_uint32_t *fields_array_len_unsigned,
700 dbus_uint32_t *body_len_unsigned,
701 DBusValidity *validity)
703 size_t message_len = _dbus_string_get_length (str);
704 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 0);
705 const char *message_ptr = _dbus_string_get_const_data (str);
706 /* so, the offset of end of fields is written at offset str->len - body_offsets_size */
707 size_t end_of_fields = bus_gvariant_read_word_le (message_ptr + message_len - body_offsets_size,
709 *fields_array_len_unsigned = end_of_fields - FIRST_GVARIANT_FIELD_OFFSET;
711 *body_len_unsigned = message_len - _DBUS_ALIGN_VALUE (end_of_fields, 8);
716 _dbus_validate_gvariant_body_with_reason (const DBusString *expected_signature,
717 int expected_signature_start,
719 int *bytes_remaining,
720 const DBusString *value_str,
726 *bytes_remaining = 0;
731 _dbus_message_gvariant_get_signature (DBusMessage *message,
732 const DBusString **type_str_p,
736 size_t body_len = _dbus_string_get_length (&message->body);
737 size_t message_len = _dbus_string_get_length (&message->header.data) + body_len;
738 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 0);
739 const char *body_ptr = _dbus_string_get_const_data (&message->body);
740 const char *sig_end_ptr = body_ptr + body_len - body_offsets_size;
741 const char *sig_ptr = sig_end_ptr - 1;
743 while (sig_ptr >= body_ptr && (*sig_ptr) != 0)
748 if (sig_ptr < body_ptr)
751 if (type_str_p != NULL)
752 *type_str_p = &message->body;
753 *type_pos_p = sig_ptr - body_ptr + 1;
754 *type_str_len = sig_end_ptr - sig_ptr - 1;
760 _dbus_message_append_body_offset (DBusMessage *message)
762 size_t body_len = _dbus_string_get_length (&message->body);
763 size_t end_of_fields_offset = _dbus_string_get_length (&message->header.data) - message->header.padding;
764 size_t message_len = _dbus_string_get_length (&message->header.data) + body_len;
765 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 1);
767 return append_sized_value (&message->body, end_of_fields_offset, body_offsets_size);
771 _dbus_message_gvariant_add_signature (DBusMessage *message,
772 const DBusString *type_str)
774 dbus_bool_t res = _dbus_string_append_byte (&message->body, 0);
775 res = res && _dbus_string_append_byte (&message->body, '(');
776 res = res && marshal_gvariant_string (&message->body, _dbus_string_get_length (&message->body),
777 _dbus_string_get_const_data (type_str), NULL, FALSE);
778 res = res && _dbus_string_append_byte (&message->body, ')');
783 _dbus_message_gvariant_remove_body_offset (DBusMessage *message)
785 size_t offset_size = bus_gvariant_determine_word_size (_dbus_string_get_length (&message->header.data) +
786 _dbus_string_get_length (&message->body),
788 _dbus_string_shorten (&message->body, offset_size);
793 _dbus_message_finalize_gvariant (DBusMessage *message, dbus_bool_t remove_signature_from_header)
796 const DBusString *type_str;
798 dbus_bool_t fieldSignaturePresent;
799 dbus_bool_t res = TRUE;
801 _dbus_assert (!message->locked);
803 if (message->header.protocol_version != DBUS_PROTOCOL_VERSION_GVARIANT)
806 fieldSignaturePresent = _dbus_header_get_field_raw (&message->header,
807 DBUS_HEADER_FIELD_SIGNATURE,
810 if (fieldSignaturePresent)
812 /* if there is signature field, then we need to move this signature to body,
813 * and delete the field
815 const char *sig_ptr = _dbus_string_get_const_data (type_str) + type_pos;
819 _dbus_string_init_const (&str, sig_ptr);
821 /* There is a special case for structs of fixed size. They need to have size
822 * which is a multiply of required alignment.
823 * The root struct must be finalized just before adding signature and locking the message.
824 * Luckily, fixed size means that there are no offsets in the message body.
826 fixed_size = _dbus_reader_get_signature_fixed_size (type_str, &type_pos, &alignment, 1);
829 int current_length = _dbus_string_get_length (&message->body);
830 int diff = _DBUS_ALIGN_VALUE (current_length, alignment) - current_length;
832 _dbus_string_insert_bytes (&message->body, current_length, diff, 0);
837 /* If there is no signature field, then the body is empty.
838 * However, we need to add signature anyway, because body is a variant.
840 _dbus_string_init_const (&str, "");
843 /* Let's set the body also */
844 res = res && _dbus_string_set_length (&message->body, 0);
845 res = res && _dbus_string_append_byte (&message->body, 0);
848 res = res && _dbus_message_gvariant_add_signature (message, &str);
850 if (res && fieldSignaturePresent && remove_signature_from_header)
851 res = res && _dbus_header_gvariant_delete_field (&message->header, DBUS_HEADER_FIELD_SIGNATURE);
853 res = res && _dbus_message_append_body_offset (message);
858 /* returns length of the body inside the outermost variant
859 * that is, without offset and signature from the end of messages
862 _dbus_message_gvariant_get_body_length (DBusMessage *message)
868 body_len = _dbus_string_get_length (&message->body);
870 /* Unlocked messages don't have any body offset or signature appended yet. */
871 if (!message->locked)
874 /* We need to find where the root container actually ends.
875 * We know there are a zero-byte, a signature and a body offset appended.
876 * We check offset's size, skip it, and go back through the signature until
877 * the zero byte, which is one byte past the end of the root container.
879 message_len = body_len + _dbus_string_get_length (&message->header.data);
880 offset_size = bus_gvariant_determine_word_size (message_len, 0);
882 if (body_len <= offset_size)
885 body_len -= offset_size;
887 /* searching for variant's NULL byte */
888 while (body_len > 0 && _dbus_string_get_byte (&message->body, body_len) != 0)
895 get_max (int a, int b)
897 return (a>b) ? a : b;
901 update_size (int current_size, int size_of_element, int *alignment, int new_alignment)
903 *alignment = get_max (*alignment, new_alignment);
904 current_size = _DBUS_ALIGN_VALUE (current_size, *alignment);
905 return current_size + size_of_element;
909 _dbus_reader_get_signature_fixed_size (const DBusString *signature, int *pos, int *alignment,
913 int current_alignment = 1;
914 dbus_bool_t variable = FALSE;
915 int length = _dbus_string_get_length (signature);
917 char c = _dbus_string_get_byte (signature, *pos);
918 if (c == DBUS_STRUCT_BEGIN_CHAR || c == DBUS_DICT_ENTRY_BEGIN_CHAR)
925 switch (_dbus_string_get_byte (signature, *pos))
928 case DBUS_TYPE_BOOLEAN:
931 case DBUS_TYPE_INT16:
932 case DBUS_TYPE_UINT16:
933 res = update_size (res, 2, ¤t_alignment, 2);
935 case DBUS_TYPE_INT32:
936 case DBUS_TYPE_UINT32:
937 case DBUS_TYPE_UNIX_FD:
938 res = update_size (res, 4, ¤t_alignment, 4);
940 case DBUS_TYPE_INT64:
941 case DBUS_TYPE_UINT64:
942 case DBUS_TYPE_DOUBLE:
943 res = update_size (res, 8, ¤t_alignment, 8);
945 case DBUS_STRUCT_END_CHAR:
946 case DBUS_DICT_ENTRY_END_CHAR:
948 /* For fixed-size structs we need to account padding.
951 res = _DBUS_ALIGN_VALUE (res, current_alignment);
953 case DBUS_STRUCT_BEGIN_CHAR:
954 case DBUS_DICT_ENTRY_BEGIN_CHAR:
956 int alignment_recursive;
957 int res_recursive = _dbus_reader_get_signature_fixed_size (signature, pos, &alignment_recursive, 0);
958 if (res_recursive == 0)
959 variable = TRUE; /* variable size detected */
961 /* we need to update at least alignment */
962 res = update_size (res, res_recursive, ¤t_alignment, alignment_recursive);
965 case DBUS_TYPE_VARIANT:
966 current_alignment = 8;
969 case DBUS_TYPE_ARRAY:
971 int alignment_recursive;
972 int recursive_pos = *pos + 1;
973 int res_recursive = _dbus_reader_get_signature_fixed_size (signature, &recursive_pos, &alignment_recursive, 0);
975 variable = TRUE; /* variable size detected */
977 /* we need to update alignment */
978 res = update_size (res, res_recursive, ¤t_alignment, alignment_recursive);
980 /* and update position */
981 *pos = recursive_pos;
984 case DBUS_TYPE_INVALID:
988 variable = TRUE; /* variable size detected */
991 } while (depth > 0 && *pos < length);
993 /* we want to point it to the last character, to allow upper instance to skip it */
996 if (alignment != NULL)
997 *alignment = current_alignment;
999 return variable ? 0 : res;
1003 _dbus_reader_get_type_fixed_size (DBusTypeReader *reader, int *alignment)
1005 int pos = reader->type_pos;
1006 return _dbus_reader_get_signature_fixed_size (reader->type_str, &pos, alignment, 0);
1010 _dbus_type_gvariant_get_fixed_size (const DBusString *type_str, int type_pos, int *alignment)
1012 return _dbus_reader_get_signature_fixed_size (type_str, &type_pos, alignment, 0);
1016 get_current_type_types_only (const DBusTypeReader *reader)
1019 if (reader->finished)
1020 t = DBUS_TYPE_INVALID;
1022 t = _dbus_first_type_in_signature (reader->type_str,
1028 /* This is for structs and dict entries.
1029 * Counts variable elements inside a container.
1030 * This is equal to number of offsets embedded into the container.
1033 _dbus_reader_count_offsets (const DBusTypeReader *reader)
1037 dbus_bool_t prev_is_variable = FALSE;
1039 int ending_char = 0;
1041 _dbus_type_reader_init_types_only (&r,
1045 r.klass = reader->klass;
1047 /* In case we are in root container, we have signature without external parentheses.
1048 * We go until ending nul, starting with position 0.
1049 * Otherwise, we are in a container, so let's check what kind of container it is,
1050 * and set proper terminating character.
1054 /* Check what container we're in */
1055 switch (_dbus_string_get_byte (r.type_str, r.type_pos-1))
1057 case DBUS_STRUCT_BEGIN_CHAR:
1058 ending_char = DBUS_STRUCT_END_CHAR;
1060 case DBUS_DICT_ENTRY_BEGIN_CHAR:
1061 ending_char = DBUS_DICT_ENTRY_END_CHAR;
1064 _dbus_assert_not_reached ("function must be called inside structs or dict entries");
1068 r.finished = (_dbus_string_get_byte (r.type_str, r.type_pos) == ending_char);
1070 while ((current_type = get_current_type_types_only (&r)) != DBUS_TYPE_INVALID)
1072 int size = _dbus_reader_get_type_fixed_size (&r, NULL);
1073 if (prev_is_variable)
1075 prev_is_variable = (size == 0);
1076 _dbus_type_signature_next (_dbus_string_get_const_data(r.type_str), &r.type_pos);
1077 r.finished = (_dbus_string_get_byte (r.type_str, r.type_pos) == ending_char);
1083 _dbus_reader_get_offset_of_end_of_variable (DBusTypeReader *reader)
1085 if (reader->is_variant)
1087 /* variant has its end set to the separating 0 */
1088 return reader->value_end;
1092 const char *buffer = _dbus_string_get_const_data (reader->value_str) + reader->value_start;
1093 size_t container_size = reader->value_end - reader->value_start;
1094 size_t offset_size = bus_gvariant_determine_word_size (container_size, 0);
1095 int index_from_back = reader->offsets_from_back ?
1096 reader->variable_index :
1097 reader->n_offsets - 1 - reader->variable_index;
1099 if (0 < container_size && 0 <= index_from_back)
1101 size_t required_offset_position = container_size - (index_from_back+1)*offset_size;
1102 if (index_from_back < reader->n_offsets)
1103 return reader->value_start +
1104 bus_gvariant_read_word_le (buffer + required_offset_position,
1106 else if (reader->offsets_from_back)
1107 return reader->value_start +
1108 container_size - (reader->n_offsets * offset_size); /* this is end of internal container */
1112 return reader->value_start;
1116 _dbus_reader_count_array_elems (const DBusTypeReader *reader)
1118 /* To count the offsets we need to have offsets size and
1119 * the start and end of the offsets. The start of the offsets
1120 * is computed from the value of the last offset.
1122 const char *buffer = _dbus_string_get_const_data (reader->value_str) + reader->value_start;
1123 size_t container_size = reader->value_end - reader->value_start;
1124 size_t offset_size = bus_gvariant_determine_word_size (container_size, 0);
1125 size_t last_offset = container_size; /* this will give 0 if container is smaller than a single offset */
1126 if (container_size > offset_size)
1127 last_offset = bus_gvariant_read_word_le (buffer + container_size - offset_size, offset_size);
1128 return (container_size - last_offset) / offset_size;
1132 write_offset (DBusString *offsets,
1138 dbus_bool_t res = _dbus_string_init_preallocated (&str, offset_size);
1139 res = res && append_sized_value (&str, offset, offset_size);
1140 res = res && _dbus_string_copy_len (&str, 0, offset_size, offsets, insert_at);
1141 _dbus_string_free (&str);
1146 prepend_offset (DBusString *offsets,
1150 return write_offset (offsets, offset, offset_size, 0);
1154 append_offset (DBusString *offsets,
1158 return write_offset (offsets, offset, offset_size, _dbus_string_get_length(offsets));
1162 convert_offsets (DBusString *offsets,
1163 size_t old_offsets_size,
1164 size_t new_offsets_size)
1166 char *old_offsets = NULL;
1167 size_t n_offsets = _dbus_string_get_length (offsets) / old_offsets_size;
1168 dbus_bool_t result = _dbus_string_steal_data (offsets, &old_offsets);
1171 for (i = 0; i < n_offsets && result; i++)
1173 size_t offset = bus_gvariant_read_word_le (old_offsets + i*old_offsets_size, old_offsets_size);
1174 result = result && append_sized_value (offsets, offset, new_offsets_size);
1177 dbus_free (old_offsets);
1183 get_offsets_count (DBusString *offsets, size_t offsets_size)
1185 return _dbus_string_get_length (offsets) / offsets_size;
1189 check_offsets_for_adding (DBusTypeWriter *writer)
1191 size_t container_size = writer->value_pos - writer->value_start;
1192 size_t n_offsets = get_offsets_count (writer->offsets,
1193 writer->offsets_size);
1194 size_t offsets_size = bus_gvariant_determine_word_size (container_size, n_offsets + 1);
1195 if (offsets_size != writer->offsets_size)
1197 if (!convert_offsets (writer->offsets, writer->offsets_size, offsets_size))
1199 writer->offsets_size = offsets_size;
1205 convert_offsets_in_body (DBusTypeWriter *writer,
1206 size_t new_offsets_size)
1211 dbus_bool_t result = _dbus_string_init (&offsets);
1214 result = result && _dbus_string_move (writer->value_str, writer->value_pos, &offsets, 0);
1215 n_offsets = _dbus_string_get_length (&offsets) / writer->offsets_size;
1216 old_offsets = _dbus_string_get_data (&offsets);
1218 for (i = 0; i < n_offsets && result; i++)
1220 size_t offset = bus_gvariant_read_word_le (old_offsets + i*writer->offsets_size, writer->offsets_size);
1221 result = result && append_sized_value (writer->value_str, offset, new_offsets_size);
1224 _dbus_string_free (&offsets);
1229 check_offsets_in_body_for_adding (DBusTypeWriter *writer)
1231 size_t container_size = writer->value_pos - writer->value_start;
1232 size_t n_offsets = (_dbus_string_get_length (writer->value_str) - writer->value_pos) / writer->offsets_size;
1233 size_t offsets_size = bus_gvariant_determine_word_size (container_size, n_offsets + 1);
1234 if (offsets_size != writer->offsets_size)
1236 if (!convert_offsets_in_body (writer, offsets_size))
1238 writer->offsets_size = offsets_size;
1244 _dbus_writer_gvariant_add_offset_with_variability (DBusTypeWriter *writer,
1247 writer->is_fixed = writer->is_fixed && fixed;
1249 if (writer->body_container)
1251 check_offsets_in_body_for_adding (writer);
1253 if (*writer->u.root.last_offset != GVARIANT_LAST_OFFSET_NOT_SET)
1255 write_offset (writer->value_str,
1256 *writer->u.root.last_offset,
1257 writer->offsets_size,
1261 *writer->u.root.last_offset = writer->value_pos - writer->value_start;
1263 *writer->u.root.last_offset = GVARIANT_LAST_OFFSET_NOT_SET;
1265 else if (DBUS_TYPE_STRUCT == writer->container_type ||
1266 DBUS_TYPE_DICT_ENTRY == writer->container_type)
1268 check_offsets_for_adding (writer);
1270 if (writer->u.struct_or_dict.last_offset != GVARIANT_LAST_OFFSET_NOT_SET)
1272 prepend_offset (writer->offsets,
1273 writer->u.struct_or_dict.last_offset,
1274 writer->offsets_size);
1277 writer->u.struct_or_dict.last_offset = writer->value_pos - writer->value_start;
1279 writer->u.struct_or_dict.last_offset = GVARIANT_LAST_OFFSET_NOT_SET;
1281 else if (DBUS_TYPE_ARRAY == writer->container_type)
1283 if (writer->offsets_size > 0)
1285 check_offsets_for_adding (writer);
1287 if (!append_offset (writer->offsets,
1288 writer->value_pos - writer->value_start,
1289 writer->offsets_size))
1297 _dbus_writer_gvariant_add_offset (DBusTypeWriter *writer,
1300 return _dbus_writer_gvariant_add_offset_with_variability (writer, dbus_type_is_fixed (type));
1303 /* this function gets only known alignments - other are 1 */
1305 get_alignment (int type)
1309 case DBUS_TYPE_INT16:
1310 case DBUS_TYPE_UINT16:
1312 case DBUS_TYPE_INT32:
1313 case DBUS_TYPE_UINT32:
1314 case DBUS_TYPE_UNIX_FD:
1316 case DBUS_TYPE_INT64:
1317 case DBUS_TYPE_UINT64:
1318 case DBUS_TYPE_DOUBLE:
1319 case DBUS_TYPE_VARIANT:
1328 fix_struct_alignment_value (DBusTypeWriter *writer, int alignment)
1330 dbus_bool_t result = TRUE;
1331 int old_alignment = writer->alignment;
1332 if (old_alignment < alignment)
1334 int diff = _DBUS_ALIGN_VALUE (writer->value_start, alignment) - writer->value_start;
1335 result = _dbus_string_insert_bytes (writer->value_str, writer->value_start, diff, 0);
1336 writer->value_start += diff;
1337 writer->value_pos += diff;
1338 writer->alignment = alignment;
1344 fix_struct_alignment (DBusTypeWriter *writer, int type)
1346 return fix_struct_alignment_value (writer, get_alignment (type));
1350 update_root_last_pos (DBusTypeWriter *writer)
1352 if (writer->body_container)
1353 *writer->u.root.last_pos = writer->value_pos;
1357 _dbus_type_writer_gvariant_write_basic_no_typecode (DBusTypeWriter *writer,
1361 dbus_bool_t result = TRUE;
1363 if (writer->container_type == DBUS_TYPE_STRUCT || writer->container_type == DBUS_TYPE_DICT_ENTRY)
1364 result = fix_struct_alignment (writer, type);
1366 result = result && _dbus_marshal_write_gvariant_basic (writer->value_str,
1371 &writer->value_pos);
1373 update_root_last_pos (writer);
1375 result = result && _dbus_writer_gvariant_add_offset (writer, type);
1380 write_offsets (DBusString *dest, size_t insert_at, DBusString *offsets)
1382 return _dbus_string_copy (offsets, 0, dest, insert_at);
1386 _dbus_writer_unrecurse_gvariant_write (DBusTypeWriter *writer,
1387 DBusTypeWriter *sub)
1389 dbus_bool_t result = TRUE;
1391 if (writer->alignment < sub->alignment)
1392 writer->alignment = sub->alignment;
1394 switch (sub->container_type) {
1395 case DBUS_TYPE_STRUCT:
1396 case DBUS_TYPE_DICT_ENTRY:
1401 if (NULL != sub->offsets)
1403 write_offsets (sub->value_str, sub->value_pos, sub->offsets);
1405 _dbus_string_free (sub->offsets);
1406 dbus_free (sub->offsets);
1409 diff = _DBUS_ALIGN_VALUE (writer->value_pos, sub->alignment) - writer->value_pos;
1411 result = _dbus_string_insert_bytes (writer->value_str, writer->value_pos, diff, 0);
1412 writer->value_pos += diff;
1413 sub_len = _dbus_string_get_length (sub->value_str);
1414 result = result && _dbus_string_copy_len (sub->value_str, 0,
1418 writer->value_pos += sub_len;
1420 /* Structs may have padding if they are fixed-size structs.
1421 * This is because of requirement that struct size must be a multiply
1422 * of required alignment.
1426 diff = _DBUS_ALIGN_VALUE (sub_len, sub->alignment) - sub_len;
1427 result = result && _dbus_string_insert_bytes (writer->value_str, writer->value_pos, diff, 0);
1428 writer->value_pos += diff;
1431 _dbus_string_free (sub->value_str);
1432 dbus_free (sub->value_str);
1436 case DBUS_TYPE_VARIANT:
1440 /* write separating nul byte */
1441 result = _dbus_string_insert_byte (sub->value_str, sub->value_pos, 0);
1442 sub->value_pos += 1;
1444 /* write signature */
1445 sub_type_len = _dbus_string_get_length (sub->type_str);
1446 result = result && _dbus_string_copy_len (sub->type_str, 0,
1450 sub->value_pos += sub_type_len;
1452 /* free type string allocated in writer_recurse_variant() */
1453 _dbus_string_free (sub->type_str);
1454 dbus_free (sub->type_str);
1456 /* update parent's string pointer */
1457 writer->value_pos = sub->value_pos;
1461 case DBUS_TYPE_ARRAY:
1462 writer->value_pos = sub->value_pos;
1463 if (NULL != sub->offsets)
1465 write_offsets (sub->value_str, sub->value_pos, sub->offsets);
1467 writer->value_pos += _dbus_string_get_length (sub->offsets);
1469 _dbus_string_free (sub->offsets);
1470 dbus_free (sub->offsets);
1475 _dbus_assert_not_reached("Invalid container type");
1478 update_root_last_pos (writer);
1480 /* well, we don't know where in the type string beginning of current container is */
1481 result = result && _dbus_writer_gvariant_add_offset_with_variability (writer, sub->is_fixed);
1487 _dbus_type_reader_gvariant_init (DBusTypeReader *reader,
1488 DBusMessage *message)
1490 reader->gvariant = TRUE;
1491 /* GVariant wraps contents into struct, but in this place type is already
1492 * stripped off the parentheses (see get_const_signature()).
1495 reader->value_end = _dbus_message_gvariant_get_body_length (message);
1496 reader->n_offsets = _dbus_reader_count_offsets (reader);
1500 _dbus_message_gvariant_convert_to_unlocked (DBusMessage *message)
1502 const char *signature;
1503 DBusTypeReader reader;
1504 DBusString signature_str;
1505 int count_variable_sized = 0;
1507 _dbus_assert (_dbus_message_is_gvariant (message));
1508 _dbus_assert (message->locked);
1510 /* Differences between locked and unlocked GVariant messages:
1512 * - body contains footer (zero byte, signature in parentheses, body offset);
1513 * - there is no signature field in header;
1514 * - 'signature' member is set if the signature was needed;
1515 * - 'gvariant_body_last_'* members are unused.
1517 * - body ends with root container offsets, if any;
1518 * - header contains signature field;
1519 * - 'signature' member is NULL;
1520 * - 'gvariant_body_last_'* members are set to proper values.
1522 * So, to convert to unlocked we need to:
1523 * - check if the last type is a variable-size type; if so, we need
1524 * to remember its end position for adding it as an offset to the body
1525 * on first append (set 'gvariant_body_last_offset');
1526 * - set 'gvariant_body_last_pos' to correct writing position (just before the offsets);
1527 * - extract signature from the body and move it to the header field;
1528 * - ensure the 'signature' member is NULL;
1529 * - shrink body length to end just after the offsets.
1532 /* Get the signature C-string, we'll need it to move it from the body
1533 * to the header field, and for iterating over types.
1534 * We need to clear message->signature later, as the function sets it.
1536 signature = dbus_message_get_signature (message);
1539 _dbus_string_free (message->signature);
1540 message->signature = NULL;
1544 /* Initialize 'reader' for iterating over types from the signature.
1546 _dbus_string_init_const (&signature_str, signature);
1548 _dbus_type_reader_init_types_only (&reader, &signature_str, 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);