diff options
author | Alexander Larsson <alexl@redhat.com> | 2018-09-19 14:15:01 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2018-09-19 14:15:01 +0200 |
commit | 05f0c89ac4d95ecba5f43bc1712a47b3e9288298 (patch) | |
tree | 472f74a875b2e3c181ae8c23cb10898427029e8c | |
parent | a83c8705d1c940ee6110c31940b66a3579187253 (diff) | |
download | glib-05f0c89ac4d95ecba5f43bc1712a47b3e9288298.tar.gz |
gmarkup: Use gvariant in the gmarkup binary formatwip/alexl/gmarkup-record-gvariant
-rw-r--r-- | glib/gmarkup.c | 305 |
1 files changed, 122 insertions, 183 deletions
diff --git a/glib/gmarkup.c b/glib/gmarkup.c index f7a9536ae..5b51425d2 100644 --- a/glib/gmarkup.c +++ b/glib/gmarkup.c @@ -2920,8 +2920,7 @@ struct RecordDataTree { typedef struct { char *string; - int count; - int offset; + int index; } RecordDataString; @@ -2972,13 +2971,11 @@ record_data_string_lookup (GHashTable *strings, const char *str, gssize len) if (s) { g_free (copy); - s->count++; return s->string; } s = g_slice_new (RecordDataString); s->string = copy ? copy : g_strdup (str); - s->count = 1; g_hash_table_insert (strings, s->string, s); return s->string; @@ -3065,116 +3062,74 @@ static const GMarkupParser record_parser = }; -static gint -compare_string (gconstpointer _a, - gconstpointer _b) -{ - const RecordDataString *a = _a; - const RecordDataString *b = _b; - - return b->count - a->count; -} - -static void -marshal_uint32 (GString *str, - guint32 v) -{ - /* - We encode in a variable length format similar to - utf8: - - v size byte 1 byte 2 byte 3 byte 4 byte 5 - 7 bit: 0xxxxxxx - 14 bit: 10xxxxxx xxxxxxxx - 21 bit: 110xxxxx xxxxxxxx xxxxxxxx - 28 bit: 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx - 32 bit: 11110000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxx - */ - - if (v < 128) - { - g_string_append_c (str, (guchar)v); - } - else if (v < (1<<14)) - { - g_string_append_c (str, (guchar)(v >> 8) | 0x80); - g_string_append_c (str, (guchar)(v & 0xff)); - } - else if (v < (1<<21)) - { - g_string_append_c (str, (guchar)(v >> 16) | 0xc0); - g_string_append_c (str, (guchar)((v >> 8) & 0xff)); - g_string_append_c (str, (guchar)(v & 0xff)); - } - else if (v < (1<<28)) - { - g_string_append_c (str, (guchar)(v >> 24) | 0xe0); - g_string_append_c (str, (guchar)((v >> 16) & 0xff)); - g_string_append_c (str, (guchar)((v >> 8) & 0xff)); - g_string_append_c (str, (guchar)(v & 0xff)); - } - else - { - g_string_append_c (str, 0xf0); - g_string_append_c (str, (guchar)((v >> 24) & 0xff)); - g_string_append_c (str, (guchar)((v >> 16) & 0xff)); - g_string_append_c (str, (guchar)((v >> 8) & 0xff)); - g_string_append_c (str, (guchar)(v & 0xff)); - } -} - -static void -marshal_string (GString *marshaled, - GHashTable *strings, - const char *string) +static guint16 +get_string_index (GHashTable *strings, + const char *string) { RecordDataString *s; s = g_hash_table_lookup (strings, string); g_assert (s != NULL); - marshal_uint32 (marshaled, s->offset); + return s->index; } static void -marshal_tree (GString *marshaled, +marshal_tree (GVariantBuilder *tree_builder, + GVariantBuilder *args_builder, + gsize *args_builder_count, GHashTable *strings, RecordDataTree *tree) { GList *l; int i; + guint16 args_index; /* Special case the root */ if (tree->parent == NULL) { for (l = g_list_last (tree->children); l != NULL; l = l->prev) - marshal_tree (marshaled, strings, l->data); + marshal_tree (tree_builder, args_builder, args_builder_count, strings, l->data); return; } switch (tree->type) { case RECORD_TYPE_ELEMENT: - marshal_uint32 (marshaled, RECORD_TYPE_ELEMENT); - marshal_string (marshaled, strings, tree->data); - marshal_uint32 (marshaled, g_strv_length ((char **)tree->attributes)); - for (i = 0; tree->attributes[i] != NULL; i++) + if (tree->attributes[0] != NULL) { - marshal_string (marshaled, strings, tree->attributes[i]); - marshal_string (marshaled, strings, tree->values[i]); + args_index = *args_builder_count; + for (i = 0; tree->attributes[i] != NULL; i++) + { + g_variant_builder_add (args_builder, "(qq)", + GUINT16_TO_LE (get_string_index (strings, tree->attributes[i])), + GUINT16_TO_LE (get_string_index (strings, tree->values[i]))); + (*args_builder_count)++; + } + g_variant_builder_add (args_builder,"(qq)", 0, 0); + (*args_builder_count)++; } + else + args_index = 0; + + g_variant_builder_add (tree_builder, "(yqq)", RECORD_TYPE_ELEMENT, + GUINT16_TO_LE (get_string_index (strings, tree->data)), + GUINT16_TO_LE (args_index)); + for (l = g_list_last (tree->children); l != NULL; l = l->prev) - marshal_tree (marshaled, strings, l->data); + marshal_tree (tree_builder, args_builder, args_builder_count, strings, l->data); - marshal_uint32 (marshaled, RECORD_TYPE_END_ELEMENT); + g_variant_builder_add (tree_builder, "(yqq)", RECORD_TYPE_END_ELEMENT, 0, 0); break; case RECORD_TYPE_TEXT: - marshal_uint32 (marshaled, RECORD_TYPE_TEXT); - marshal_string (marshaled, strings, tree->data); + g_variant_builder_add (tree_builder, "(yqq)", RECORD_TYPE_TEXT, + GUINT16_TO_LE (get_string_index (strings, tree->data)), + 0); break; case RECORD_TYPE_PASSTHROUGH: - marshal_uint32 (marshaled, RECORD_TYPE_PASSTHROUGH); - marshal_string (marshaled, strings, tree->data); + g_variant_builder_add (tree_builder, "(yqq)", RECORD_TYPE_PASSTHROUGH, + GUINT16_TO_LE (get_string_index (strings, tree->data)), + 0); break; case RECORD_TYPE_END_ELEMENT: default: @@ -3182,8 +3137,6 @@ marshal_tree (GString *marshaled, } } -static guint32 demarshal_uint32 (const char **tree); - GLIB_AVAILABLE_IN_ALL GBytes * g_markup_parse_context_record (GMarkupParseFlags flags, @@ -3193,9 +3146,14 @@ g_markup_parse_context_record (GMarkupParseFlags flags, { GMarkupParseContext *ctx; RecordData data = { 0 }; + GBytes *result; + GVariant *v; GList *string_table, *l; - GString *marshaled; - int offset; + GVariantBuilder stringtable_builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_STRING_ARRAY); + GVariantBuilder tree_builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE("a(yqq)")); + GVariantBuilder args_builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE("a(qq)")); + gsize args_builder_count = 0; + int index; data.strings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)record_data_string_free); data.root = record_data_tree_new (NULL, RECORD_TYPE_ELEMENT, NULL); @@ -3216,100 +3174,72 @@ g_markup_parse_context_record (GMarkupParseFlags flags, string_table = g_hash_table_get_values (data.strings); - string_table = g_list_sort (string_table, compare_string); - - offset = 0; - for (l = string_table; l != NULL; l = l->next) - { - RecordDataString *s = l->data; - s->offset = offset; - offset += strlen (s->string) + 1; - } - - marshaled = g_string_new (""); - /* Magic marker */ - g_string_append_len (marshaled, "GMU\0", 4); - marshal_uint32 (marshaled, offset); + /* reserve index 0 for end-of-array markers */ + index = 1; + g_variant_builder_add (&stringtable_builder, "s", ""); for (l = string_table; l != NULL; l = l->next) { RecordDataString *s = l->data; - g_string_append_len (marshaled, s->string, strlen (s->string) + 1); + s->index = index++; + g_variant_builder_add (&stringtable_builder, "s", s->string); } - g_list_free (string_table); + /* Reserve 0 as no-args */ + g_variant_builder_add (&args_builder, "(qq)", 0, 0); + args_builder_count++; - marshal_tree (marshaled, data.strings, data.root); + marshal_tree (&tree_builder, &args_builder, &args_builder_count, data.strings, data.root); + v = g_variant_new ("(s@as@a(qq)@a(yqq))", + "GMU", + g_variant_builder_end (&stringtable_builder), + g_variant_builder_end (&args_builder), + g_variant_builder_end (&tree_builder)); + result = g_variant_get_data_as_bytes (v); + g_variant_unref (g_variant_ref_sink (v)); record_data_tree_free (data.root); + g_list_free (string_table); g_hash_table_destroy (data.strings); - return g_string_free_to_bytes (marshaled); -} - -static guint32 -demarshal_uint32 (const char **tree) -{ - const guchar *p = (const guchar *)*tree; - guchar c = *p; - /* see marshal_uint32 for format */ - - if (c < 128) /* 7 bit */ - { - *tree += 1; - return c; - } - else if ((c & 0xc0) == 0x80) /* 14 bit */ - { - *tree += 2; - return (c & 0x3f) << 8 | p[1]; - } - else if ((c & 0xe0) == 0xc0) /* 21 bit */ - { - *tree += 3; - return (c & 0x1f) << 16 | p[1] << 8 | p[2]; - } - else if ((c & 0xf0) == 0xe0) /* 28 bit */ - { - *tree += 4; - return (c & 0xf) << 24 | p[1] << 16 | p[2] << 8 | p[3]; - } - else - { - *tree += 5; - return p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4]; - } + return result; } -static const char * -demarshal_string (const char **tree, const char *strings) -{ - guint32 offset = demarshal_uint32 (tree); +typedef struct { + guint8 type; + guint16 data; + guint16 attributes; +} RecordDataNode; - return strings + offset; -} +typedef struct { + guint16 attr; + guint16 val; +} RecordDataAttr; static gboolean replay_start_element (GMarkupParseContext *context, - const char **tree, - const char *strings, + const char *element_name, + gint attr_index, + const char **strings, + const RecordDataAttr *attrs, GError **error) { - const char *element_name; - guint32 i, n_attrs; + gsize end_index, n_attrs, i; const gchar **attr_names; const gchar **attr_values; GError *tmp_error = NULL; - element_name = demarshal_string (tree, strings); - n_attrs = demarshal_uint32 (tree); + /* Count nr of attrs */ + for (end_index = attr_index; attrs[end_index].attr != 0; end_index++) + ; + n_attrs = end_index - attr_index, attr_names = g_newa (const gchar *, n_attrs + 1); attr_values = g_newa (const gchar *, n_attrs + 1); for (i = 0; i < n_attrs; i++) { - attr_names[i] = demarshal_string (tree, strings); - attr_values[i] = demarshal_string (tree, strings); + attr_names[i] = strings[GUINT16_FROM_LE(attrs[attr_index + i].attr)]; + attr_values[i] = strings[GUINT16_FROM_LE(attrs[attr_index + i].val)]; } attr_names[i] = NULL; attr_values[i] = NULL; @@ -3335,8 +3265,6 @@ replay_start_element (GMarkupParseContext *context, static gboolean replay_end_element (GMarkupParseContext *context, - const char **tree, - const char *strings, GError **error) { GError *tmp_error = NULL; @@ -3369,15 +3297,11 @@ replay_end_element (GMarkupParseContext *context, static gboolean replay_text (GMarkupParseContext *context, - const char **tree, - const char *strings, + const char *text, GError **error) { - const char *text; GError *tmp_error = NULL; - text = demarshal_string (tree, strings); - if (context->parser->text) (*context->parser->text) (context, text, @@ -3396,15 +3320,11 @@ replay_text (GMarkupParseContext *context, static gboolean replay_passthrough (GMarkupParseContext *context, - const char **tree, - const char *strings, + const char *text, GError **error) { - const char *text; GError *tmp_error = NULL; - text = demarshal_string (tree, strings); - if (context->parser->passthrough) (*context->parser->passthrough) (context, text, @@ -3427,14 +3347,14 @@ g_markup_parse_context_replay (GMarkupParseContext *context, gsize data_size, GError **error) { - const char *data_end; - guint32 len, type; - const char *strings; - const char *tree; + GVariant *v, *stringsv, *nodesv, *attrsv; + const char **strings; + const RecordDataAttr *attrs; + const RecordDataNode *nodes; + gsize n_strings, n_attrs, n_nodes, i; - data_end = data + data_size; - - if (!(data[0] == 'G' && + if (data_size < 4 || + !(data[0] == 'G' && data[1] == 'M' && data[2] == 'U' && data[3] == 0)) @@ -3443,40 +3363,59 @@ g_markup_parse_context_replay (GMarkupParseContext *context, _("Invalid gmarkup replay data")); return FALSE; } - data = data + 4; - len = demarshal_uint32 (&data); + v = g_variant_new_from_data (G_VARIANT_TYPE("(sasa(qq)a(yqq))"), + data, data_size, TRUE, NULL, NULL); + g_variant_ref_sink (v); + + stringsv = g_variant_get_child_value (v, 1); + strings = g_variant_get_strv (stringsv, &n_strings); + g_variant_unref (stringsv); - strings = data; - data = data + len; - tree = data; + attrsv = g_variant_get_child_value (v, 2); + attrs = g_variant_get_fixed_array (attrsv, &n_attrs, sizeof (*attrs)); + g_variant_unref (attrsv); - while (tree < data_end) + nodesv = g_variant_get_child_value (v, 3); + nodes = g_variant_get_fixed_array (nodesv, &n_nodes, sizeof (*nodes)); + g_variant_unref (nodesv); + + for (i = 0; i < n_nodes; i++) { + const RecordDataNode *node = &nodes[i]; + const char *node_data; gboolean res; - type = demarshal_uint32 (&tree); - switch (type) + node_data = strings[GUINT16_FROM_LE(node->data)]; + + switch (node->type) { case RECORD_TYPE_ELEMENT: - res = replay_start_element (context, &tree, strings, error); + res = replay_start_element (context, node_data, GUINT16_FROM_LE(node->attributes), + strings, attrs, error); break; case RECORD_TYPE_END_ELEMENT: - res = replay_end_element (context, &tree, strings, error); + res = replay_end_element (context, error); break; case RECORD_TYPE_TEXT: - res = replay_text (context, &tree, strings, error); + res = replay_text (context, node_data, error); break; case RECORD_TYPE_PASSTHROUGH: - res = replay_passthrough (context, &tree, strings, error); + res = replay_passthrough (context, node_data, error); break; default: g_assert_not_reached (); } if (!res) - return FALSE; + { + g_variant_unref (v); + return FALSE; + } } + + g_variant_unref (v); + return TRUE; } |