[glib] GVariant: improve bytestring support
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] GVariant: improve bytestring support
- Date: Wed, 7 Jul 2010 20:26:37 +0000 (UTC)
commit d9e90c3894739bdfa642e35bdea866c6d0ab7ef2
Author: Ryan Lortie <desrt desrt ca>
Date: Wed Jul 7 10:37:16 2010 -0400
GVariant: improve bytestring support
- add G_VARIANT_TYPE_BYTESTRING, _BYTESTRING_ARRAY, _STRING_ARRAY
- remove g_variant_{new,get}_byte_array functions
- add g_variant_{new,get,dup}_bytestring{,_array} functions
- remove undocumented support for deserialising arrays of objectpaths
or signature strngs using g_variant_get_strv()
- add and document new format strings '^ay', '^&ay', '^aay' and '^a&ay'
- update GApplication to use the new API
- update GSettings binding code to use the new API
- add tests
docs/reference/glib/glib-sections.txt | 9 +-
docs/reference/glib/gvariant-varargs.xml | 184 +++++++++--
docs/reference/glib/tmpl/glib-unused.sgml | 40 +---
gio/gapplication.c | 32 +--
gio/gsettings-mapping.c | 8 +-
gio/tests/gsettings.c | 2 +-
gio/tests/testapp.c | 4 +-
glib/glib.symbols | 8 +-
glib/gvariant-parser.c | 179 ++++++++++-
glib/gvariant.c | 477 +++++++++++++++++++++--------
glib/gvariant.h | 14 +-
glib/gvarianttype.h | 25 ++
glib/tests/gvariant.c | 129 ++++++--
13 files changed, 836 insertions(+), 275 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 8f16358..b0a9c8f 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2842,8 +2842,9 @@ g_variant_is_object_path
g_variant_new_signature
g_variant_is_signature
g_variant_new_variant
-g_variant_new_byte_array
g_variant_new_strv
+g_variant_new_bytestring
+g_variant_new_bytestring_array
<SUBSECTION>
g_variant_get_boolean
@@ -2859,10 +2860,12 @@ g_variant_get_double
g_variant_get_string
g_variant_dup_string
g_variant_get_variant
-g_variant_new_byte_array
-g_variant_get_byte_array
g_variant_get_strv
g_variant_dup_strv
+g_variant_get_bytestring
+g_variant_dup_bytestring
+g_variant_get_bytestring_array
+g_variant_dup_bytestring_array
<SUBSECTION>
g_variant_new_maybe
diff --git a/docs/reference/glib/gvariant-varargs.xml b/docs/reference/glib/gvariant-varargs.xml
index 2eb945f..2d92af0 100644
--- a/docs/reference/glib/gvariant-varargs.xml
+++ b/docs/reference/glib/gvariant-varargs.xml
@@ -46,8 +46,8 @@
<listitem>
<para>
'<literal>&s</literal>' '<literal>&o</literal>', '<literal>&g</literal>', '<literal>^as</literal>',
- '<literal>^ao</literal>', '<literal>^ag</literal>', '<literal>^a&s</literal>', '<literal>^a&o</literal>' or
- '<literal>^a&g</literal>'
+ '<literal>^a&s</literal>', '<literal>^ay</literal>', '<literal>^&ay</literal>', '<literal>^aay</literal>'
+ or '<literal>^a&ay</literal>'.
</para>
</listitem>
<listitem>
@@ -935,39 +935,155 @@ value2 = g_variant_new ("(@(iii)*)", value1, g_variant_new_string ("foo"));
</para>
<para>
- The '<literal>^</literal>' character currently only has one purpose: to convert to and from
- <link linkend='G-TYPE-STRV'><literal>G_TYPE_STRV</literal></link> type arrays of strings. It is always used with
- arrays of strings (or other string types). It has two forms.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- '<literal>^as</literal>' (or <literal>o</literal> or <literal>g</literal>)
- </para>
- </listitem>
- <listitem>
- <para>
- '<literal>^a&s</literal>' (or <literal>o</literal> or <literal>g</literal>)
- </para>
- </listitem>
- </itemizedlist>
- <para>
- When used with <link linkend='g-variant-new'><function>g_variant_new()</function></link> both forms are equivalent.
- A <code>(const <link linkend='gchar'>gchar</link> * const *)</code> is collected. This must be a pointer to the
- array of <link linkend='NULL--CAPS'><literal>NULL</literal></link>-terminated pointers to strings. This array is
- converted to a <link linkend='GVariant'><type>GVariant</type></link> instance. Copies are made, so the original
- array may be freed immediately.
- </para>
- <para>
- When used with <link linkend='g-variant-get'><function>g_variant_get()</function></link> the two forms have
- different meaning. Both return a freshly allocated
- <link linkend='NULL--CAPS'><literal>NULL</literal></link>-terminated array of pointers to strings. In the case of
- '<literal>^as</literal>', the strings are owned by the caller -- it is appropriate to free the array with
- <link linkend='g-strfreev'><function>g_strfreev()</function></link>. In the case of '<literal>^a&s</literal>',
- a shallow copy is made; the strings themselves are embedded in the serialised data and owned by the original
- <link linkend='GVariant'><type>GVariant</type></link> instance -- it is only appropriate to free the outer array
- with <link linkend='g-free'><function>g_free()</function></link>.
+ The '<literal>^</literal>' character currently supports conversion to and from bytestrings or to and from arrays
+ of strings or bytestrings. It has a number of forms.
</para>
+
+ <para>
+ In all forms, when used with <link linkend='g-variant-new'><function>g_variant_new()</function></link> one
+ pointer value is collected from the variable arguments and passed to a function (as given in the table below).
+ The result of that function is used as the value for this position. When used with
+ <link linkend='g-variant-get'><function>g_variant_get()</function></link> one pointer value is produced by using
+ the function (given in the table) and returned by reference.
+ </para>
+
+ <informaltable>
+ <tgroup cols='2'>
+ <colspec colname='col_0'/>
+ <colspec colname='col_1'/>
+ <colspec colname='col_2'/>
+ <tbody>
+
+ <row rowsep='1'>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ <emphasis role='strong'>Conversion</emphasis>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ <emphasis role='strong'>
+ Used with <link linkend='g-variant-new'><function>g_variant_new()</function></link>
+ </emphasis>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ <emphasis role='strong'>
+ Used with <link linkend='g-variant-get'><function>g_variant_get()</function></link>
+ </emphasis>
+ </para>
+ </entry>
+ </row>
+
+ <row rowsep='1'>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ <emphasis role='strong'>
+ <literal>^as</literal>
+ </emphasis>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1' morerows='1'>
+ <para>
+ equivalent to <link linkend='g-variant-new-strv'><function>g_variant_new_strv()</function></link>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ equivalent to <link linkend='g-variant-dup-strv'><function>g_variant_dup_strv()</function></link>
+ </para>
+ </entry>
+ </row>
+
+ <row rowsep='1'>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ <emphasis role='strong'>
+ <literal>^a&s</literal>
+ </emphasis>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ equivalent to <link linkend='g-variant-get-strv'><function>g_variant_get_strv()</function></link>
+ </para>
+ </entry>
+ </row>
+
+ <row rowsep='1'>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ <emphasis role='strong'>
+ <literal>^ay</literal>
+ </emphasis>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1' morerows='1'>
+ <para>
+ equivalent to <link linkend='g-variant-new-bytestring'><function>g_variant_new_bytestring()</function></link>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ equivalent to <link linkend='g-variant-dup-bytestring'><function>g_variant_dup_bytestring()</function></link>
+ </para>
+ </entry>
+ </row>
+
+ <row rowsep='1'>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ <emphasis role='strong'>
+ <literal>^&ay</literal>
+ </emphasis>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ equivalent to <link linkend='g-variant-get-bytestring'><function>g_variant_get_bytestring()</function></link>
+ </para>
+ </entry>
+ </row>
+
+ <row rowsep='1'>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ <emphasis role='strong'>
+ <literal>^aay</literal>
+ </emphasis>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1' morerows='1'>
+ <para>
+ equivalent to <link linkend='g-variant-new-bytestring-array'><function>g_variant_new_bytestring_array()</function></link>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ equivalent to <link linkend='g-variant-dup-bytestring-array'><function>g_variant_dup_bytestring_array()</function></link>
+ </para>
+ </entry>
+ </row>
+
+ <row rowsep='1'>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ <emphasis role='strong'>
+ <literal>^a&ay</literal>
+ </emphasis>
+ </para>
+ </entry>
+ <entry colsep='1' rowsep='1'>
+ <para>
+ equivalent to <link linkend='g-variant-get-bytestring-array'><function>g_variant_get_bytestring_array()</function></link>
+ </para>
+ </entry>
+ </row>
+
+ </tbody>
+ </tgroup>
+ </informaltable>
</refsect2>
</refsect1>
</refentry>
diff --git a/docs/reference/glib/tmpl/glib-unused.sgml b/docs/reference/glib/tmpl/glib-unused.sgml
index 8824266..7469a50 100644
--- a/docs/reference/glib/tmpl/glib-unused.sgml
+++ b/docs/reference/glib/tmpl/glib-unused.sgml
@@ -877,7 +877,7 @@ Turns the argument into a string literal by using the '#' stringizing operator.
@x: text to convert to a literal string.
-<!-- ##### FUNCTION g_variant_dup_bytestring ##### -->
+<!-- ##### FUNCTION g_variant_get_byte_array ##### -->
<para>
</para>
@@ -886,46 +886,12 @@ Turns the argument into a string literal by using the '#' stringizing operator.
@length:
@Returns:
-<!-- ##### FUNCTION g_variant_dup_bytestring_array ##### -->
+<!-- ##### FUNCTION g_variant_new_byte_array ##### -->
<para>
</para>
- value:
- length:
- Returns:
-
-<!-- ##### FUNCTION g_variant_get_bytestring ##### -->
-<para>
-
-</para>
-
- value:
- Returns:
-
-<!-- ##### FUNCTION g_variant_get_bytestring_array ##### -->
-<para>
-
-</para>
-
- value:
- length:
- Returns:
-
-<!-- ##### FUNCTION g_variant_new_bytestring ##### -->
-<para>
-
-</para>
-
- string:
- Returns:
-
-<!-- ##### FUNCTION g_variant_new_bytestring_array ##### -->
-<para>
-
-</para>
-
- strv:
+ array:
@length:
@Returns:
diff --git a/gio/gapplication.c b/gio/gapplication.c
index 2996d1b..2e3a3e5 100644
--- a/gio/gapplication.c
+++ b/gio/gapplication.c
@@ -332,7 +332,7 @@ append_cwd_to_platform_data (GVariant *platform_data)
if (cwd)
g_variant_builder_add (&builder, "{sv}",
"cwd",
- g_variant_new_byte_array (cwd, -1));
+ g_variant_new_bytestring (cwd));
g_free (cwd);
if (platform_data)
@@ -351,27 +351,6 @@ append_cwd_to_platform_data (GVariant *platform_data)
return result;
}
-static GVariant *
-variant_from_argv (int argc,
- char **argv)
-{
- GVariantBuilder builder;
- int i;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay"));
-
- for (i = 1; i < argc; i++)
- {
- guint8 *argv_bytes;
-
- argv_bytes = (guint8*) argv[i];
- g_variant_builder_add_value (&builder,
- g_variant_new_byte_array (argv_bytes, -1));
- }
-
- return g_variant_builder_end (&builder);
-}
-
static gboolean
timeout_handle_actions_changed (gpointer user_data)
{
@@ -468,6 +447,7 @@ g_application_new (const gchar *appid,
int argc,
char **argv)
{
+ const gchar * const *args = (const gchar **) argv;
GObject *app;
GError *error = NULL;
GVariant *argv_variant;
@@ -476,7 +456,7 @@ g_application_new (const gchar *appid,
g_return_val_if_fail (appid != NULL, NULL);
- argv_variant = variant_from_argv (argc, argv);
+ argv_variant = g_variant_new_bytestring_array (args, argc);
app = g_initable_new (G_TYPE_APPLICATION,
NULL,
@@ -514,13 +494,14 @@ g_application_try_new (const gchar *appid,
char **argv,
GError **error)
{
+ const gchar * const *args = (const gchar **) argv;
GVariant *argv_variant;
g_type_init ();
g_return_val_if_fail (appid != NULL, NULL);
- argv_variant = variant_from_argv (argc, argv);
+ argv_variant = g_variant_new_bytestring_array (args, argc);
return G_APPLICATION (g_initable_new (G_TYPE_APPLICATION,
NULL,
@@ -551,13 +532,14 @@ g_application_unregistered_try_new (const gchar *appid,
char **argv,
GError **error)
{
+ const gchar * const *args = (const gchar **) argv;
GVariant *argv_variant;
g_type_init ();
g_return_val_if_fail (appid != NULL, NULL);
- argv_variant = variant_from_argv (argc, argv);
+ argv_variant = g_variant_new_bytestring_array (args, argc);
return G_APPLICATION (g_initable_new (G_TYPE_APPLICATION,
NULL,
diff --git a/gio/gsettings-mapping.c b/gio/gsettings-mapping.c
index d85fae1..f83e238 100644
--- a/gio/gsettings-mapping.c
+++ b/gio/gsettings-mapping.c
@@ -369,8 +369,8 @@ g_settings_set_mapping (const GValue *value,
return NULL;
else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_STRING))
return g_variant_new_string (g_value_get_string (value));
- else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE ("ay")))
- return g_variant_new_byte_array (g_value_get_string (value), -1);
+ else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BYTESTRING))
+ return g_variant_new_bytestring (g_value_get_string (value));
else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_OBJECT_PATH))
return g_variant_new_object_path (g_value_get_string (value));
else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_SIGNATURE))
@@ -528,9 +528,9 @@ g_settings_get_mapping (GValue *value,
return TRUE;
}
}
- else if (g_variant_is_of_type (variant, G_VARIANT_TYPE ("ay")))
+ else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTESTRING))
{
- g_value_set_string (value, g_variant_get_byte_array (variant, NULL));
+ g_value_set_string (value, g_variant_get_bytestring (variant));
return TRUE;
}
diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c
index 06f98bf..f3727e0 100644
--- a/gio/tests/gsettings.c
+++ b/gio/tests/gsettings.c
@@ -1006,7 +1006,7 @@ test_simple_binding (void)
g_object_set (obj, "string", "non-unicode:\315", NULL);
value = g_settings_get_value (settings, "chararray");
- g_assert_cmpstr (g_variant_get_byte_array (value, NULL), ==, "non-unicode:\315");
+ g_assert_cmpstr (g_variant_get_bytestring (value), ==, "non-unicode:\315");
g_variant_unref (value);
g_settings_bind (settings, "double", obj, "double", G_SETTINGS_BIND_DEFAULT);
diff --git a/gio/tests/testapp.c b/gio/tests/testapp.c
index caed830..c583645 100644
--- a/gio/tests/testapp.c
+++ b/gio/tests/testapp.c
@@ -41,11 +41,11 @@ on_app_activated (GApplication *application,
while (g_variant_iter_next (&iter, "{&sv}", &key, &value))
{
const char *activate_cwd;
- gsize *len;
+
if (strcmp (key, "cwd") != 0)
continue;
- activate_cwd = g_variant_get_byte_array (value, &len);
+ activate_cwd = g_variant_get_bytestring (value);
g_assert_cmpstr (cwd, ==, activate_cwd);
g_variant_unref (value);
}
diff --git a/glib/glib.symbols b/glib/glib.symbols
index 41ef82b..648812a 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -1743,8 +1743,9 @@ g_variant_is_object_path
g_variant_new_signature
g_variant_is_signature
g_variant_new_variant
-g_variant_new_byte_array
g_variant_new_strv
+g_variant_new_bytestring
+g_variant_new_bytestring_array
g_variant_get_boolean
g_variant_get_byte
@@ -1759,9 +1760,12 @@ g_variant_get_double
g_variant_get_string
g_variant_dup_string
g_variant_get_variant
-g_variant_get_byte_array
g_variant_get_strv
g_variant_dup_strv
+g_variant_get_bytestring
+g_variant_dup_bytestring
+g_variant_get_bytestring_array
+g_variant_dup_bytestring_array
g_variant_new_maybe
g_variant_new_array
diff --git a/glib/gvariant-parser.c b/glib/gvariant-parser.c
index 93a5dd3..7932d85 100644
--- a/glib/gvariant-parser.c
+++ b/glib/gvariant-parser.c
@@ -163,7 +163,22 @@ token_stream_prepare (TokenStream *stream)
break;
break;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'b':
+ if (stream->stream[1] == '\'' || stream->stream[1] == '"')
+ {
+ for (end = stream->stream + 2; end != stream->end; end++)
+ if (*end == stream->stream[1] || *end == '\0' ||
+ (*end == '\\' && (++end == stream->end || *end == '\0')))
+ break;
+
+ if (end != stream->end && *end)
+ end++;
+ break;
+ }
+
+ else /* â??â??â?? */;
+
+ case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
@@ -173,13 +188,23 @@ token_stream_prepare (TokenStream *stream)
break;
break;
+ case '\'': case '"':
+ for (end = stream->stream + 1; end != stream->end; end++)
+ if (*end == stream->stream[0] || *end == '\0' ||
+ (*end == '\\' && (++end == stream->end || *end == '\0')))
+ break;
+
+ if (end != stream->end && *end)
+ end++;
+ break;
+
case '@': case '%':
/* stop at the first space, comma, colon or unmatched bracket.
* deals nicely with cases like (%i, %i) or {%i: %i}.
*/
for (end = stream->stream + 1;
end != stream->end && *end != ',' &&
- *end != ':' && !g_ascii_isspace (*end);
+ *end != ':' && *end != '>' && !g_ascii_isspace (*end);
end++)
if (*end == '(' || *end == '{')
@@ -190,16 +215,6 @@ token_stream_prepare (TokenStream *stream)
break;
- case '\'': case '"':
- for (end = stream->stream + 1; end != stream->end; end++)
- if (*end == stream->stream[0] || *end == '\0' ||
- (*end == '\\' && (++end == stream->end || *end == '\0')))
- break;
-
- if (end != stream->end && *end)
- end++;
- break;
-
default:
end = stream->stream + 1;
break;
@@ -225,11 +240,23 @@ token_stream_peek (TokenStream *stream,
}
static gboolean
+token_stream_peek2 (TokenStream *stream,
+ gchar first_char,
+ gchar second_char)
+{
+ token_stream_prepare (stream);
+
+ return stream->this[0] == first_char &&
+ stream->this[1] == second_char;
+}
+
+static gboolean
token_stream_is_keyword (TokenStream *stream)
{
token_stream_prepare (stream);
- return g_ascii_isalpha (stream->this[0]);
+ return g_ascii_isalpha (stream->this[0]) &&
+ g_ascii_isalpha (stream->this[1]);
}
static gboolean
@@ -1542,6 +1569,128 @@ string_parse (TokenStream *stream,
typedef struct
{
AST ast;
+ gchar *string;
+} ByteString;
+
+static gchar *
+bytestring_get_pattern (AST *ast,
+ GError **error)
+{
+ return g_strdup ("May");
+}
+
+static GVariant *
+bytestring_get_value (AST *ast,
+ const GVariantType *type,
+ GError **error)
+{
+ ByteString *string = (ByteString *) ast;
+
+ g_assert (g_variant_type_equal (type, G_VARIANT_TYPE_BYTESTRING));
+
+ return g_variant_new_bytestring (string->string);
+}
+
+static void
+bytestring_free (AST *ast)
+{
+ ByteString *string = (ByteString *) ast;
+
+ g_free (string->string);
+ g_slice_free (ByteString, string);
+}
+
+static AST *
+bytestring_parse (TokenStream *stream,
+ va_list *app,
+ GError **error)
+{
+ static const ASTClass bytestring_class = {
+ bytestring_get_pattern,
+ maybe_wrapper, bytestring_get_value,
+ bytestring_free
+ };
+ ByteString *string;
+ SourceRef ref;
+ gchar *token;
+ gsize length;
+ gchar quote;
+ gchar *str;
+ gint i, j;
+
+ token_stream_start_ref (stream, &ref);
+ token = token_stream_get (stream);
+ token_stream_end_ref (stream, &ref);
+ g_assert (token[0] == 'b');
+ length = strlen (token);
+ quote = token[1];
+
+ str = g_malloc (length);
+ g_assert (quote == '"' || quote == '\'');
+ j = 0;
+ i = 2;
+ while (token[i] != quote)
+ switch (token[i])
+ {
+ case '\0':
+ parser_set_error (error, &ref, NULL,
+ "unterminated string constant");
+ g_free (token);
+ return NULL;
+
+ case '\\':
+ switch (token[++i])
+ {
+ case '\0':
+ parser_set_error (error, &ref, NULL,
+ "unterminated string constant");
+ g_free (token);
+ return NULL;
+
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ {
+ /* up to 3 characters */
+ guchar val = token[i++] - '0';
+
+ if ('0' <= token[i] && token[i] < '8')
+ val = (val << 3) | (token[i++] - '0');
+
+ if ('0' <= token[i] && token[i] < '8')
+ val = (val << 3) | (token[i++] - '0');
+
+ str[j++] = val;
+ }
+ continue;
+
+ case 'a': str[j++] = '\a'; i++; continue;
+ case 'b': str[j++] = '\b'; i++; continue;
+ case 'f': str[j++] = '\f'; i++; continue;
+ case 'n': str[j++] = '\n'; i++; continue;
+ case 'r': str[j++] = '\r'; i++; continue;
+ case 't': str[j++] = '\t'; i++; continue;
+ case 'v': str[j++] = '\v'; i++; continue;
+ case '\n': i++; continue;
+ }
+
+ default:
+ str[j++] = token[i++];
+ }
+ str[j++] = '\0';
+ g_free (token);
+
+ string = g_slice_new (ByteString);
+ string->ast.class = &bytestring_class;
+ string->string = str;
+
+ token_stream_next (stream);
+
+ return (AST *) string;
+}
+
+typedef struct
+{
+ AST ast;
gchar *token;
} Number;
@@ -2043,6 +2192,10 @@ parse (TokenStream *stream,
token_stream_peek (stream, '"'))
result = string_parse (stream, app, error);
+ else if (token_stream_peek2 (stream, 'b', '\'') ||
+ token_stream_peek2 (stream, 'b', '"'))
+ result = bytestring_parse (stream, app, error);
+
else
{
token_stream_set_error (stream, error, FALSE, "expected value");
diff --git a/glib/gvariant.c b/glib/gvariant.c
index 2819eda..03c09ff 100644
--- a/glib/gvariant.c
+++ b/glib/gvariant.c
@@ -1165,101 +1165,248 @@ g_variant_dup_string (GVariant *value,
}
/**
- * g_variant_new_byte_array:
- * @array: (array length=length): a pointer to an array of bytes
- * @length: the length of @array, or -1
+ * g_variant_new_strv:
+ * @strv: (array length=length): an array of strings
+ * @length: the length of @strv, or -1
* @returns: a new floating #GVariant instance
*
- * Constructs an array of bytes #GVariant from the given array of bytes.
+ * Constructs an array of strings #GVariant from the given array of
+ * strings.
*
- * If @length is -1 then @array is taken to be a normal C string (in the
- * sense that it is terminated by a nul character). The nul character
- * is included in the array. If length is not -1 then it gives the
- * length of @array which may then contain nul chracters with no special
- * meaning.
+ * If @length is -1 then @strv is %NULL-terminated.
*
- * Since: 2.26
+ * Since: 2.24
**/
GVariant *
-g_variant_new_byte_array (gconstpointer array,
- gssize length)
+g_variant_new_strv (const gchar * const *strv,
+ gssize length)
{
- if (length == -1)
+ GVariant **strings;
+ gsize i;
+
+ g_return_val_if_fail (length == 0 || strv != NULL, NULL);
+
+ if (length < 0)
+ length = g_strv_length ((gchar **) strv);
+
+ strings = g_new (GVariant *, length);
+ for (i = 0; i < length; i++)
+ strings[i] = g_variant_ref_sink (g_variant_new_string (strv[i]));
+
+ return g_variant_new_from_children (G_VARIANT_TYPE_STRING_ARRAY,
+ strings, length, TRUE);
+}
+
+/**
+ * g_variant_get_strv:
+ * @value: an array of strings #GVariant
+ * @length: (allow-none): the length of the result, or %NULL
+ * @returns: (array length=length): an array of constant strings
+ *
+ * Gets the contents of an array of strings #GVariant. This call
+ * makes a shallow copy; the return result should be released with
+ * g_free(), but the individual strings must not be modified.
+ *
+ * If @length is non-%NULL then the number of elements in the result
+ * is stored there. In any case, the resulting array will be
+ * %NULL-terminated.
+ *
+ * For an empty array, @length will be set to 0 and a pointer to a
+ * %NULL pointer will be returned.
+ *
+ * Since: 2.24
+ **/
+const gchar **
+g_variant_get_strv (GVariant *value,
+ gsize *length)
+{
+ const gchar **strv;
+ gsize n;
+ gsize i;
+
+ TYPE_CHECK (value, G_VARIANT_TYPE_STRING_ARRAY, NULL);
+
+ g_variant_get_data (value);
+ n = g_variant_n_children (value);
+ strv = g_new (const gchar *, n + 1);
+
+ for (i = 0; i < n; i++)
{
- const gchar *bytes = array;
+ GVariant *string;
- length = 0;
- while (bytes[length++]);
+ string = g_variant_get_child_value (value, i);
+ strv[i] = g_variant_get_string (string, NULL);
+ g_variant_unref (string);
}
+ strv[i] = NULL;
- return g_variant_new_from_trusted (G_VARIANT_TYPE ("ay"),
- array, length);
+ if (length)
+ *length = n;
+
+ return strv;
}
/**
- * g_variant_get_byte_array:
- * @value: an array of bytes #GVariant
+ * g_variant_dup_strv:
+ * @value: an array of strings #GVariant
* @length: (allow-none): the length of the result, or %NULL
- * @returns: (array length=length): a pointer to the byte data, or %NULL
+ * @returns: (array length=length): an array of strings
+ *
+ * Gets the contents of an array of strings #GVariant. This call
+ * makes a deep copy; the return result should be released with
+ * g_strfreev().
+ *
+ * If @length is non-%NULL then the number of elements in the result
+ * is stored there. In any case, the resulting array will be
+ * %NULL-terminated.
+ *
+ * For an empty array, @length will be set to 0 and a pointer to a
+ * %NULL pointer will be returned.
+ *
+ * Since: 2.24
+ **/
+gchar **
+g_variant_dup_strv (GVariant *value,
+ gsize *length)
+{
+ gchar **strv;
+ gsize n;
+ gsize i;
+
+ TYPE_CHECK (value, G_VARIANT_TYPE_STRING_ARRAY, NULL);
+
+ n = g_variant_n_children (value);
+ strv = g_new (gchar *, n + 1);
+
+ for (i = 0; i < n; i++)
+ {
+ GVariant *string;
+
+ string = g_variant_get_child_value (value, i);
+ strv[i] = g_variant_dup_string (string, NULL);
+ g_variant_unref (string);
+ }
+ strv[i] = NULL;
+
+ if (length)
+ *length = n;
+
+ return strv;
+}
+
+/**
+ * g_variant_new_bytestring:
+ * @string: a normal utf8 nul-terminated string
+ * @returns: a new bytestring #GVariant instance
+ *
+ * Creates an array-of-bytes #GVariant with the contents of @string.
+ * This function is just like g_variant_new_string() except that the
+ * string need not be valid utf8.
+ *
+ * The nul terminator character at the end of the string is stored in
+ * the array.
+ *
+ * Since: 2.26
+ **/
+GVariant *
+g_variant_new_bytestring (const gchar *string)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+
+ return g_variant_new_from_trusted (G_VARIANT_TYPE_BYTESTRING,
+ string, strlen (string) + 1);
+}
+
+/**
+ * g_variant_get_bytestring:
+ * @value: an array-of-bytes #GVariant instance
+ * @returns: the constant string
+ *
+ * Returns the string value of a #GVariant instance with an
+ * array-of-bytes type. The string has no particular encoding.
*
- * Gets the contents of an array of bytes #GVariant.
+ * If the array does not end with a nul terminator character, the empty
+ * string is returned. For this reason, you can always trust that a
+ * non-%NULL nul-terminated string will be returned by this function.
*
- * If @length is non-%NULL then it points to a location at which to
- * store the length of the array and nul bytes contained within the
- * array have no special meaning.
+ * If the array contains a nul terminator character somewhere other than
+ * the last byte then the returned string is the string, up to the first
+ * such nul character.
*
- * If @length is %NULL then the caller has no way to determine what the
- * length of the returned data might be. In this case, the function
- * ensures that the last byte of the array is a nul byte and, if it is
- * not, returns %NULL instead. In this way, the caller is assured that
- * any non-%NULL pointer that is returned will be nul-terminated.
+ * It is an error to call this function with a @value that is not an
+ * array of bytes.
*
* The return value remains valid as long as @value exists.
*
* Since: 2.26
**/
-gconstpointer
-g_variant_get_byte_array (GVariant *value,
- gsize *length)
+const gchar *
+g_variant_get_bytestring (GVariant *value)
{
- gconstpointer data;
+ const gchar *string;
gsize size;
- TYPE_CHECK (value, G_VARIANT_TYPE ("ay"), NULL);
+ TYPE_CHECK (value, G_VARIANT_TYPE_BYTESTRING, NULL);
- data = g_variant_get_data (value);
+ /* Won't be NULL since this is an array type */
+ string = g_variant_get_data (value);
size = g_variant_get_size (value);
- if (length == NULL)
- {
- const gchar *bytes = data;
-
- if (bytes[size - 1] != '\0')
- return NULL;
- }
+ if (string[size - 1] == '\0')
+ return string;
else
+ return "";
+}
+
+/**
+ * g_variant_dup_bytestring:
+ * @value: an array-of-bytes #GVariant instance
+ * @length: (allow-none) (default NULL): a pointer to a #gsize, to store
+ * the length (not including the nul terminator)
+ * @returns: a newly allocated string
+ *
+ * Similar to g_variant_get_bytestring() except that instead of
+ * returning a constant string, the string is duplicated.
+ *
+ * The return value must be freed using g_free().
+ *
+ * Since: 2.26
+ **/
+gchar *
+g_variant_dup_bytestring (GVariant *value,
+ gsize *length)
+{
+ const gchar *original = g_variant_get_bytestring (value);
+ gsize size;
+
+ /* don't crash in case get_bytestring() had an assert failure */
+ if (original == NULL)
+ return NULL;
+
+ size = strlen (original);
+
+ if (length)
*length = size;
- return data;
+ return g_memdup (original, size + 1);
}
/**
- * g_variant_new_strv:
- * @strv: an array of strings
+ * g_variant_new_bytestring_array:
+ * @strv (array length=length): an array of strings
* @length: the length of @strv, or -1
- * @returns: (array length=length): a new floating #GVariant instance
+ * @returns: a new floating #GVariant instance
*
- * Constructs an array of strings #GVariant from the given array of
+ * Constructs an array of bytestring #GVariant from the given array of
* strings.
*
- * If @length is not -1 then it gives the maximum length of @strv. In
- * any case, a %NULL pointer in @strv is taken as a terminator.
+ * If @length is -1 then @strv is %NULL-terminated.
*
- * Since: 2.24
+ * Since: 2.26
**/
GVariant *
-g_variant_new_strv (const gchar * const *strv,
- gssize length)
+g_variant_new_bytestring_array (const gchar * const *strv,
+ gssize length)
{
GVariant **strings;
gsize i;
@@ -1271,43 +1418,40 @@ g_variant_new_strv (const gchar * const *strv,
strings = g_new (GVariant *, length);
for (i = 0; i < length; i++)
- strings[i] = g_variant_ref_sink (g_variant_new_string (strv[i]));
+ strings[i] = g_variant_ref_sink (g_variant_new_bytestring (strv[i]));
- return g_variant_new_from_children (G_VARIANT_TYPE ("as"),
+ return g_variant_new_from_children (G_VARIANT_TYPE_BYTESTRING_ARRAY,
strings, length, TRUE);
}
/**
- * g_variant_get_strv:
- * @value: an array of strings #GVariant
+ * g_variant_get_bytestring_array:
+ * @value: an array of array of bytes #GVariant ('aay')
* @length: (allow-none): the length of the result, or %NULL
* @returns: (array length=length): an array of constant strings
*
- * Gets the contents of an array of strings #GVariant. This call
+ * Gets the contents of an array of array of bytes #GVariant. This call
* makes a shallow copy; the return result should be released with
* g_free(), but the individual strings must not be modified.
*
- * If @length is non-%NULL then the number of elements in the result
- * is stored there. In any case, the resulting array will be
+ * If @length is non-%NULL then the number of elements in the result is
+ * stored there. In any case, the resulting array will be
* %NULL-terminated.
*
* For an empty array, @length will be set to 0 and a pointer to a
* %NULL pointer will be returned.
*
- * Since: 2.24
+ * Since: 2.26
**/
const gchar **
-g_variant_get_strv (GVariant *value,
- gsize *length)
+g_variant_get_bytestring_array (GVariant *value,
+ gsize *length)
{
const gchar **strv;
gsize n;
gsize i;
- g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("as")) ||
- g_variant_is_of_type (value, G_VARIANT_TYPE ("ao")) ||
- g_variant_is_of_type (value, G_VARIANT_TYPE ("ag")),
- NULL);
+ TYPE_CHECK (value, G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL);
g_variant_get_data (value);
n = g_variant_n_children (value);
@@ -1318,7 +1462,7 @@ g_variant_get_strv (GVariant *value,
GVariant *string;
string = g_variant_get_child_value (value, i);
- strv[i] = g_variant_get_string (string, NULL);
+ strv[i] = g_variant_get_bytestring (string);
g_variant_unref (string);
}
strv[i] = NULL;
@@ -1330,37 +1474,35 @@ g_variant_get_strv (GVariant *value,
}
/**
- * g_variant_dup_strv:
- * @value: an array of strings #GVariant
+ * g_variant_dup_bytestring_array:
+ * @value: an array of array of bytes #GVariant ('aay')
* @length: (allow-none): the length of the result, or %NULL
- * @returns: (array length=length): an array of constant strings
+ * @returns: (array length=length): an array of strings
*
- * Gets the contents of an array of strings #GVariant. This call
+ * Gets the contents of an array of array of bytes #GVariant. This call
* makes a deep copy; the return result should be released with
* g_strfreev().
*
- * If @length is non-%NULL then the number of elements in the result
- * is stored there. In any case, the resulting array will be
+ * If @length is non-%NULL then the number of elements in the result is
+ * stored there. In any case, the resulting array will be
* %NULL-terminated.
*
* For an empty array, @length will be set to 0 and a pointer to a
* %NULL pointer will be returned.
*
- * Since: 2.24
+ * Since: 2.26
**/
gchar **
-g_variant_dup_strv (GVariant *value,
- gsize *length)
+g_variant_dup_bytestring_array (GVariant *value,
+ gsize *length)
{
gchar **strv;
gsize n;
gsize i;
- g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("as")) ||
- g_variant_is_of_type (value, G_VARIANT_TYPE ("ao")) ||
- g_variant_is_of_type (value, G_VARIANT_TYPE ("ag")),
- NULL);
+ TYPE_CHECK (value, G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL);
+ g_variant_get_data (value);
n = g_variant_n_children (value);
strv = g_new (gchar *, n + 1);
@@ -1369,7 +1511,7 @@ g_variant_dup_strv (GVariant *value,
GVariant *string;
string = g_variant_get_child_value (value, i);
- strv[i] = g_variant_dup_string (string, NULL);
+ strv[i] = g_variant_dup_bytestring (string, NULL);
g_variant_unref (string);
}
strv[i] = NULL;
@@ -1573,6 +1715,45 @@ g_variant_print_string (GVariant *value,
case G_VARIANT_CLASS_ARRAY:
/* it's an array so the first character of the type string is 'a'
*
+ * if the first two characters are 'ay' then it's a bytestring.
+ * under certain conditions we print those as strings.
+ */
+ if (g_variant_get_type_string (value)[1] == 'y')
+ {
+ const gchar *str;
+ gsize size;
+ gsize i;
+
+ /* first determine if it is a byte string.
+ * that's when there's a single nul character: at the end.
+ */
+ str = g_variant_get_data (value);
+ size = g_variant_get_size (value);
+
+ for (i = 0; i < size; i++)
+ if (str[i] == '\0')
+ break;
+
+ /* first nul byte is the last byte -> it's a byte string. */
+ if (i == size - 1)
+ {
+ gchar *escaped = g_strescape (str, NULL);
+
+ /* use double quotes only if a ' is in the string */
+ if (strchr (str, '\''))
+ g_string_append_printf (string, "b\"%s\"", escaped);
+ else
+ g_string_append_printf (string, "b'%s'", escaped);
+
+ g_free (escaped);
+ break;
+ }
+
+ else
+ /* fall through and handle normally... */;
+ }
+
+ /*
* if the first two characters are 'a{' then it's an array of
* dictionary entries (ie: a dictionary) so we print that
* differently.
@@ -3015,19 +3196,43 @@ g_variant_format_string_scan (const gchar *string,
break;
- case '^': /* '^as' or '^a&s' only */
- if (next_char() != 'a')
- return FALSE;
+ case '^':
+ if ((c = next_char()) == 'a')
+ {
+ if ((c = next_char()) == '&')
+ {
+ if ((c = next_char()) == 'a')
+ {
+ if ((c = next_char()) == 'y')
+ break; /* '^a&ay' */
+ }
+
+ else if (c == 's')
+ break; /* '^a&s' */
+ }
- if (peek_char() == '&')
- next_char ();
+ else if (c == 'a')
+ {
+ if ((c = next_char()) == 'y')
+ break; /* '^aay' */
+ }
- c = next_char ();
+ else if (c == 's')
+ break; /* '^as' */
- if (c != 's' && c != 'o' && c != 'g')
- return FALSE;
+ else if (c == 'y')
+ break; /* '^ay' */
+ }
+ else if (c == '&')
+ {
+ if ((c = next_char()) == 'a')
+ {
+ if ((c = next_char()) == 'y')
+ break; /* '^&ay' */
+ }
+ }
- break;
+ return FALSE;
case '&':
c = next_char();
@@ -3242,6 +3447,29 @@ g_variant_valist_free_nnp (const gchar *str,
}
}
+static gchar
+g_variant_scan_convenience (const gchar **str,
+ gboolean *constant,
+ guint *arrays)
+{
+ *constant = FALSE;
+ *arrays = 0;
+
+ for (;;)
+ {
+ char c = *(*str)++;
+
+ if (c == '&')
+ *constant = TRUE;
+
+ else if (c == 'a')
+ (*arrays)++;
+
+ else
+ return c;
+ }
+}
+
static GVariant *
g_variant_valist_new_nnp (const gchar **str,
gpointer ptr)
@@ -3288,31 +3516,16 @@ g_variant_valist_new_nnp (const gchar **str,
case '^':
{
- const GVariantType *type;
- GVariantType *array_type;
- GVariant **children;
- gchar **strv = ptr;
- GVariant *value;
- guint length, i;
+ gboolean constant;
+ guint arrays;
- if ((*str)[1] == '&') /* '^a&s' */
- (*str) += 2;
- else /* '^as' */
- (*str)++;
+ if (g_variant_scan_convenience (str, &constant, &arrays) == 's')
+ return g_variant_new_strv (ptr, -1);
- type = (GVariantType *) (*str)++;
- array_type = g_variant_type_new_array (type);
- length = g_strv_length (strv);
- children = g_new (GVariant *, length);
- for (i = 0; i < length; i++)
- children[i] = g_variant_ref_sink (
- g_variant_new_from_trusted (type, strv[i], strlen (strv[i]) + 1));
+ if (arrays > 1)
+ return g_variant_new_bytestring_array (ptr, -1);
- value = g_variant_new_from_children (array_type, children,
- length, TRUE);
- g_variant_type_free (array_type);
-
- return value;
+ return g_variant_new_bytestring (ptr);
}
case '@':
@@ -3373,16 +3586,34 @@ g_variant_valist_get_nnp (const gchar **str,
return g_variant_dup_string (value, NULL);
case '^':
- if ((*str)[1] == '&') /* '^a&s' */
- {
- (*str) += 3;
- return g_variant_get_strv (value, NULL);
- }
- else /* '^as' */
- {
- (*str) += 2;
- return g_variant_dup_strv (value, NULL);
- }
+ {
+ gboolean constant;
+ guint arrays;
+
+ if (g_variant_scan_convenience (str, &constant, &arrays) == 's')
+ {
+ if (constant)
+ return g_variant_get_strv (value, NULL);
+ else
+ return g_variant_dup_strv (value, NULL);
+ }
+
+ else if (arrays > 1)
+ {
+ if (constant)
+ return g_variant_get_bytestring_array (value, NULL);
+ else
+ return g_variant_dup_bytestring_array (value, NULL);
+ }
+
+ else
+ {
+ if (constant)
+ return (gchar *) g_variant_get_bytestring (value);
+ else
+ return g_variant_dup_bytestring (value, NULL);
+ }
+ }
case '@':
g_variant_type_string_scan (*str, NULL, str);
diff --git a/glib/gvariant.h b/glib/gvariant.h
index aa270f6..528492b 100644
--- a/glib/gvariant.h
+++ b/glib/gvariant.h
@@ -83,10 +83,11 @@ gboolean g_variant_is_object_path (const g
GVariant * g_variant_new_signature (const gchar *signature);
gboolean g_variant_is_signature (const gchar *string);
GVariant * g_variant_new_variant (GVariant *value);
-GVariant * g_variant_new_byte_array (gconstpointer array,
- gssize length);
GVariant * g_variant_new_strv (const gchar * const *strv,
gssize length);
+GVariant * g_variant_new_bytestring (const gchar *string);
+GVariant * g_variant_new_bytestring_array (const gchar * const *strv,
+ gssize length);
gboolean g_variant_get_boolean (GVariant *value);
guchar g_variant_get_byte (GVariant *value);
@@ -103,12 +104,17 @@ const gchar * g_variant_get_string (GVarian
gsize *length);
gchar * g_variant_dup_string (GVariant *value,
gsize *length);
-gconstpointer g_variant_get_byte_array (GVariant *value,
- gsize *length);
const gchar ** g_variant_get_strv (GVariant *value,
gsize *length);
gchar ** g_variant_dup_strv (GVariant *value,
gsize *length);
+const gchar * g_variant_get_bytestring (GVariant *value);
+gchar * g_variant_dup_bytestring (GVariant *value,
+ gsize *length);
+const gchar ** g_variant_get_bytestring_array (GVariant *value,
+ gsize *length);
+gchar ** g_variant_dup_bytestring_array (GVariant *value,
+ gsize *length);
GVariant * g_variant_new_maybe (const GVariantType *child_type,
GVariant *child);
diff --git a/glib/gvarianttype.h b/glib/gvarianttype.h
index 2203ccb..124fa46 100644
--- a/glib/gvarianttype.h
+++ b/glib/gvarianttype.h
@@ -232,6 +232,31 @@ typedef struct _GVariantType GVariantType;
#define G_VARIANT_TYPE_DICTIONARY ((const GVariantType *) "a{?*}")
/**
+ * G_VARIANT_TYPE_STRING_ARRAY:
+ *
+ * The type of an array of strings.
+ **/
+#define G_VARIANT_TYPE_STRING_ARRAY ((const GVariantType *) "as")
+
+/**
+ * G_VARIANT_TYPE_BYTESTRING:
+ *
+ * The type of an array of bytes. This type is commonly used to pass
+ * around strings that may not be valid utf8. In that case, the
+ * convention is that the nul terminator character should be included as
+ * the last character in the array.
+ **/
+#define G_VARIANT_TYPE_BYTESTRING ((const GVariantType *) "ay")
+
+/**
+ * G_VARIANT_TYPE_BYTESTRING_ARRAY:
+ *
+ * The type of an array of byte strings (an array of arrays of bytes).
+ **/
+#define G_VARIANT_TYPE_BYTESTRING_ARRAY ((const GVariantType *) "aay")
+
+
+/**
* G_VARIANT_TYPE:
* @type_string: a well-formed #GVariantType type string
*
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index 23302f8..7da3830 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -2981,16 +2981,16 @@ test_varargs (void)
gchar *str;
gint i;
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
- g_variant_builder_add (&builder, "o", "/foo");
- g_variant_builder_add (&builder, "o", "/bar");
- g_variant_builder_add (&builder, "o", "/baz");
- value = g_variant_new("(ao^ao^a&o)", &builder, strvector, strvector);
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
+ g_variant_builder_add (&builder, "s", "/foo");
+ g_variant_builder_add (&builder, "s", "/bar");
+ g_variant_builder_add (&builder, "s", "/baz");
+ value = g_variant_new("(as^as^a&s)", &builder, strvector, strvector);
g_variant_iter_init (&tuple, value);
- g_variant_iter_next (&tuple, "ao", &array);
+ g_variant_iter_next (&tuple, "as", &array);
i = 0;
- while (g_variant_iter_loop (array, "o", &str))
+ while (g_variant_iter_loop (array, "s", &str))
g_assert_cmpstr (str, ==, test_strs[i++]);
g_assert (i == 3);
@@ -2998,17 +2998,17 @@ test_varargs (void)
/* start over */
g_variant_iter_init (&tuple, value);
- g_variant_iter_next (&tuple, "ao", &array);
+ g_variant_iter_next (&tuple, "as", &array);
i = 0;
- while (g_variant_iter_loop (array, "&o", &str))
+ while (g_variant_iter_loop (array, "&s", &str))
g_assert_cmpstr (str, ==, test_strs[i++]);
g_assert (i == 3);
g_variant_iter_free (array);
- g_variant_iter_next (&tuple, "^a&o", &strv);
- g_variant_iter_next (&tuple, "^ao", &my_strv);
+ g_variant_iter_next (&tuple, "^a&s", &strv);
+ g_variant_iter_next (&tuple, "^as", &my_strv);
g_assert_cmpstr (strv[0], ==, "/hello");
g_assert_cmpstr (strv[1], ==, "/world");
@@ -3033,46 +3033,46 @@ test_varargs (void)
gchar **strv;
gint i;
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("aag"));
- g_variant_builder_open (&builder, G_VARIANT_TYPE ("ag"));
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aas"));
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("as"));
for (i = 0; i < 6; i++)
if (i & 1)
- g_variant_builder_add (&builder, "g", strvector[i]);
+ g_variant_builder_add (&builder, "s", strvector[i]);
else
- g_variant_builder_add (&builder, "&g", strvector[i]);
+ g_variant_builder_add (&builder, "&s", strvector[i]);
g_variant_builder_close (&builder);
- g_variant_builder_add (&builder, "^ag", strvector);
- g_variant_builder_add (&builder, "^ag", strvector);
- value = g_variant_new ("aag", &builder);
+ g_variant_builder_add (&builder, "^as", strvector);
+ g_variant_builder_add (&builder, "^as", strvector);
+ value = g_variant_new ("aas", &builder);
g_variant_iter_init (&iter, value);
- while (g_variant_iter_loop (&iter, "^ag", &strv))
+ while (g_variant_iter_loop (&iter, "^as", &strv))
for (i = 0; i < 6; i++)
g_assert_cmpstr (strv[i], ==, strvector[i]);
g_variant_iter_init (&iter, value);
- while (g_variant_iter_loop (&iter, "^a&g", &strv))
+ while (g_variant_iter_loop (&iter, "^a&s", &strv))
for (i = 0; i < 6; i++)
g_assert_cmpstr (strv[i], ==, strvector[i]);
g_variant_iter_init (&iter, value);
- while (g_variant_iter_loop (&iter, "ag", &i2))
+ while (g_variant_iter_loop (&iter, "as", &i2))
{
gchar *str;
i = 0;
- while (g_variant_iter_loop (i2, "g", &str))
+ while (g_variant_iter_loop (i2, "s", &str))
g_assert_cmpstr (str, ==, strvector[i++]);
g_assert (i == 6);
}
g_variant_iter_init (&iter, value);
i3 = g_variant_iter_copy (&iter);
- while (g_variant_iter_loop (&iter, "@ag", &sub))
+ while (g_variant_iter_loop (&iter, "@as", &sub))
{
gchar *str = g_variant_print (sub, TRUE);
g_assert_cmpstr (str, ==,
- "[signature 'i', 'ii', 'iii', 'iv', 'v', 'vi']");
+ "['i', 'ii', 'iii', 'iv', 'v', 'vi']");
g_free (str);
}
@@ -3087,7 +3087,7 @@ test_varargs (void)
{
gchar *str = g_variant_print (sub, TRUE);
g_assert_cmpstr (str, ==,
- "[signature 'i', 'ii', 'iii', 'iv', 'v', 'vi']");
+ "['i', 'ii', 'iii', 'iv', 'v', 'vi']");
g_free (str);
}
@@ -3104,11 +3104,11 @@ test_varargs (void)
const gchar *str = NULL;
GVariant *cval;
- g_variant_get_child (sub, j, "&g", &str);
+ g_variant_get_child (sub, j, "&s", &str);
g_assert_cmpstr (str, ==, strvector[j]);
cval = g_variant_get_child_value (sub, j);
- g_variant_get (cval, "&g", &str);
+ g_variant_get (cval, "&s", &str);
g_assert_cmpstr (str, ==, strvector[j]);
g_variant_unref (cval);
}
@@ -3812,6 +3812,80 @@ test_floating (void)
g_variant_unref (value);
}
+static void
+test_bytestring (void)
+{
+ const gchar *test_string = "foo,bar,baz,quux,\xffoooo";
+ GVariant *value;
+ gchar **strv;
+ gchar *str;
+
+ strv = g_strsplit (test_string, ",", 0);
+
+ value = g_variant_new_bytestring_array ((const gchar **) strv, -1);
+ g_assert (g_variant_is_floating (value));
+ g_strfreev (strv);
+
+ str = g_variant_print (value, FALSE);
+ g_variant_unref (value);
+
+ value = g_variant_parse (NULL, str, NULL, NULL, NULL);
+ g_free (str);
+
+ strv = g_variant_dup_bytestring_array (value, NULL);
+ g_variant_unref (value);
+
+ str = g_strjoinv (",", strv);
+ g_strfreev (strv);
+
+ g_assert_cmpstr (str, ==, test_string);
+ g_free (str);
+
+ strv = g_strsplit (test_string, ",", 0);
+ value = g_variant_new ("(^aay^a&ay^ay^&ay)",
+ strv, strv, strv[0], strv[0]);
+ g_strfreev (strv);
+
+ g_variant_get_child (value, 0, "^a&ay", &strv);
+ str = g_strjoinv (",", strv);
+ g_free (strv);
+ g_assert_cmpstr (str, ==, test_string);
+ g_free (str);
+
+ g_variant_get_child (value, 0, "^aay", &strv);
+ str = g_strjoinv (",", strv);
+ g_strfreev (strv);
+ g_assert_cmpstr (str, ==, test_string);
+ g_free (str);
+
+ g_variant_get_child (value, 1, "^a&ay", &strv);
+ str = g_strjoinv (",", strv);
+ g_free (strv);
+ g_assert_cmpstr (str, ==, test_string);
+ g_free (str);
+
+ g_variant_get_child (value, 1, "^aay", &strv);
+ str = g_strjoinv (",", strv);
+ g_strfreev (strv);
+ g_assert_cmpstr (str, ==, test_string);
+ g_free (str);
+
+ g_variant_get_child (value, 2, "^ay", &str);
+ g_assert_cmpstr (str, ==, "foo");
+ g_free (str);
+
+ g_variant_get_child (value, 2, "^&ay", &str);
+ g_assert_cmpstr (str, ==, "foo");
+
+ g_variant_get_child (value, 3, "^ay", &str);
+ g_assert_cmpstr (str, ==, "foo");
+ g_free (str);
+
+ g_variant_get_child (value, 3, "^&ay", &str);
+ g_assert_cmpstr (str, ==, "foo");
+ g_variant_unref (value);
+}
+
int
main (int argc, char **argv)
{
@@ -3851,6 +3925,7 @@ main (int argc, char **argv)
g_test_add_func ("/gvariant/parse-failures", test_parse_failures);
g_test_add_func ("/gvariant/parse-positional", test_parse_positional);
g_test_add_func ("/gvariant/floating", test_floating);
+ g_test_add_func ("/gvariant/bytestring", test_bytestring);
return g_test_run ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]