mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-11 15:06:14 +01:00
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
This commit is contained in:
parent
2d2a321a4b
commit
d9e90c3894
@ -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
|
||||
|
@ -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.
|
||||
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>
|
||||
<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>.
|
||||
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>
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,23 +188,6 @@ token_stream_prepare (TokenStream *stream)
|
||||
break;
|
||||
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++)
|
||||
|
||||
if (*end == '(' || *end == '{')
|
||||
brackets++;
|
||||
|
||||
else if ((*end == ')' || *end == '}') && !brackets--)
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case '\'': case '"':
|
||||
for (end = stream->stream + 1; end != stream->end; end++)
|
||||
if (*end == stream->stream[0] || *end == '\0' ||
|
||||
@ -200,6 +198,23 @@ token_stream_prepare (TokenStream *stream)
|
||||
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 != ':' && *end != '>' && !g_ascii_isspace (*end);
|
||||
end++)
|
||||
|
||||
if (*end == '(' || *end == '{')
|
||||
brackets++;
|
||||
|
||||
else if ((*end == ')' || *end == '}') && !brackets--)
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
end = stream->stream + 1;
|
||||
break;
|
||||
@ -224,12 +239,24 @@ token_stream_peek (TokenStream *stream,
|
||||
return stream->this[0] == first_char;
|
||||
}
|
||||
|
||||
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
|
||||
@ -1539,6 +1566,128 @@ string_parse (TokenStream *stream,
|
||||
return (AST *) string;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -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");
|
||||
|
499
glib/gvariant.c
499
glib/gvariant.c
@ -1164,96 +1164,16 @@ g_variant_dup_string (GVariant *value,
|
||||
return g_strdup (g_variant_get_string (value, length));
|
||||
}
|
||||
|
||||
/**
|
||||
* g_variant_new_byte_array:
|
||||
* @array: (array length=length): a pointer to an array of bytes
|
||||
* @length: the length of @array, or -1
|
||||
* @returns: a new floating #GVariant instance
|
||||
*
|
||||
* Constructs an array of bytes #GVariant from the given array of bytes.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Since: 2.26
|
||||
**/
|
||||
GVariant *
|
||||
g_variant_new_byte_array (gconstpointer array,
|
||||
gssize length)
|
||||
{
|
||||
if (length == -1)
|
||||
{
|
||||
const gchar *bytes = array;
|
||||
|
||||
length = 0;
|
||||
while (bytes[length++]);
|
||||
}
|
||||
|
||||
return g_variant_new_from_trusted (G_VARIANT_TYPE ("ay"),
|
||||
array, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_variant_get_byte_array:
|
||||
* @value: an array of bytes #GVariant
|
||||
* @length: (allow-none): the length of the result, or %NULL
|
||||
* @returns: (array length=length): a pointer to the byte data, or %NULL
|
||||
*
|
||||
* Gets the contents of an array of bytes #GVariant.
|
||||
*
|
||||
* 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 @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.
|
||||
*
|
||||
* The return value remains valid as long as @value exists.
|
||||
*
|
||||
* Since: 2.26
|
||||
**/
|
||||
gconstpointer
|
||||
g_variant_get_byte_array (GVariant *value,
|
||||
gsize *length)
|
||||
{
|
||||
gconstpointer data;
|
||||
gsize size;
|
||||
|
||||
TYPE_CHECK (value, G_VARIANT_TYPE ("ay"), NULL);
|
||||
|
||||
data = 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;
|
||||
}
|
||||
else
|
||||
*length = size;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_variant_new_strv:
|
||||
* @strv: an array of strings
|
||||
* @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
|
||||
* 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
|
||||
**/
|
||||
@ -1273,7 +1193,7 @@ g_variant_new_strv (const gchar * const *strv,
|
||||
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 ("as"),
|
||||
return g_variant_new_from_children (G_VARIANT_TYPE_STRING_ARRAY,
|
||||
strings, length, TRUE);
|
||||
}
|
||||
|
||||
@ -1304,10 +1224,7 @@ g_variant_get_strv (GVariant *value,
|
||||
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_STRING_ARRAY, NULL);
|
||||
|
||||
g_variant_get_data (value);
|
||||
n = g_variant_n_children (value);
|
||||
@ -1333,7 +1250,7 @@ g_variant_get_strv (GVariant *value,
|
||||
* g_variant_dup_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
|
||||
* @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
|
||||
@ -1356,10 +1273,7 @@ g_variant_dup_strv (GVariant *value,
|
||||
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_STRING_ARRAY, NULL);
|
||||
|
||||
n = g_variant_n_children (value);
|
||||
strv = g_new (gchar *, n + 1);
|
||||
@ -1380,6 +1294,234 @@ g_variant_dup_strv (GVariant *value,
|
||||
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.
|
||||
*
|
||||
* 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 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.
|
||||
*
|
||||
* 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
|
||||
**/
|
||||
const gchar *
|
||||
g_variant_get_bytestring (GVariant *value)
|
||||
{
|
||||
const gchar *string;
|
||||
gsize size;
|
||||
|
||||
TYPE_CHECK (value, G_VARIANT_TYPE_BYTESTRING, NULL);
|
||||
|
||||
/* Won't be NULL since this is an array type */
|
||||
string = g_variant_get_data (value);
|
||||
size = g_variant_get_size (value);
|
||||
|
||||
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 g_memdup (original, size + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_variant_new_bytestring_array:
|
||||
* @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 bytestring #GVariant from the given array of
|
||||
* strings.
|
||||
*
|
||||
* If @length is -1 then @strv is %NULL-terminated.
|
||||
*
|
||||
* Since: 2.26
|
||||
**/
|
||||
GVariant *
|
||||
g_variant_new_bytestring_array (const gchar * const *strv,
|
||||
gssize length)
|
||||
{
|
||||
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_bytestring (strv[i]));
|
||||
|
||||
return g_variant_new_from_children (G_VARIANT_TYPE_BYTESTRING_ARRAY,
|
||||
strings, length, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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
|
||||
* %NULL-terminated.
|
||||
*
|
||||
* For an empty array, @length will be set to 0 and a pointer to a
|
||||
* %NULL pointer will be returned.
|
||||
*
|
||||
* Since: 2.26
|
||||
**/
|
||||
const gchar **
|
||||
g_variant_get_bytestring_array (GVariant *value,
|
||||
gsize *length)
|
||||
{
|
||||
const gchar **strv;
|
||||
gsize n;
|
||||
gsize i;
|
||||
|
||||
TYPE_CHECK (value, G_VARIANT_TYPE_BYTESTRING_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++)
|
||||
{
|
||||
GVariant *string;
|
||||
|
||||
string = g_variant_get_child_value (value, i);
|
||||
strv[i] = g_variant_get_bytestring (string);
|
||||
g_variant_unref (string);
|
||||
}
|
||||
strv[i] = NULL;
|
||||
|
||||
if (length)
|
||||
*length = n;
|
||||
|
||||
return strv;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 strings
|
||||
*
|
||||
* 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
|
||||
* %NULL-terminated.
|
||||
*
|
||||
* For an empty array, @length will be set to 0 and a pointer to a
|
||||
* %NULL pointer will be returned.
|
||||
*
|
||||
* Since: 2.26
|
||||
**/
|
||||
gchar **
|
||||
g_variant_dup_bytestring_array (GVariant *value,
|
||||
gsize *length)
|
||||
{
|
||||
gchar **strv;
|
||||
gsize n;
|
||||
gsize i;
|
||||
|
||||
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);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GVariant *string;
|
||||
|
||||
string = g_variant_get_child_value (value, i);
|
||||
strv[i] = g_variant_dup_bytestring (string, NULL);
|
||||
g_variant_unref (string);
|
||||
}
|
||||
strv[i] = NULL;
|
||||
|
||||
if (length)
|
||||
*length = n;
|
||||
|
||||
return strv;
|
||||
}
|
||||
|
||||
/* Type checking and querying {{{1 */
|
||||
/**
|
||||
* g_variant_get_type:
|
||||
@ -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' */
|
||||
}
|
||||
|
||||
if (peek_char() == '&')
|
||||
next_char ();
|
||||
else if (c == 's')
|
||||
break; /* '^a&s' */
|
||||
}
|
||||
|
||||
c = next_char ();
|
||||
else if (c == 'a')
|
||||
{
|
||||
if ((c = next_char()) == 'y')
|
||||
break; /* '^aay' */
|
||||
}
|
||||
|
||||
if (c != 's' && c != 'o' && c != 'g')
|
||||
return FALSE;
|
||||
else if (c == 's')
|
||||
break; /* '^as' */
|
||||
|
||||
break;
|
||||
else if (c == 'y')
|
||||
break; /* '^ay' */
|
||||
}
|
||||
else if (c == '&')
|
||||
{
|
||||
if ((c = next_char()) == 'a')
|
||||
{
|
||||
if ((c = next_char()) == 'y')
|
||||
break; /* '^&ay' */
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -231,6 +231,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
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user