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);
37 #define FIELD_ID_SIZE sizeof(dbus_uint64_t)
40 _dbus_get_gvariant_header_signature_str (void)
42 return &_dbus_header_gvariant_signature_str;
46 append_sized_value (DBusString *str,
50 /* always write as little endian */
52 for (i = 0; i < value_size; i++)
55 size_t mask = 0xFF << move;
56 if (!_dbus_string_append_byte(str, (value & mask) >> move))
62 #define MAX_OFFSET_SIZE 8
63 #define MAX_VALUE_FOR_OFFSET_SIZE(o) ((1ULL<<(8*(o)))-1)
65 /* taken from systemd */
67 bus_gvariant_determine_word_size(size_t sz, size_t extra)
69 if (sz + extra <= 0xFF)
71 else if (sz + extra*2 <= 0xFFFF)
73 else if (sz + extra*4 <= 0xFFFFFFFF)
79 /* taken from systemd */
81 bus_gvariant_read_word_le (const void *p, size_t sz)
98 return le16toh(x.u16);
100 return le32toh(x.u32);
102 return le64toh(x.u64);
107 get_header_const_array (DBusHeader *header)
109 return _dbus_string_get_const_data (&header->data) + FIRST_GVARIANT_FIELD_OFFSET;
113 get_header_array_size (DBusHeader *header)
115 return _dbus_string_get_length (&header->data) - FIRST_GVARIANT_FIELD_OFFSET - header->padding;
119 append_offsets (DBusString *str,
120 size_t *fields_offsets,
121 size_t n_fields_offsets)
124 size_t array_size = _dbus_string_get_length (str) - FIRST_GVARIANT_FIELD_OFFSET;
125 size_t offset_size = bus_gvariant_determine_word_size (array_size, n_fields_offsets);
127 for (i = 0; i < n_fields_offsets; i++)
129 if (!append_sized_value (str, fields_offsets[i], offset_size))
136 append_field_string (DBusString *str,
140 size_t *fields_offsets,
141 size_t *n_fields_offsets)
143 dbus_bool_t res = TRUE;
146 res = res && _dbus_string_align_length(str, 8);
147 res = res && append_sized_value(str, field, FIELD_ID_SIZE);
148 res = res && _dbus_string_append_len(str, value, strlen(value)+1);
149 res = res && _dbus_string_append_byte(str, 0); /* variant value-signature separator */
150 res = res && _dbus_string_append_byte(str, type);
151 fields_offsets[(*n_fields_offsets)++] = _dbus_string_get_length(str) - FIRST_GVARIANT_FIELD_OFFSET;
157 append_field_uint64 (DBusString *str,
160 size_t *fields_offsets,
161 size_t *n_fields_offsets)
163 dbus_bool_t res = TRUE;
164 res = res && _dbus_string_align_length(str, 8);
165 res = res && append_sized_value(str, field, FIELD_ID_SIZE);
166 res = res && append_sized_value(str, value, 8);
167 res = res && _dbus_string_append_byte(str, 0); /* variant value-signature separator */
168 res = res && _dbus_string_append_byte(str, DBUS_TYPE_UINT64);
169 fields_offsets[(*n_fields_offsets)++] = _dbus_string_get_length(str) - FIRST_GVARIANT_FIELD_OFFSET;
174 append_field_uint32 (DBusString *str,
177 size_t *fields_offsets,
178 size_t *n_fields_offsets)
180 dbus_bool_t res = TRUE;
181 res = res && _dbus_string_align_length(str, 8);
182 res = res && append_sized_value(str, field, FIELD_ID_SIZE);
183 res = res && append_sized_value(str, value, 4);
184 res = res && _dbus_string_append_byte(str, 0); /* variant value-signature separator */
185 res = res && _dbus_string_append_byte(str, DBUS_TYPE_UINT32);
187 fields_offsets[(*n_fields_offsets)++] = _dbus_string_get_length(str) - FIRST_GVARIANT_FIELD_OFFSET;
192 _dbus_header_toggle_gvariant (DBusHeader *header, dbus_bool_t gvariant)
194 header->protocol_version = gvariant ? DBUS_PROTOCOL_VERSION_GVARIANT : DBUS_MAJOR_PROTOCOL_VERSION;
198 get_next_field_address (const char *array_buffer, size_t offset)
200 return array_buffer + _DBUS_ALIGN_VALUE(offset, 8);
204 get_field_after (const char *array_buffer, size_t offset)
206 return *(dbus_uint64_t*)(get_next_field_address(array_buffer, offset));
210 _dbus_header_fill_cache (DBusHeader *header,
211 size_t *fields_offsets,
212 size_t n_fields_offsets)
214 const char *array_buffer = get_header_const_array (header);
217 if (get_header_array_size (header) > 0)
219 header->fields[get_field_after (array_buffer, 0)].value_pos = FIELD_ID_SIZE + FIRST_GVARIANT_FIELD_OFFSET;
220 for (i=0; i < n_fields_offsets-1; i++)
222 dbus_uint64_t field = get_field_after (array_buffer, fields_offsets[i]);
223 header->fields[field].value_pos = _DBUS_ALIGN_VALUE(fields_offsets[i],8) +
224 FIELD_ID_SIZE + FIRST_GVARIANT_FIELD_OFFSET;
230 correct_header_padding (DBusHeader *header)
232 int unpadded_len = _dbus_string_get_length (&header->data);
233 if (!_dbus_string_align_length (&header->data, 8))
236 header->padding = _dbus_string_get_length (&header->data) - unpadded_len;
241 _dbus_header_gvariant_create (DBusHeader *header,
244 const char *destination,
246 const char *interface,
248 const char *error_name)
250 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
251 size_t n_fields_offsets = 0;
252 dbus_bool_t res = TRUE;
254 _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
255 byte_order == DBUS_BIG_ENDIAN);
256 _dbus_assert (((interface || type != DBUS_MESSAGE_TYPE_SIGNAL) && member) ||
258 !(interface || member || error_name));
259 _dbus_assert (_dbus_string_get_length (&header->data) == 0);
261 _dbus_header_toggle_gvariant (header, TRUE);
263 res = res && _dbus_string_append_byte (&header->data, byte_order);
264 res = res && _dbus_string_append_byte (&header->data, type);
265 res = res && _dbus_string_append_byte (&header->data, 0); /* flags */
266 res = res && _dbus_string_append_byte (&header->data, DBUS_PROTOCOL_VERSION_GVARIANT);
267 res = res && append_sized_value (&header->data, 0, sizeof(dbus_uint32_t)); /* reserved */
268 res = res && append_sized_value (&header->data, 0, sizeof(dbus_uint64_t)); /* cookie */
269 /* array of fields */
270 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_PATH, path, DBUS_TYPE_OBJECT_PATH,
271 fields_offsets, &n_fields_offsets);
272 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_DESTINATION, destination, DBUS_TYPE_STRING,
273 fields_offsets, &n_fields_offsets);
274 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_INTERFACE, interface, DBUS_TYPE_STRING,
275 fields_offsets, &n_fields_offsets);
276 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_MEMBER, member, DBUS_TYPE_STRING,
277 fields_offsets, &n_fields_offsets);
278 res = res && append_field_string (&header->data, DBUS_HEADER_FIELD_ERROR_NAME, error_name, DBUS_TYPE_STRING,
279 fields_offsets, &n_fields_offsets);
280 res = res && append_offsets (&header->data, fields_offsets, n_fields_offsets);
282 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
283 res = res && correct_header_padding (header);
289 marshal_gvariant_string (DBusString *str,
293 dbus_bool_t with_nul)
295 DBusString value_str;
296 size_t value_len = strlen(value);
301 _dbus_string_init_const_len (&value_str, value, value_len);
302 if (!_dbus_string_copy_len (&value_str, 0, value_len, str, insert_at))
308 *pos_after = insert_at + value_len;
314 _dbus_marshal_write_gvariant_basic (DBusString *str,
321 const DBusBasicValue *vp;
322 _dbus_assert (dbus_type_is_basic (type));
328 case DBUS_TYPE_STRING:
329 case DBUS_TYPE_OBJECT_PATH:
330 case DBUS_TYPE_SIGNATURE:
331 return marshal_gvariant_string (str, insert_at, vp->str, pos_after, TRUE);
332 case DBUS_TYPE_BOOLEAN:
335 return _dbus_string_insert_byte (str, insert_at, vp->u32 != FALSE);
337 return _dbus_marshal_write_basic (str, insert_at, type, value, byte_order, pos_after);
342 _dbus_marshal_read_gvariant_basic (const DBusString *str,
349 const char *str_data;
351 _dbus_assert (dbus_type_is_basic (type));
353 str_data = _dbus_string_get_const_data (str);
356 case DBUS_TYPE_STRING:
357 case DBUS_TYPE_OBJECT_PATH:
358 case DBUS_TYPE_SIGNATURE:
360 volatile char **vp = value;
361 *vp = (char*) str_data + pos;
362 pos += strlen (str_data+pos)+1;
365 case DBUS_TYPE_BOOLEAN:
367 volatile dbus_bool_t *vp = value;
368 *vp = (dbus_bool_t) _dbus_string_get_byte (str, pos);
373 _dbus_marshal_read_basic (str, pos, type, value, byte_order, new_pos);
382 get_offsets (const char *buffer, size_t container_size,
383 size_t *fields_offsets, size_t *n_fields_offsets,
386 *offset_size = bus_gvariant_determine_word_size (container_size, 0);
388 if (0 < container_size && 0 < *offset_size)
390 size_t last_offset_position = container_size - (*offset_size);
391 size_t last_offset = bus_gvariant_read_word_le (buffer + last_offset_position,
395 *n_fields_offsets = (container_size - last_offset) / (*offset_size);
396 fields_offsets[(*n_fields_offsets)-1] = last_offset;
397 for (i = 0; i < (*n_fields_offsets)-1; i++)
399 fields_offsets[i] = bus_gvariant_read_word_le (buffer + last_offset + i*(*offset_size),
406 find_field (int field, const char *array_buffer, size_t *fields_offsets, size_t n_fields_offsets,
407 size_t *field_offset)
409 /* last_offset points to the offsets array, beyond the last element of the array container */
410 size_t last_offset = fields_offsets[n_fields_offsets-1];
412 size_t next_offset = 0;
414 while ( next_offset < last_offset && get_field_after (array_buffer, next_offset) != field)
416 next_offset = fields_offsets[i];
419 if (next_offset < last_offset)
421 *field_offset = next_offset;
428 _dbus_header_gvariant_delete_field (DBusHeader *header,
431 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
432 size_t n_fields_offsets = 0;
433 size_t offset_size = 0;
434 const char *array_buffer;
436 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
438 array_buffer = get_header_const_array (header);
440 get_offsets (array_buffer,
441 get_header_array_size (header),
442 fields_offsets, &n_fields_offsets, &offset_size );
444 if (0 < n_fields_offsets)
446 /* check if the field is already in the header */
448 int field_index = find_field (field, array_buffer, fields_offsets, n_fields_offsets, &field_offset);
450 /* prepare for changing - remove array offsets and offsets */
451 _dbus_string_shorten (&header->data, n_fields_offsets*offset_size + header->padding);
453 if (field_index >= 0)
456 size_t field_len = 0;
457 size_t field_start = 0;
458 /* let's remove aligned block of the field, along with padding */
459 if (field_index == 0)
461 field_len = _DBUS_ALIGN_VALUE (fields_offsets[0],8);
465 field_len = _DBUS_ALIGN_VALUE (fields_offsets[field_index],8) -
466 _DBUS_ALIGN_VALUE (fields_offsets[field_index-1],8);
469 field_start = FIRST_GVARIANT_FIELD_OFFSET + _DBUS_ALIGN_VALUE (field_offset, 8);
471 /* if this is the last field, then there is no padding at the end */
472 if (field_start + field_len > (size_t)_dbus_string_get_length (&header->data))
474 field_len = _dbus_string_get_length (&header->data) - field_start;
477 /* remove the field */
478 _dbus_string_delete (&header->data, field_start, field_len);
479 header->fields[field].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT;
480 /* and update offsets */
481 for (; (size_t)field_index < n_fields_offsets-1; field_index++)
483 fields_offsets[field_index] = fields_offsets[field_index+1]-field_len;
487 /* remove padding from now-last field */
488 _dbus_string_shorten (&header->data,
489 _dbus_string_get_length(&header->data) -
490 (FIRST_GVARIANT_FIELD_OFFSET + fields_offsets[n_fields_offsets-1]));
495 /* It seems impossible for append_offsets() and correct_header_padding() to fail,
496 because space for offsets was already allocated */
497 if (!append_offsets(&header->data, fields_offsets, n_fields_offsets))
499 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
500 if (!correct_header_padding (header))
507 _dbus_header_set_field_basic_gvariant (DBusHeader *header,
512 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
513 size_t n_fields_offsets = 0;
514 dbus_bool_t result = TRUE;
515 const DBusBasicValue *vp = value;
516 size_t offset_size = 0;
517 const char *array_buffer;
519 _dbus_assert(field != DBUS_HEADER_FIELD_INVALID);
520 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
522 array_buffer = get_header_const_array (header);
524 result = result && _dbus_header_gvariant_delete_field (header, field);
526 /* now, we are sure that there is no such field (anymore) - so, simply append */
528 get_offsets (array_buffer,
529 get_header_array_size (header),
530 fields_offsets, &n_fields_offsets, &offset_size );
532 /* prepare for changing - remove array offsets and padding */
533 _dbus_string_shorten (&header->data, n_fields_offsets*offset_size + header->padding);
537 case DBUS_TYPE_STRING:
538 case DBUS_TYPE_OBJECT_PATH:
539 case DBUS_TYPE_SIGNATURE:
540 result = result && append_field_string (&header->data, field, vp->str, type,
541 fields_offsets, &n_fields_offsets);
543 case DBUS_TYPE_UINT32:
544 result = result && append_field_uint32 (&header->data, field, vp->u32,
545 fields_offsets, &n_fields_offsets);
547 case DBUS_TYPE_UINT64:
548 append_field_uint64 (&header->data, field, vp->u64,
549 fields_offsets, &n_fields_offsets);
553 _dbus_assert_not_reached("Not a basic type");
558 result = result && append_offsets(&header->data, fields_offsets, n_fields_offsets);
559 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
560 result = result && correct_header_padding (header);
566 _dbus_header_get_field_basic_gvariant (DBusHeader *header,
571 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
572 size_t n_fields_offsets = 0;
573 dbus_bool_t result = FALSE;
574 DBusBasicValue *vp = value;
575 size_t offset_size = 0;
576 const char *array_buffer;
578 _dbus_assert(field != DBUS_HEADER_FIELD_INVALID);
579 _dbus_assert(field <= DBUS_HEADER_FIELD_LAST);
581 array_buffer = get_header_const_array (header);
583 get_offsets( array_buffer,
584 get_header_array_size (header),
585 fields_offsets, &n_fields_offsets, &offset_size );
587 if (0 < n_fields_offsets)
589 /* check if the field is already in the header */
591 int field_index = find_field (field, array_buffer, fields_offsets, n_fields_offsets, &field_offset);
592 if (0 <= field_index)
594 /* field found, get value */
595 const void *field_begin = array_buffer + _DBUS_ALIGN_VALUE(field_offset,8) + FIELD_ID_SIZE;
596 dbus_uint32_t byte_order = _dbus_header_get_byte_order (header);
600 case DBUS_TYPE_STRING:
601 case DBUS_TYPE_OBJECT_PATH:
602 case DBUS_TYPE_SIGNATURE:
604 vp->str = (char *)field_begin;
607 case DBUS_TYPE_UINT32:
609 vp->u32 = *(const dbus_uint32_t *)field_begin;
610 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
611 vp->u32 = DBUS_UINT32_SWAP_LE_BE (vp->u32);
614 case DBUS_TYPE_UINT64:
616 vp->u64 = *(const dbus_uint64_t *)field_begin;
617 if (byte_order != DBUS_COMPILER_BYTE_ORDER)
618 vp->u64 = DBUS_UINT64_SWAP_LE_BE (vp->u64);
622 _dbus_assert_not_reached("Not a basic type");
633 _dbus_marshal_skip_gvariant_basic (const DBusString *str,
640 case DBUS_TYPE_STRING:
641 case DBUS_TYPE_OBJECT_PATH:
642 case DBUS_TYPE_SIGNATURE:
643 /* FIXME - this will require redesign... size should come from upper container */
644 *pos += strlen (_dbus_string_get_const_data (str) + *pos) + 1; /* length plus nul */
646 case DBUS_TYPE_BOOLEAN:
650 _dbus_marshal_skip_basic (str, type, byte_order, pos);
656 _dbus_header_load_gvariant (DBusHeader *header,
657 DBusTypeReader *reader,
658 DBusValidity *validity)
660 size_t fields_offsets[DBUS_HEADER_FIELD_LAST];
661 size_t n_fields_offsets = 0;
662 size_t offset_size = 0;
663 const char *array_buffer = get_header_const_array (header);
665 get_offsets( array_buffer,
666 get_header_array_size (header),
667 fields_offsets, &n_fields_offsets, &offset_size );
669 _dbus_header_fill_cache (header, fields_offsets, n_fields_offsets);
674 _dbus_gvariant_raw_get_lengths (const DBusString *str,
675 dbus_uint32_t *fields_array_len_unsigned,
676 dbus_uint32_t *body_len_unsigned,
677 DBusValidity *validity)
679 size_t message_len = _dbus_string_get_length (str);
680 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 0);
681 const char *message_ptr = _dbus_string_get_const_data (str);
682 /* so, the offset of end of fields is written at offset str->len - body_offsets_size */
683 size_t end_of_fields = bus_gvariant_read_word_le (message_ptr + message_len - body_offsets_size,
685 *fields_array_len_unsigned = end_of_fields - FIRST_GVARIANT_FIELD_OFFSET;
687 *body_len_unsigned = message_len - _DBUS_ALIGN_VALUE (end_of_fields, 8);
692 _dbus_validate_gvariant_body_with_reason (const DBusString *expected_signature,
693 int expected_signature_start,
695 int *bytes_remaining,
696 const DBusString *value_str,
702 *bytes_remaining = 0;
707 _dbus_message_gvariant_get_signature (DBusMessage *message,
708 const DBusString **type_str_p,
712 size_t body_len = _dbus_string_get_length (&message->body);
713 size_t message_len = _dbus_string_get_length (&message->header.data) + body_len;
714 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 0);
715 const char *body_ptr = _dbus_string_get_const_data (&message->body);
716 const char *sig_end_ptr = body_ptr + body_len - body_offsets_size;
717 const char *sig_ptr = sig_end_ptr - 1;
719 while (sig_ptr >= body_ptr && (*sig_ptr) != 0)
724 if (sig_ptr < body_ptr)
727 if (type_str_p != NULL)
728 *type_str_p = &message->body;
729 *type_pos_p = sig_ptr - body_ptr + 1;
730 *type_str_len = sig_end_ptr - sig_ptr - 1;
736 _dbus_message_append_body_offset (DBusMessage *message)
738 size_t body_len = _dbus_string_get_length (&message->body);
739 size_t end_of_fields_offset = _dbus_string_get_length (&message->header.data) - message->header.padding;
740 size_t message_len = _dbus_string_get_length (&message->header.data) + body_len;
741 size_t body_offsets_size = bus_gvariant_determine_word_size (message_len, 1);
743 return append_sized_value (&message->body, end_of_fields_offset, body_offsets_size);
747 _dbus_message_gvariant_add_signature (DBusMessage *message,
748 const DBusString *type_str)
750 dbus_bool_t res = _dbus_string_append_byte (&message->body, 0);
751 res = res && _dbus_string_append_byte (&message->body, '(');
752 res = res && marshal_gvariant_string (&message->body, _dbus_string_get_length (&message->body),
753 _dbus_string_get_const_data (type_str), NULL, FALSE);
754 res = res && _dbus_string_append_byte (&message->body, ')');
759 _dbus_message_gvariant_remove_body_offset (DBusMessage *message)
761 size_t offset_size = bus_gvariant_determine_word_size (_dbus_string_get_length (&message->header.data) +
762 _dbus_string_get_length (&message->body),
764 _dbus_string_shorten (&message->body, offset_size);
769 _dbus_message_finalize_gvariant (DBusMessage *message, dbus_bool_t remove_signature_from_header)
772 const DBusString *type_str;
774 dbus_bool_t fieldSignaturePresent;
775 dbus_bool_t res = TRUE;
777 _dbus_assert (!message->locked);
779 if (message->header.protocol_version != DBUS_PROTOCOL_VERSION_GVARIANT)
782 fieldSignaturePresent = _dbus_header_get_field_raw (&message->header,
783 DBUS_HEADER_FIELD_SIGNATURE,
786 if (fieldSignaturePresent)
788 /* if there is signature field, then we need to move this signature to body,
789 * and delete the field
791 const char *sig_ptr = _dbus_string_get_const_data (type_str) + type_pos;
792 _dbus_string_init_const (&str, sig_ptr);
796 /* If there is no signature field, then the body is empty.
797 * However, we need to add signature anyway, because body is a variant.
799 _dbus_string_init_const (&str, "");
802 /* Let's set the body also */
803 _dbus_string_set_length (&message->body, 0);
804 _dbus_string_append_byte (&message->body, 0);
807 res = res && _dbus_message_gvariant_add_signature (message, &str);
809 if (res && fieldSignaturePresent && remove_signature_from_header)
810 res = res && _dbus_header_gvariant_delete_field (&message->header, DBUS_HEADER_FIELD_SIGNATURE);
812 res = res && _dbus_message_append_body_offset (message);
817 /* returns length of the body inside the outermost variant
818 * that is, without offset and signature from the end of messages
821 _dbus_message_gvariant_get_body_length (DBusMessage *message)
823 size_t body_len = _dbus_string_get_length (&message->body);
824 size_t message_len = body_len + _dbus_string_get_length (&message->header.data);
825 body_len -= bus_gvariant_determine_word_size (message_len , 0);
827 while (body_len > 0 && _dbus_string_get_byte (&message->body, body_len) != 0)
834 get_max (int a, int b)
836 return (a>b) ? a : b;
840 update_size (int current_size, int size_of_element, int *alignment, int new_alignment)
842 *alignment = get_max (*alignment, new_alignment);
843 current_size = _DBUS_ALIGN_VALUE (current_size, *alignment);
844 return current_size + size_of_element;
848 _dbus_reader_get_signature_fixed_size (const DBusString *signature, int *pos, int *alignment)
852 int current_alignment = 1;
853 dbus_bool_t variable = FALSE;
855 char c = _dbus_string_get_byte (signature, *pos);
856 if (c == DBUS_STRUCT_BEGIN_CHAR || c == DBUS_DICT_ENTRY_BEGIN_CHAR)
863 switch (_dbus_string_get_byte (signature, *pos))
866 case DBUS_TYPE_BOOLEAN:
869 case DBUS_TYPE_INT16:
870 case DBUS_TYPE_UINT16:
871 res = update_size (res, 2, ¤t_alignment, 2);
873 case DBUS_TYPE_INT32:
874 case DBUS_TYPE_UINT32:
875 case DBUS_TYPE_UNIX_FD:
876 res = update_size (res, 4, ¤t_alignment, 4);
878 case DBUS_TYPE_INT64:
879 case DBUS_TYPE_UINT64:
880 case DBUS_TYPE_DOUBLE:
881 res = update_size (res, 8, ¤t_alignment, 8);
883 case DBUS_STRUCT_END_CHAR:
884 case DBUS_DICT_ENTRY_END_CHAR:
887 case DBUS_STRUCT_BEGIN_CHAR:
888 case DBUS_DICT_ENTRY_BEGIN_CHAR:
890 int alignment_recursive;
891 int res_recursive = _dbus_reader_get_signature_fixed_size (signature, pos, &alignment_recursive);
892 if (res_recursive == 0)
893 variable = TRUE; /* variable size detected */
895 /* we need to update at least alignment */
896 res = update_size (res, res_recursive, ¤t_alignment, alignment_recursive);
899 case DBUS_TYPE_VARIANT:
900 current_alignment = 8;
903 case DBUS_TYPE_ARRAY:
905 int alignment_recursive;
906 int recursive_pos = *pos + 1;
907 int res_recursive = _dbus_reader_get_signature_fixed_size (signature, &recursive_pos, &alignment_recursive);
909 variable = TRUE; /* variable size detected */
911 /* we need to update alignment */
912 res = update_size (res, res_recursive, ¤t_alignment, alignment_recursive);
914 /* and update position */
915 *pos = recursive_pos - 1;
919 variable = TRUE; /* variable size detected */
924 /* we want to point it to the last character, to allow upper instance to skip it */
927 if (alignment != NULL)
928 *alignment = current_alignment;
930 return variable ? 0 : res;
934 _dbus_reader_get_type_fixed_size (DBusTypeReader *reader, int *alignment)
936 int pos = reader->type_pos;
937 return _dbus_reader_get_signature_fixed_size (reader->type_str, &pos, alignment);
941 _dbus_type_gvariant_get_fixed_size (const DBusString *type_str, int type_pos, int *alignment)
943 return _dbus_reader_get_signature_fixed_size (type_str, &type_pos, alignment);
947 get_current_type_types_only (const DBusTypeReader *reader)
950 if (reader->finished)
951 t = DBUS_TYPE_INVALID;
953 t = _dbus_first_type_in_signature (reader->type_str,
959 /* This is for structs and dict entries.
960 * Counts variable elements inside a container.
961 * This is equal to number of offsets embedded into the container.
964 _dbus_reader_count_offsets (const DBusTypeReader *reader)
968 dbus_bool_t prev_is_variable = FALSE;
972 /* if signature is not empty, it must be after initial parenthesis */
973 /* empty signature has length 1 - only nul byte */
974 _dbus_assert (reader->type_pos > 0);
976 _dbus_type_reader_init_types_only (&r,
980 r.klass = reader->klass;
982 /* Check what container we're in */
983 switch (_dbus_string_get_byte (r.type_str, r.type_pos-1))
985 case DBUS_STRUCT_BEGIN_CHAR:
986 ending_char = DBUS_STRUCT_END_CHAR;
988 case DBUS_DICT_ENTRY_BEGIN_CHAR:
989 ending_char = DBUS_DICT_ENTRY_END_CHAR;
992 _dbus_assert_not_reached ("function must be called inside structs or dict entries");
995 r.finished = (_dbus_string_get_byte (r.type_str, r.type_pos) == ending_char);
997 while ((current_type = get_current_type_types_only (&r)) != DBUS_TYPE_INVALID)
999 int size = _dbus_reader_get_type_fixed_size (&r, NULL);
1000 if (prev_is_variable)
1002 prev_is_variable = (size == 0);
1003 _dbus_type_signature_next (_dbus_string_get_const_data(r.type_str), &r.type_pos);
1004 r.finished = (_dbus_string_get_byte (r.type_str, r.type_pos) == ending_char);
1010 _dbus_reader_get_offset_of_end_of_variable (DBusTypeReader *reader)
1012 if (reader->is_variant)
1014 /* variant has its end set to the separating 0 */
1015 return reader->value_end;
1019 const char *buffer = _dbus_string_get_const_data (reader->value_str) + reader->value_start;
1020 size_t container_size = reader->value_end - reader->value_start;
1021 size_t offset_size = bus_gvariant_determine_word_size (container_size, 0);
1022 int index_from_back = reader->offsets_from_back ?
1023 reader->variable_index :
1024 reader->n_offsets - 1 - reader->variable_index;
1026 if (0 < container_size && 0 <= index_from_back)
1028 size_t required_offset_position = container_size - (index_from_back+1)*offset_size;
1029 if (index_from_back < reader->n_offsets)
1030 return reader->value_start +
1031 bus_gvariant_read_word_le (buffer + required_offset_position,
1033 else if (reader->offsets_from_back)
1034 return reader->value_start +
1035 container_size - (reader->n_offsets * offset_size); /* this is end of internal container */
1039 return reader->value_start;
1043 _dbus_reader_count_array_elems (const DBusTypeReader *reader)
1045 const char *buffer = _dbus_string_get_const_data (reader->value_str) + reader->value_start;
1046 size_t container_size = reader->value_end - reader->value_start;
1047 size_t offset_size = bus_gvariant_determine_word_size (container_size, 0);
1048 size_t last_offset = bus_gvariant_read_word_le (buffer + container_size - offset_size, offset_size);
1049 return (container_size - last_offset) / offset_size;
1053 write_offset (DBusString *offsets,
1059 dbus_bool_t res = _dbus_string_init_preallocated (&str, offset_size);
1060 res = res && append_sized_value (&str, offset, offset_size);
1061 res = res && _dbus_string_copy_len (&str, 0, offset_size, offsets, insert_at);
1062 _dbus_string_free (&str);
1067 prepend_offset (DBusString *offsets,
1071 return write_offset (offsets, offset, offset_size, 0);
1075 append_offset (DBusString *offsets,
1079 return write_offset (offsets, offset, offset_size, _dbus_string_get_length(offsets));
1083 convert_offsets (DBusString *offsets,
1084 size_t old_offsets_size,
1085 size_t new_offsets_size)
1087 char *old_offsets = NULL;
1088 size_t n_offsets = _dbus_string_get_length (offsets) / old_offsets_size;
1089 dbus_bool_t result = _dbus_string_steal_data (offsets, &old_offsets);
1092 for (i = 0; i < n_offsets && result; i++)
1094 size_t offset = bus_gvariant_read_word_le (old_offsets + i*old_offsets_size, old_offsets_size);
1095 result = result && append_sized_value (offsets, offset, new_offsets_size);
1098 dbus_free (old_offsets);
1104 get_offsets_count (DBusString *offsets, size_t offsets_size)
1106 return _dbus_string_get_length (offsets) / offsets_size;
1110 check_offsets_for_adding (DBusTypeWriter *writer)
1112 size_t container_size = writer->value_pos - writer->value_start;
1113 size_t n_offsets = get_offsets_count (writer->offsets,
1114 writer->offsets_size);
1115 size_t offsets_size = bus_gvariant_determine_word_size (container_size, n_offsets + 1);
1116 if (offsets_size != writer->offsets_size)
1118 if (!convert_offsets (writer->offsets, writer->offsets_size, offsets_size))
1120 writer->offsets_size = offsets_size;
1126 convert_offsets_in_body (DBusTypeWriter *writer,
1127 size_t new_offsets_size)
1132 dbus_bool_t result = _dbus_string_init (&offsets);
1135 result = result && _dbus_string_move (writer->value_str, writer->value_pos, &offsets, 0);
1136 n_offsets = _dbus_string_get_length (&offsets) / writer->offsets_size;
1137 old_offsets = _dbus_string_get_data (&offsets);
1139 for (i = 0; i < n_offsets && result; i++)
1141 size_t offset = bus_gvariant_read_word_le (old_offsets + i*writer->offsets_size, writer->offsets_size);
1142 result = result && append_sized_value (writer->value_str, offset, new_offsets_size);
1145 _dbus_string_free (&offsets);
1150 check_offsets_in_body_for_adding (DBusTypeWriter *writer)
1152 size_t container_size = writer->value_pos - writer->value_start;
1153 size_t n_offsets = (_dbus_string_get_length (writer->value_str) - writer->value_pos) / writer->offsets_size;
1154 size_t offsets_size = bus_gvariant_determine_word_size (container_size, n_offsets + 1);
1155 if (offsets_size != writer->offsets_size)
1157 if (!convert_offsets_in_body (writer, offsets_size))
1159 writer->offsets_size = offsets_size;
1165 _dbus_writer_gvariant_add_offset_with_variability (DBusTypeWriter *writer,
1168 writer->is_fixed = writer->is_fixed && fixed;
1170 if (writer->body_container)
1172 if (*writer->u.root.last_offset != 0)
1174 check_offsets_in_body_for_adding (writer);
1176 write_offset (writer->value_str,
1177 *writer->u.root.last_offset,
1178 writer->offsets_size,
1182 *writer->u.root.last_offset = writer->value_pos - writer->value_start;
1184 *writer->u.root.last_offset = 0;
1186 else if (DBUS_TYPE_STRUCT == writer->container_type ||
1187 DBUS_TYPE_DICT_ENTRY == writer->container_type)
1189 if (writer->u.struct_or_dict.last_offset != 0)
1191 check_offsets_for_adding (writer);
1193 prepend_offset (writer->offsets,
1194 writer->u.struct_or_dict.last_offset,
1195 writer->offsets_size);
1198 writer->u.struct_or_dict.last_offset = writer->value_pos - writer->value_start;
1200 writer->u.struct_or_dict.last_offset = 0;
1202 else if (DBUS_TYPE_ARRAY == writer->container_type)
1204 if (writer->offsets_size > 0)
1206 check_offsets_for_adding (writer);
1208 if (!append_offset (writer->offsets,
1209 writer->value_pos - writer->value_start,
1210 writer->offsets_size))
1218 _dbus_writer_gvariant_add_offset (DBusTypeWriter *writer,
1221 return _dbus_writer_gvariant_add_offset_with_variability (writer, dbus_type_is_fixed (type));
1224 /* this function gets only known alignments - other are 1 */
1226 get_alignment (int type)
1230 case DBUS_TYPE_INT16:
1231 case DBUS_TYPE_UINT16:
1233 case DBUS_TYPE_INT32:
1234 case DBUS_TYPE_UINT32:
1235 case DBUS_TYPE_UNIX_FD:
1237 case DBUS_TYPE_INT64:
1238 case DBUS_TYPE_UINT64:
1239 case DBUS_TYPE_DOUBLE:
1240 case DBUS_TYPE_VARIANT:
1249 fix_struct_alignment_value (DBusTypeWriter *writer, int alignment)
1251 dbus_bool_t result = TRUE;
1252 int old_alignment = writer->alignment;
1253 if (old_alignment < alignment)
1255 int diff = _DBUS_ALIGN_VALUE (writer->value_start, alignment) - writer->value_start;
1256 result = _dbus_string_insert_bytes (writer->value_str, writer->value_start, diff, 0);
1257 writer->value_start += diff;
1258 writer->value_pos += diff;
1259 writer->alignment = alignment;
1265 fix_struct_alignment (DBusTypeWriter *writer, int type)
1267 return fix_struct_alignment_value (writer, get_alignment (type));
1271 update_root_last_pos (DBusTypeWriter *writer)
1273 if (writer->body_container)
1274 *writer->u.root.last_pos = writer->value_pos;
1278 _dbus_type_writer_gvariant_write_basic_no_typecode (DBusTypeWriter *writer,
1282 dbus_bool_t result = TRUE;
1284 if (writer->container_type == DBUS_TYPE_STRUCT || writer->container_type == DBUS_TYPE_DICT_ENTRY)
1285 result = fix_struct_alignment (writer, type);
1287 result = result && _dbus_marshal_write_gvariant_basic (writer->value_str,
1292 &writer->value_pos);
1294 update_root_last_pos (writer);
1296 result = result && _dbus_writer_gvariant_add_offset (writer, type);
1301 write_offsets (DBusString *dest, size_t insert_at, DBusString *offsets)
1303 return _dbus_string_copy (offsets, 0, dest, insert_at);
1307 _dbus_writer_unrecurse_gvariant_write (DBusTypeWriter *writer,
1308 DBusTypeWriter *sub)
1310 dbus_bool_t result = TRUE;
1312 if (writer->alignment < sub->alignment)
1313 writer->alignment = sub->alignment;
1315 switch (sub->container_type) {
1316 case DBUS_TYPE_STRUCT:
1317 case DBUS_TYPE_DICT_ENTRY:
1322 if (NULL != sub->offsets)
1324 write_offsets (sub->value_str, sub->value_pos, sub->offsets);
1326 _dbus_string_free (sub->offsets);
1327 dbus_free (sub->offsets);
1330 diff = _DBUS_ALIGN_VALUE (writer->value_pos, sub->alignment) - writer->value_pos;
1332 result = _dbus_string_insert_bytes (writer->value_str, writer->value_pos, diff, 0);
1333 writer->value_pos += diff;
1334 sub_len = _dbus_string_get_length (sub->value_str);
1335 result = result && _dbus_string_copy_len (sub->value_str, 0,
1339 writer->value_pos += sub_len;
1341 _dbus_string_free (sub->value_str);
1342 dbus_free (sub->value_str);
1346 case DBUS_TYPE_VARIANT:
1350 /* write separating nul byte */
1351 result = _dbus_string_insert_byte (sub->value_str, sub->value_pos, 0);
1352 sub->value_pos += 1;
1354 /* write signature */
1355 sub_type_len = _dbus_string_get_length (sub->type_str);
1356 result = result && _dbus_string_copy_len (sub->type_str, 0,
1360 sub->value_pos += sub_type_len;
1362 /* free type string allocated in writer_recurse_variant() */
1363 _dbus_string_free (sub->type_str);
1364 dbus_free (sub->type_str);
1366 /* update parent's string pointer */
1367 writer->value_pos = sub->value_pos;
1371 case DBUS_TYPE_ARRAY:
1372 writer->value_pos = sub->value_pos;
1373 if (NULL != sub->offsets)
1375 write_offsets (sub->value_str, sub->value_pos, sub->offsets);
1377 writer->value_pos += _dbus_string_get_length (sub->offsets);
1379 _dbus_string_free (sub->offsets);
1380 dbus_free (sub->offsets);
1385 _dbus_assert_not_reached("Invalid container type");
1388 update_root_last_pos (writer);
1390 /* well, we don't know where in the type string beginning of current container is */
1391 result = result && _dbus_writer_gvariant_add_offset_with_variability (writer, sub->is_fixed);
1397 _dbus_type_reader_gvariant_init (DBusTypeReader *reader,
1398 DBusMessage *message)
1400 reader->gvariant = TRUE;
1401 /* GVariant wraps contents into struct */
1402 if (_dbus_string_get_byte (reader->type_str, reader->type_pos) == DBUS_STRUCT_BEGIN_CHAR)
1405 if (_dbus_string_get_byte (reader->type_str, reader->type_pos) == DBUS_STRUCT_END_CHAR)
1406 reader->finished = TRUE;
1409 reader->value_end = _dbus_message_gvariant_get_body_length (message);
1410 reader->n_offsets = _dbus_reader_count_offsets (reader);