/* < private >
* g_variant_alloc:
- * @type: the type of the new instance
+ * @type_info: (transfer full) the type info of the new instance
* @serialised: if the instance will be in serialised form
* @trusted: if the instance will be trusted
*
* Returns: a new #GVariant with a floating reference
*/
static GVariant *
-g_variant_alloc (const GVariantType *type,
- gboolean serialised,
- gboolean trusted)
+g_variant_alloc (GVariantTypeInfo *type_info,
+ gboolean serialised,
+ gboolean trusted)
{
GVariant *value;
value = g_slice_new (GVariant);
- value->type_info = g_variant_type_info_get (type);
+ value->type_info = type_info;
value->state = (serialised ? STATE_SERIALISED : 0) |
(trusted ? STATE_TRUSTED : 0) |
STATE_FLOATING;
/* < internal >
* g_variant_new_from_children:
- * @type: a #GVariantType
+ * @type_info: (transfer full) a #GVariantTypeInfo
* @children: an array of #GVariant pointers. Consumed.
* @n_children: the length of @children
* @trusted: %TRUE if every child in @children in trusted
* Returns: a new #GVariant with a floating reference
*/
GVariant *
-g_variant_new_from_children (const GVariantType *type,
- GVariant **children,
- gsize n_children,
- gboolean trusted)
+g_variant_new_from_children (GVariantTypeInfo *type_info,
+ GVariant **children,
+ gsize n_children,
+ gboolean trusted)
{
GVariant *value;
- value = g_variant_alloc (type, FALSE, trusted);
+ value = g_variant_alloc (type_info, FALSE, trusted);
value->contents.tree.children = children;
value->contents.tree.n_children = n_children;
value->size = g_variant_serialiser_needed_size (value->type_info, g_variant_fill_gvs,
/* < internal >
* g_variant_new_serialised:
- * @type: a #GVariantType
- * @bytes: the #GBytes holding @data
+ * @type_info: (transfer full): a #GVariantTypeInfo
+ * @bytes: (transfer full): the #GBytes holding @data
* @data: a pointer to the serialised data
* @size: the size of @data, in bytes
* @trusted: %TRUE if @data is trusted
* Returns: a new #GVariant with a floating reference
*/
GVariant *
-g_variant_new_serialised (const GVariantType *type,
- GBytes *bytes,
- gconstpointer data,
- gsize size,
- gboolean trusted)
+g_variant_new_serialised (GVariantTypeInfo *type_info,
+ GBytes *bytes,
+ gconstpointer data,
+ gsize size,
+ gboolean trusted)
{
GVariant *value;
gsize fixed_size;
- value = g_variant_alloc (type, TRUE, trusted);
+ value = g_variant_alloc (type_info, TRUE, trusted);
value->contents.serialised.bytes = bytes;
value->contents.serialised.data = data;
value->size = size;
return value->contents.serialised.data;
}
+static GVariant *
+g_variant_vector_deserialise (GVariantTypeInfo *type_info,
+ GVariantVector *first_vector,
+ GVariantVector *last_vector,
+ gsize size,
+ gboolean trusted,
+ GArray *unpacked_children)
+{
+ g_assert (size > 0);
+
+ if (first_vector < last_vector)
+ {
+ GVariantVector *vector = first_vector;
+ const guchar *end_pointer;
+ GVariant **children;
+ guint save_point;
+ guint n_children;
+ gboolean failed;
+ guint i;
+
+ end_pointer = last_vector->data.pointer + last_vector->size;
+ save_point = unpacked_children->len;
+
+ if (!g_variant_serialiser_unpack_all (type_info, end_pointer, last_vector->size, size, unpacked_children))
+ {
+ for (i = save_point; i < unpacked_children->len; i++)
+ g_variant_type_info_unref (g_array_index (unpacked_children, GVariantUnpacked, i).type_info);
+ g_array_set_size (unpacked_children, save_point);
+
+ g_variant_type_info_unref (type_info);
+
+ return NULL;
+ }
+
+ n_children = unpacked_children->len - save_point;
+ children = g_new (GVariant *, n_children);
+ failed = FALSE;
+
+ for (i = 0; i < n_children; i++)
+ {
+ GVariantUnpacked *unpacked = &g_array_index (unpacked_children, GVariantUnpacked, save_point + i);
+ const guchar *resume_at_data;
+ gsize resume_at_size;
+ GVariantVector *fv;
+
+ /* Skip the alignment.
+ *
+ * We can destroy vectors because we won't be going back.
+ *
+ * We do a >= compare because we want to go to the next vector
+ * if it is the start of our child.
+ */
+ while (unpacked->skip >= vector->size)
+ {
+ unpacked->skip -= vector->size;
+ vector++;
+ }
+ g_assert (vector <= last_vector);
+
+ fv = vector;
+ fv->data.pointer += unpacked->skip;
+ fv->size -= unpacked->skip;
+
+ if (unpacked->size == 0)
+ {
+ children[i] = g_variant_new_serialised (unpacked->type_info, g_bytes_new (NULL, 0), NULL, 0, trusted);
+ g_variant_ref_sink (children[i]);
+ continue;
+ }
+
+ /* Now skip to the end, according to 'size'.
+ *
+ * We cannot destroy everything here because we will probably
+ * end up reusing the last one.
+ *
+ * We do a > compare because we want to stay on this vector if
+ * it is the end of our child.
+ */
+ size = unpacked->size;
+ while (unpacked->size > vector->size)
+ {
+ unpacked->size -= vector->size;
+ vector++;
+ }
+ g_assert (vector <= last_vector);
+
+ /* We have to modify the vectors for the benefit of the
+ * recursive step. We also have to remember where we left
+ * off, keeping in mind that the recursive step may itself
+ * modify the vectors.
+ */
+ resume_at_data = vector->data.pointer + unpacked->size;
+ resume_at_size = vector->size - unpacked->size;
+ vector->size = unpacked->size;
+
+ children[i] = g_variant_vector_deserialise (unpacked->type_info, fv, vector,
+ size, trusted, unpacked_children);
+
+ vector->data.pointer = resume_at_data;
+ vector->size = resume_at_size;
+
+ if (children[i])
+ g_variant_ref_sink (children[i]);
+ else
+ failed = TRUE;
+ }
+
+ /* We consumed all the type infos */
+ g_array_set_size (unpacked_children, save_point);
+
+ if G_UNLIKELY (failed)
+ {
+ for (i = 0; i < n_children; i++)
+ if (children[i])
+ g_variant_unref (children[i]);
+
+ g_variant_type_info_unref (type_info);
+ g_free (children);
+
+ return NULL;
+ }
+
+ return g_variant_new_from_children (type_info, children, n_children, trusted);
+ }
+ else
+ {
+ g_assert (first_vector == last_vector);
+ g_assert (size == first_vector->size);
+
+ return g_variant_new_serialised (type_info, g_bytes_ref (first_vector->gbytes),
+ first_vector->data.pointer, size, trusted);
+ }
+}
+
+GVariant *
+g_variant_from_vectors (const GVariantType *type,
+ GVariantVector *vectors,
+ gsize n_vectors,
+ gsize size,
+ gboolean trusted)
+{
+ GVariant *result;
+ GArray *tmp;
+
+ g_return_val_if_fail (vectors != NULL || n_vectors == 0, NULL);
+
+ if (size == 0)
+ return g_variant_new_serialised (g_variant_type_info_get (type), g_bytes_new (NULL, 0), NULL, 0, trusted);
+
+ tmp = g_array_new (FALSE, FALSE, sizeof (GVariantUnpacked));
+ result = g_variant_vector_deserialise (g_variant_type_info_get (type),
+ vectors, vectors + n_vectors - 1, size, trusted, tmp);
+ if (result)
+ g_variant_ref_sink (result);
+ g_array_free (tmp, TRUE);
+
+ return result;
+}
+
/* -- public -- */
/**
s_child = g_variant_serialised_get_child (serialised, index_);
/* create a new serialised instance out of it */
- child = g_slice_new (GVariant);
- child->type_info = s_child.type_info;
- child->state = (value->state & STATE_TRUSTED) |
- STATE_SERIALISED;
- child->size = s_child.size;
- child->ref_count = 1;
- child->contents.serialised.bytes =
- g_bytes_ref (value->contents.serialised.bytes);
- child->contents.serialised.data = s_child.data;
+ child = g_variant_new_serialised (s_child.type_info,
+ g_bytes_ref (value->contents.serialised.bytes),
+ s_child.data, s_child.size,
+ value->state & STATE_TRUSTED);
+ child->state &= ~STATE_FLOATING;
}
return child;