2 * Copyright © 2009, 2010 Codethink Limited
4 * SPDX-License-Identifier: LGPL-2.1-or-later
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * Author: Ryan Lortie <desrt@desrt.ca>
31 #include "gstrfuncs.h"
32 #include "gtestutils.h"
34 #include "glib/gvariant-core.h"
35 #include "gvariant-internal.h"
36 #include "gvarianttype.h"
42 * designed by ryan lortie and william hua
43 * designed in itb-229 and at ghazi's, 2009.
47 * G_VARIANT_PARSE_ERROR:
49 * Error domain for GVariant text format parsing. Specific error codes
50 * are not currently defined for this domain. See #GError for
51 * information on error domains.
55 * @G_VARIANT_PARSE_ERROR_FAILED: generic error (unused)
56 * @G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED: a non-basic #GVariantType was given where a basic type was expected
57 * @G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE: cannot infer the #GVariantType
58 * @G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED: an indefinite #GVariantType was given where a definite type was expected
59 * @G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END: extra data after parsing finished
60 * @G_VARIANT_PARSE_ERROR_INVALID_CHARACTER: invalid character in number or unicode escape
61 * @G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING: not a valid #GVariant format string
62 * @G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH: not a valid object path
63 * @G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE: not a valid type signature
64 * @G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING: not a valid #GVariant type string
65 * @G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE: could not find a common type for array entries
66 * @G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE: the numerical value is out of range of the given type
67 * @G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG: the numerical value is out of range for any type
68 * @G_VARIANT_PARSE_ERROR_TYPE_ERROR: cannot parse as variant of the specified type
69 * @G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN: an unexpected token was encountered
70 * @G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD: an unknown keyword was encountered
71 * @G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT: unterminated string constant
72 * @G_VARIANT_PARSE_ERROR_VALUE_EXPECTED: no value given
73 * @G_VARIANT_PARSE_ERROR_RECURSION: variant was too deeply nested; #GVariant is only guaranteed to handle nesting up to 64 levels (Since: 2.64)
75 * Error codes returned by parsing text-format GVariants.
77 G_DEFINE_QUARK (g-variant-parse-error-quark, g_variant_parse_error)
80 * g_variant_parser_get_error_quark:
82 * Same as g_variant_error_quark().
84 * Deprecated: Use g_variant_parse_error_quark() instead.
87 g_variant_parser_get_error_quark (void)
89 return g_variant_parse_error_quark ();
99 parser_set_error_va (GError **error,
106 GString *msg = g_string_new (NULL);
108 if (location->start == location->end)
109 g_string_append_printf (msg, "%d", location->start);
111 g_string_append_printf (msg, "%d-%d", location->start, location->end);
115 g_assert (other->start != other->end);
116 g_string_append_printf (msg, ",%d-%d", other->start, other->end);
118 g_string_append_c (msg, ':');
120 g_string_append_vprintf (msg, format, ap);
121 g_set_error_literal (error, G_VARIANT_PARSE_ERROR, code, msg->str);
122 g_string_free (msg, TRUE);
127 parser_set_error (GError **error,
136 va_start (ap, format);
137 parser_set_error_va (error, location, other, code, format, ap);
153 token_stream_set_error (TokenStream *stream,
163 ref.start = stream->this - stream->start;
166 ref.end = stream->stream - stream->start;
170 va_start (ap, format);
171 parser_set_error_va (error, &ref, NULL, code, format, ap);
176 token_stream_prepare (TokenStream *stream)
181 if (stream->this != NULL)
184 while (stream->stream != stream->end && g_ascii_isspace (*stream->stream))
187 if (stream->stream == stream->end || *stream->stream == '\0')
189 stream->this = stream->stream;
193 switch (stream->stream[0])
195 case '-': case '+': case '.': case '0': case '1': case '2':
196 case '3': case '4': case '5': case '6': case '7': case '8':
198 for (end = stream->stream; end != stream->end; end++)
199 if (!g_ascii_isalnum (*end) &&
200 *end != '-' && *end != '+' && *end != '.')
205 if (stream->stream + 1 != stream->end &&
206 (stream->stream[1] == '\'' || stream->stream[1] == '"'))
208 for (end = stream->stream + 2; end != stream->end; end++)
209 if (*end == stream->stream[1] || *end == '\0' ||
210 (*end == '\\' && (++end == stream->end || *end == '\0')))
213 if (end != stream->end && *end)
220 case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
221 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
222 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
223 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
225 for (end = stream->stream; end != stream->end; end++)
226 if (!g_ascii_isalnum (*end))
231 for (end = stream->stream + 1; end != stream->end; end++)
232 if (*end == stream->stream[0] || *end == '\0' ||
233 (*end == '\\' && (++end == stream->end || *end == '\0')))
236 if (end != stream->end && *end)
241 /* stop at the first space, comma, colon or unmatched bracket.
242 * deals nicely with cases like (%i, %i) or {%i: %i}.
243 * Also: ] and > are never in format strings.
245 for (end = stream->stream + 1;
246 end != stream->end && *end != '\0' && *end != ',' &&
247 *end != ':' && *end != '>' && *end != ']' && !g_ascii_isspace (*end);
250 if (*end == '(' || *end == '{')
253 else if ((*end == ')' || *end == '}') && !brackets--)
259 end = stream->stream + 1;
263 stream->this = stream->stream;
264 stream->stream = end;
266 /* We must have at least one byte in a token. */
267 g_assert (stream->stream - stream->this >= 1);
273 token_stream_next (TokenStream *stream)
279 token_stream_peek (TokenStream *stream,
282 if (!token_stream_prepare (stream))
285 return stream->stream - stream->this >= 1 &&
286 stream->this[0] == first_char;
290 token_stream_peek2 (TokenStream *stream,
294 if (!token_stream_prepare (stream))
297 return stream->stream - stream->this >= 2 &&
298 stream->this[0] == first_char &&
299 stream->this[1] == second_char;
303 token_stream_is_keyword (TokenStream *stream)
305 if (!token_stream_prepare (stream))
308 return stream->stream - stream->this >= 2 &&
309 g_ascii_isalpha (stream->this[0]) &&
310 g_ascii_isalpha (stream->this[1]);
314 token_stream_is_numeric (TokenStream *stream)
316 if (!token_stream_prepare (stream))
319 return (stream->stream - stream->this >= 1 &&
320 (g_ascii_isdigit (stream->this[0]) ||
321 stream->this[0] == '-' ||
322 stream->this[0] == '+' ||
323 stream->this[0] == '.'));
327 token_stream_peek_string (TokenStream *stream,
330 gint length = strlen (token);
332 return token_stream_prepare (stream) &&
333 stream->stream - stream->this == length &&
334 memcmp (stream->this, token, length) == 0;
338 token_stream_consume (TokenStream *stream,
341 if (!token_stream_peek_string (stream, token))
344 token_stream_next (stream);
349 token_stream_require (TokenStream *stream,
351 const gchar *purpose,
355 if (!token_stream_consume (stream, token))
357 token_stream_set_error (stream, error, FALSE,
358 G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN,
359 "expected '%s'%s", token, purpose);
367 token_stream_assert (TokenStream *stream,
370 gboolean correct_token G_GNUC_UNUSED /* when compiling with G_DISABLE_ASSERT */;
372 correct_token = token_stream_consume (stream, token);
373 g_assert (correct_token);
377 token_stream_get (TokenStream *stream)
381 if (!token_stream_prepare (stream))
384 result = g_strndup (stream->this, stream->stream - stream->this);
390 token_stream_start_ref (TokenStream *stream,
393 token_stream_prepare (stream);
394 ref->start = stream->this - stream->start;
398 token_stream_end_ref (TokenStream *stream,
401 ref->end = stream->stream - stream->start;
405 pattern_copy (gchar **out,
410 while (**in == 'a' || **in == 'm' || **in == 'M')
411 *(*out)++ = *(*in)++;
415 if (**in == '(' || **in == '{')
418 else if (**in == ')' || **in == '}')
421 *(*out)++ = *(*in)++;
426 /* Returns the most general pattern that is subpattern of left and subpattern
427 * of right, or NULL if there is no such pattern. */
429 pattern_coalesce (const gchar *left,
435 /* the length of the output is loosely bound by the sum of the input
436 * lengths, not simply the greater of the two lengths.
438 * (*(iii)) + ((iii)*) ((iii)(iii))
442 out = result = g_malloc (strlen (left) + strlen (right));
444 while (*left && *right)
454 const gchar **one = &left, **the_other = &right;
457 if (**one == '*' && **the_other != ')')
459 pattern_copy (&out, the_other);
463 else if (**one == 'M' && **the_other == 'm')
465 *out++ = *(*the_other)++;
468 else if (**one == 'M' && **the_other != 'm' && **the_other != '*')
473 else if (**one == 'N' && strchr ("ynqiuxthd", **the_other))
475 *out++ = *(*the_other)++;
479 else if (**one == 'S' && strchr ("sog", **the_other))
481 *out++ = *(*the_other)++;
485 else if (one == &left)
487 one = &right, the_other = &left;
507 typedef struct _AST AST;
508 typedef gchar * (*get_pattern_func) (AST *ast,
510 typedef GVariant * (*get_value_func) (AST *ast,
511 const GVariantType *type,
513 typedef GVariant * (*get_base_value_func) (AST *ast,
514 const GVariantType *type,
516 typedef void (*free_func) (AST *ast);
520 gchar * (* get_pattern) (AST *ast,
522 GVariant * (* get_value) (AST *ast,
523 const GVariantType *type,
525 GVariant * (* get_base_value) (AST *ast,
526 const GVariantType *type,
528 void (* free) (AST *ast);
533 const ASTClass *class;
534 SourceRef source_ref;
538 ast_get_pattern (AST *ast,
541 return ast->class->get_pattern (ast, error);
545 ast_get_value (AST *ast,
546 const GVariantType *type,
549 return ast->class->get_value (ast, type, error);
555 ast->class->free (ast);
560 ast_set_error (AST *ast,
569 va_start (ap, format);
570 parser_set_error_va (error, &ast->source_ref,
571 other_ast ? & other_ast->source_ref : NULL,
578 ast_type_error (AST *ast,
579 const GVariantType *type,
584 typestr = g_variant_type_dup_string (type);
585 ast_set_error (ast, error, NULL,
586 G_VARIANT_PARSE_ERROR_TYPE_ERROR,
587 "can not parse as value of type '%s'",
595 ast_resolve (AST *ast,
602 pattern = ast_get_pattern (ast, error);
607 /* choose reasonable defaults
609 * 1) favour non-maybe values where possible
610 * 2) default type for strings is 's'
611 * 3) default type for integers is 'i'
613 for (i = 0; pattern[i]; i++)
617 ast_set_error (ast, error, NULL,
618 G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE,
619 "unable to infer type");
635 pattern[j++] = pattern[i];
640 value = ast_get_value (ast, G_VARIANT_TYPE (pattern), error);
647 static AST *parse (TokenStream *stream,
653 ast_array_append (AST ***array,
657 if ((*n_items & (*n_items - 1)) == 0)
658 *array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
660 (*array)[(*n_items)++] = ast;
664 ast_array_free (AST **array,
669 for (i = 0; i < n_items; i++)
675 ast_array_get_pattern (AST **array,
682 /* Find the pattern which applies to all children in the array, by l-folding a
683 * coalesce operation.
685 pattern = ast_get_pattern (array[0], error);
690 for (i = 1; i < n_items; i++)
694 tmp = ast_get_pattern (array[i], error);
702 merged = pattern_coalesce (pattern, tmp);
707 /* set coalescence implies pairwise coalescence (i think).
708 * we should therefore be able to trace the failure to a single
719 /* if 'j' reaches 'i' then we didn't find the pair that failed
720 * to coalesce. This shouldn't happen (see above), but just in
721 * case report an error:
725 ast_set_error (array[i], error, NULL,
726 G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE,
727 "unable to find a common type");
732 tmp2 = ast_get_pattern (array[j], NULL);
733 g_assert (tmp2 != NULL);
735 m = pattern_coalesce (tmp, tmp2);
741 /* we found a conflict between 'i' and 'j'.
743 * report the error. note: 'j' is first.
745 ast_set_error (array[j], error, array[i],
746 G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE,
747 "unable to find a common type");
771 maybe_get_pattern (AST *ast,
774 Maybe *maybe = (Maybe *) ast;
776 if (maybe->child != NULL)
778 gchar *child_pattern;
781 child_pattern = ast_get_pattern (maybe->child, error);
783 if (child_pattern == NULL)
786 pattern = g_strdup_printf ("m%s", child_pattern);
787 g_free (child_pattern);
792 return g_strdup ("m*");
796 maybe_get_value (AST *ast,
797 const GVariantType *type,
800 Maybe *maybe = (Maybe *) ast;
803 if (!g_variant_type_is_maybe (type))
804 return ast_type_error (ast, type, error);
806 type = g_variant_type_element (type);
810 value = ast_get_value (maybe->child, type, error);
818 return g_variant_new_maybe (type, value);
822 maybe_free (AST *ast)
824 Maybe *maybe = (Maybe *) ast;
826 if (maybe->child != NULL)
827 ast_free (maybe->child);
829 g_slice_free (Maybe, maybe);
833 maybe_parse (TokenStream *stream,
838 static const ASTClass maybe_class = {
840 maybe_get_value, NULL,
846 if (token_stream_consume (stream, "just"))
848 child = parse (stream, max_depth - 1, app, error);
853 else if (!token_stream_consume (stream, "nothing"))
855 token_stream_set_error (stream, error, TRUE,
856 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
861 maybe = g_slice_new (Maybe);
862 maybe->ast.class = &maybe_class;
863 maybe->child = child;
865 return (AST *) maybe;
869 maybe_wrapper (AST *ast,
870 const GVariantType *type,
873 const GVariantType *base_type;
874 GVariant *base_value;
875 GVariant *value = NULL;
878 GVariantTypeInfo *base_type_info = NULL;
879 gsize base_serialised_fixed_size, base_serialised_size, serialised_size, n_suffix_zeros;
880 guint8 *serialised = NULL;
881 GBytes *bytes = NULL;
884 for (depth = 0, base_type = type;
885 g_variant_type_is_maybe (base_type);
886 depth++, base_type = g_variant_type_element (base_type));
888 base_value = ast->class->get_base_value (ast, base_type, error);
890 if (base_value == NULL || depth == 0)
891 return g_steal_pointer (&base_value);
893 /* This is the equivalent of calling g_variant_new_maybe() in a loop enough
894 * times to match the number of nested maybe types in @type. It does the same
895 * in a single `GVariant` allocation, though.
897 * This avoids maybe_wrapper() becoming an attack vector where a malicious
898 * text-form variant can create a long array, and insert a typedecl for a
899 * deeply nested maybe type on one of its elements. This is achievable with a
900 * relatively short text form, but results in O(array length × typedecl depth)
901 * allocations. This is a denial of service attack.
903 * Instead of constructing a tree of `GVariant`s in tree-form to match the
904 * @ast, construct a single `GVariant` containing the serialised form of the
905 * maybe-wrappers and the base value that they contain. This is relatively
906 * straightforward: serialise the base value, and then append the correct
907 * number of zero bytes for the maybe-wrappers.
909 * This is a bit of a layering violation, unfortunately.
911 * By doing this, the typedecl depth variable is reduced to O(1).
913 trusted = g_variant_is_trusted (base_value);
915 /* See https://developer.gnome.org/documentation/specifications/gvariant-specification-1.0.html#maybes
917 * The serialised form of a `Just x` is the serialised form of `x` if `x` is
918 * fixed-size, and the serialised form of `x` plus a trailing zero byte if `x`
919 * is variable-size. A `Maybe` variant is always variable-size, even if its
920 * child element is fixed-size, because it might be `Nothing`. This means that
921 * all the maybe-wrappers which are not the innermost are always serialised
922 * with one trailing zero byte each.
924 * The serialised form of a `Nothing` is an empty byte sequence, but that’s
925 * already handled above in the `base_value == NULL` case.
927 base_type_info = g_variant_type_info_get (base_type);
928 g_variant_type_info_query (base_type_info, NULL, &base_serialised_fixed_size);
929 g_variant_type_info_unref (base_type_info);
931 base_serialised_size = g_variant_get_size (base_value);
932 n_suffix_zeros = (base_serialised_fixed_size > 0) ? depth - 1 : depth;
933 g_assert (base_serialised_size <= G_MAXSIZE - n_suffix_zeros);
934 serialised_size = base_serialised_size + n_suffix_zeros;
936 g_assert (serialised_size >= base_serialised_size);
938 /* Serialise the base value. */
939 serialised = g_malloc (serialised_size);
940 g_variant_store (base_value, serialised);
942 /* Zero-out the suffix zeros to complete the serialisation of the maybe wrappers. */
943 for (i = base_serialised_size; i < serialised_size; i++)
946 bytes = g_bytes_new_take (g_steal_pointer (&serialised), serialised_size);
947 value = g_variant_new_from_bytes (type, bytes, trusted);
948 g_bytes_unref (bytes);
950 g_variant_unref (base_value);
952 return g_steal_pointer (&value);
964 array_get_pattern (AST *ast,
967 Array *array = (Array *) ast;
971 if (array->n_children == 0)
972 return g_strdup ("Ma*");
974 pattern = ast_array_get_pattern (array->children, array->n_children, error);
979 result = g_strdup_printf ("Ma%s", pattern);
986 array_get_value (AST *ast,
987 const GVariantType *type,
990 Array *array = (Array *) ast;
991 const GVariantType *childtype;
992 GVariantBuilder builder;
995 if (!g_variant_type_is_array (type))
996 return ast_type_error (ast, type, error);
998 g_variant_builder_init (&builder, type);
999 childtype = g_variant_type_element (type);
1001 for (i = 0; i < array->n_children; i++)
1005 if (!(child = ast_get_value (array->children[i], childtype, error)))
1007 g_variant_builder_clear (&builder);
1011 g_variant_builder_add_value (&builder, child);
1014 return g_variant_builder_end (&builder);
1018 array_free (AST *ast)
1020 Array *array = (Array *) ast;
1022 ast_array_free (array->children, array->n_children);
1023 g_slice_free (Array, array);
1027 array_parse (TokenStream *stream,
1032 static const ASTClass array_class = {
1034 maybe_wrapper, array_get_value,
1037 gboolean need_comma = FALSE;
1040 array = g_slice_new (Array);
1041 array->ast.class = &array_class;
1042 array->children = NULL;
1043 array->n_children = 0;
1045 token_stream_assert (stream, "[");
1046 while (!token_stream_consume (stream, "]"))
1051 !token_stream_require (stream, ",",
1052 " or ']' to follow array element",
1056 child = parse (stream, max_depth - 1, app, error);
1061 ast_array_append (&array->children, &array->n_children, child);
1065 return (AST *) array;
1068 ast_array_free (array->children, array->n_children);
1069 g_slice_free (Array, array);
1083 tuple_get_pattern (AST *ast,
1086 Tuple *tuple = (Tuple *) ast;
1087 gchar *result = NULL;
1091 parts = g_new (gchar *, tuple->n_children + 4);
1092 parts[tuple->n_children + 1] = (gchar *) ")";
1093 parts[tuple->n_children + 2] = NULL;
1094 parts[0] = (gchar *) "M(";
1096 for (i = 0; i < tuple->n_children; i++)
1097 if (!(parts[i + 1] = ast_get_pattern (tuple->children[i], error)))
1100 if (i == tuple->n_children)
1101 result = g_strjoinv ("", parts);
1103 /* parts[0] should not be freed */
1105 g_free (parts[i--]);
1112 tuple_get_value (AST *ast,
1113 const GVariantType *type,
1116 Tuple *tuple = (Tuple *) ast;
1117 const GVariantType *childtype;
1118 GVariantBuilder builder;
1121 if (!g_variant_type_is_tuple (type))
1122 return ast_type_error (ast, type, error);
1124 g_variant_builder_init (&builder, type);
1125 childtype = g_variant_type_first (type);
1127 for (i = 0; i < tuple->n_children; i++)
1131 if (childtype == NULL)
1133 g_variant_builder_clear (&builder);
1134 return ast_type_error (ast, type, error);
1137 if (!(child = ast_get_value (tuple->children[i], childtype, error)))
1139 g_variant_builder_clear (&builder);
1143 g_variant_builder_add_value (&builder, child);
1144 childtype = g_variant_type_next (childtype);
1147 if (childtype != NULL)
1149 g_variant_builder_clear (&builder);
1150 return ast_type_error (ast, type, error);
1153 return g_variant_builder_end (&builder);
1157 tuple_free (AST *ast)
1159 Tuple *tuple = (Tuple *) ast;
1161 ast_array_free (tuple->children, tuple->n_children);
1162 g_slice_free (Tuple, tuple);
1166 tuple_parse (TokenStream *stream,
1171 static const ASTClass tuple_class = {
1173 maybe_wrapper, tuple_get_value,
1176 gboolean need_comma = FALSE;
1177 gboolean first = TRUE;
1180 tuple = g_slice_new (Tuple);
1181 tuple->ast.class = &tuple_class;
1182 tuple->children = NULL;
1183 tuple->n_children = 0;
1185 token_stream_assert (stream, "(");
1186 while (!token_stream_consume (stream, ")"))
1191 !token_stream_require (stream, ",",
1192 " or ')' to follow tuple element",
1196 child = parse (stream, max_depth - 1, app, error);
1201 ast_array_append (&tuple->children, &tuple->n_children, child);
1203 /* the first time, we absolutely require a comma, so grab it here
1204 * and leave need_comma = FALSE so that the code above doesn't
1205 * require a second comma.
1207 * the second and remaining times, we set need_comma = TRUE.
1211 if (!token_stream_require (stream, ",",
1212 " after first tuple element", error))
1221 return (AST *) tuple;
1224 ast_array_free (tuple->children, tuple->n_children);
1225 g_slice_free (Tuple, tuple);
1238 variant_get_pattern (AST *ast,
1241 return g_strdup ("Mv");
1245 variant_get_value (AST *ast,
1246 const GVariantType *type,
1249 Variant *variant = (Variant *) ast;
1252 if (!g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
1253 return ast_type_error (ast, type, error);
1255 child = ast_resolve (variant->value, error);
1260 return g_variant_new_variant (child);
1264 variant_free (AST *ast)
1266 Variant *variant = (Variant *) ast;
1268 ast_free (variant->value);
1269 g_slice_free (Variant, variant);
1273 variant_parse (TokenStream *stream,
1278 static const ASTClass variant_class = {
1279 variant_get_pattern,
1280 maybe_wrapper, variant_get_value,
1286 token_stream_assert (stream, "<");
1287 value = parse (stream, max_depth - 1, app, error);
1292 if (!token_stream_require (stream, ">", " to follow variant value", error))
1298 variant = g_slice_new (Variant);
1299 variant->ast.class = &variant_class;
1300 variant->value = value;
1302 return (AST *) variant;
1315 dictionary_get_pattern (AST *ast,
1318 Dictionary *dict = (Dictionary *) ast;
1319 gchar *value_pattern;
1324 if (dict->n_children == 0)
1325 return g_strdup ("Ma{**}");
1327 key_pattern = ast_array_get_pattern (dict->keys,
1328 abs (dict->n_children),
1331 if (key_pattern == NULL)
1334 /* we can not have maybe keys */
1335 if (key_pattern[0] == 'M')
1336 key_char = key_pattern[1];
1338 key_char = key_pattern[0];
1340 g_free (key_pattern);
1343 * plus undetermined number type and undetermined string type.
1345 if (!strchr ("bynqiuxthdsogNS", key_char))
1347 ast_set_error (ast, error, NULL,
1348 G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED,
1349 "dictionary keys must have basic types");
1353 value_pattern = ast_get_pattern (dict->values[0], error);
1355 if (value_pattern == NULL)
1358 result = g_strdup_printf ("M%s{%c%s}",
1359 dict->n_children > 0 ? "a" : "",
1360 key_char, value_pattern);
1361 g_free (value_pattern);
1367 dictionary_get_value (AST *ast,
1368 const GVariantType *type,
1371 Dictionary *dict = (Dictionary *) ast;
1373 if (dict->n_children == -1)
1375 const GVariantType *subtype;
1376 GVariantBuilder builder;
1379 if (!g_variant_type_is_dict_entry (type))
1380 return ast_type_error (ast, type, error);
1382 g_variant_builder_init (&builder, type);
1384 subtype = g_variant_type_key (type);
1385 if (!(subvalue = ast_get_value (dict->keys[0], subtype, error)))
1387 g_variant_builder_clear (&builder);
1390 g_variant_builder_add_value (&builder, subvalue);
1392 subtype = g_variant_type_value (type);
1393 if (!(subvalue = ast_get_value (dict->values[0], subtype, error)))
1395 g_variant_builder_clear (&builder);
1398 g_variant_builder_add_value (&builder, subvalue);
1400 return g_variant_builder_end (&builder);
1404 const GVariantType *entry, *key, *val;
1405 GVariantBuilder builder;
1408 if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
1409 return ast_type_error (ast, type, error);
1411 entry = g_variant_type_element (type);
1412 key = g_variant_type_key (entry);
1413 val = g_variant_type_value (entry);
1415 g_variant_builder_init (&builder, type);
1417 for (i = 0; i < dict->n_children; i++)
1421 g_variant_builder_open (&builder, entry);
1423 if (!(subvalue = ast_get_value (dict->keys[i], key, error)))
1425 g_variant_builder_clear (&builder);
1428 g_variant_builder_add_value (&builder, subvalue);
1430 if (!(subvalue = ast_get_value (dict->values[i], val, error)))
1432 g_variant_builder_clear (&builder);
1435 g_variant_builder_add_value (&builder, subvalue);
1436 g_variant_builder_close (&builder);
1439 return g_variant_builder_end (&builder);
1444 dictionary_free (AST *ast)
1446 Dictionary *dict = (Dictionary *) ast;
1449 if (dict->n_children > -1)
1450 n_children = dict->n_children;
1454 ast_array_free (dict->keys, n_children);
1455 ast_array_free (dict->values, n_children);
1456 g_slice_free (Dictionary, dict);
1460 dictionary_parse (TokenStream *stream,
1465 static const ASTClass dictionary_class = {
1466 dictionary_get_pattern,
1467 maybe_wrapper, dictionary_get_value,
1470 gint n_keys, n_values;
1475 dict = g_slice_new (Dictionary);
1476 dict->ast.class = &dictionary_class;
1478 dict->values = NULL;
1479 n_keys = n_values = 0;
1481 token_stream_assert (stream, "{");
1483 if (token_stream_consume (stream, "}"))
1485 dict->n_children = 0;
1486 return (AST *) dict;
1489 if ((first = parse (stream, max_depth - 1, app, error)) == NULL)
1492 ast_array_append (&dict->keys, &n_keys, first);
1494 only_one = token_stream_consume (stream, ",");
1496 !token_stream_require (stream, ":",
1497 " or ',' to follow dictionary entry key",
1501 if ((first = parse (stream, max_depth - 1, app, error)) == NULL)
1504 ast_array_append (&dict->values, &n_values, first);
1508 if (!token_stream_require (stream, "}", " at end of dictionary entry",
1512 g_assert (n_keys == 1 && n_values == 1);
1513 dict->n_children = -1;
1515 return (AST *) dict;
1518 while (!token_stream_consume (stream, "}"))
1522 if (!token_stream_require (stream, ",",
1523 " or '}' to follow dictionary entry", error))
1526 child = parse (stream, max_depth - 1, app, error);
1531 ast_array_append (&dict->keys, &n_keys, child);
1533 if (!token_stream_require (stream, ":",
1534 " to follow dictionary entry key", error))
1537 child = parse (stream, max_depth - 1, app, error);
1542 ast_array_append (&dict->values, &n_values, child);
1545 g_assert (n_keys == n_values);
1546 dict->n_children = n_keys;
1548 return (AST *) dict;
1551 ast_array_free (dict->keys, n_keys);
1552 ast_array_free (dict->values, n_values);
1553 g_slice_free (Dictionary, dict);
1565 string_get_pattern (AST *ast,
1568 return g_strdup ("MS");
1572 string_get_value (AST *ast,
1573 const GVariantType *type,
1576 String *string = (String *) ast;
1578 if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
1579 return g_variant_new_string (string->string);
1581 else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
1583 if (!g_variant_is_object_path (string->string))
1585 ast_set_error (ast, error, NULL,
1586 G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH,
1587 "not a valid object path");
1591 return g_variant_new_object_path (string->string);
1594 else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
1596 if (!g_variant_is_signature (string->string))
1598 ast_set_error (ast, error, NULL,
1599 G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE,
1600 "not a valid signature");
1604 return g_variant_new_signature (string->string);
1608 return ast_type_error (ast, type, error);
1612 string_free (AST *ast)
1614 String *string = (String *) ast;
1616 g_free (string->string);
1617 g_slice_free (String, string);
1620 /* Accepts exactly @length hexadecimal digits. No leading sign or `0x`/`0X` prefix allowed.
1621 * No leading/trailing space allowed. */
1623 unicode_unescape (const gchar *src,
1634 gsize n_valid_chars;
1638 g_assert (length < sizeof (buffer));
1639 strncpy (buffer, src + *src_ofs, length);
1640 buffer[length] = '\0';
1642 for (n_valid_chars = 0; n_valid_chars < length; n_valid_chars++)
1643 if (!g_ascii_isxdigit (buffer[n_valid_chars]))
1646 if (n_valid_chars == length)
1647 value = g_ascii_strtoull (buffer, &end, 0x10);
1649 if (value == 0 || end != buffer + length)
1651 SourceRef escape_ref;
1654 escape_ref.start += *src_ofs;
1655 escape_ref.end = escape_ref.start + n_valid_chars;
1657 parser_set_error (error, &escape_ref, NULL,
1658 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1659 "invalid %" G_GSIZE_FORMAT "-character unicode escape", length);
1663 g_assert (value <= G_MAXUINT32);
1665 *dest_ofs += g_unichar_to_utf8 (value, dest + *dest_ofs);
1672 string_parse (TokenStream *stream,
1676 static const ASTClass string_class = {
1678 maybe_wrapper, string_get_value,
1689 token_stream_start_ref (stream, &ref);
1690 token = token_stream_get (stream);
1691 token_stream_end_ref (stream, &ref);
1692 length = strlen (token);
1695 str = g_malloc (length);
1696 g_assert (quote == '"' || quote == '\'');
1699 while (token[i] != quote)
1703 parser_set_error (error, &ref, NULL,
1704 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1705 "unterminated string constant");
1714 parser_set_error (error, &ref, NULL,
1715 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1716 "unterminated string constant");
1722 if (!unicode_unescape (token, &i, str, &j, 4, &ref, error))
1731 if (!unicode_unescape (token, &i, str, &j, 8, &ref, error))
1739 case 'a': str[j++] = '\a'; i++; continue;
1740 case 'b': str[j++] = '\b'; i++; continue;
1741 case 'f': str[j++] = '\f'; i++; continue;
1742 case 'n': str[j++] = '\n'; i++; continue;
1743 case 'r': str[j++] = '\r'; i++; continue;
1744 case 't': str[j++] = '\t'; i++; continue;
1745 case 'v': str[j++] = '\v'; i++; continue;
1746 case '\n': i++; continue;
1752 str[j++] = token[i++];
1757 string = g_slice_new (String);
1758 string->ast.class = &string_class;
1759 string->string = str;
1761 token_stream_next (stream);
1763 return (AST *) string;
1773 bytestring_get_pattern (AST *ast,
1776 return g_strdup ("May");
1780 bytestring_get_value (AST *ast,
1781 const GVariantType *type,
1784 ByteString *string = (ByteString *) ast;
1786 if (!g_variant_type_equal (type, G_VARIANT_TYPE_BYTESTRING))
1787 return ast_type_error (ast, type, error);
1789 return g_variant_new_bytestring (string->string);
1793 bytestring_free (AST *ast)
1795 ByteString *string = (ByteString *) ast;
1797 g_free (string->string);
1798 g_slice_free (ByteString, string);
1802 bytestring_parse (TokenStream *stream,
1806 static const ASTClass bytestring_class = {
1807 bytestring_get_pattern,
1808 maybe_wrapper, bytestring_get_value,
1819 token_stream_start_ref (stream, &ref);
1820 token = token_stream_get (stream);
1821 token_stream_end_ref (stream, &ref);
1822 g_assert (token[0] == 'b');
1823 length = strlen (token);
1826 str = g_malloc (length);
1827 g_assert (quote == '"' || quote == '\'');
1830 while (token[i] != quote)
1834 parser_set_error (error, &ref, NULL,
1835 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1836 "unterminated string constant");
1845 parser_set_error (error, &ref, NULL,
1846 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1847 "unterminated string constant");
1852 case '0': case '1': case '2': case '3':
1853 case '4': case '5': case '6': case '7':
1855 /* up to 3 characters */
1856 guchar val = token[i++] - '0';
1858 if ('0' <= token[i] && token[i] < '8')
1859 val = (val << 3) | (token[i++] - '0');
1861 if ('0' <= token[i] && token[i] < '8')
1862 val = (val << 3) | (token[i++] - '0');
1868 case 'a': str[j++] = '\a'; i++; continue;
1869 case 'b': str[j++] = '\b'; i++; continue;
1870 case 'f': str[j++] = '\f'; i++; continue;
1871 case 'n': str[j++] = '\n'; i++; continue;
1872 case 'r': str[j++] = '\r'; i++; continue;
1873 case 't': str[j++] = '\t'; i++; continue;
1874 case 'v': str[j++] = '\v'; i++; continue;
1875 case '\n': i++; continue;
1881 str[j++] = token[i++];
1886 string = g_slice_new (ByteString);
1887 string->ast.class = &bytestring_class;
1888 string->string = str;
1890 token_stream_next (stream);
1892 return (AST *) string;
1903 number_get_pattern (AST *ast,
1906 Number *number = (Number *) ast;
1908 if (strchr (number->token, '.') ||
1909 (!g_str_has_prefix (number->token, "0x") && strchr (number->token, 'e')) ||
1910 strstr (number->token, "inf") ||
1911 strstr (number->token, "nan"))
1912 return g_strdup ("Md");
1914 return g_strdup ("MN");
1918 number_overflow (AST *ast,
1919 const GVariantType *type,
1922 ast_set_error (ast, error, NULL,
1923 G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE,
1924 "number out of range for type '%c'",
1925 g_variant_type_peek_string (type)[0]);
1930 number_get_value (AST *ast,
1931 const GVariantType *type,
1934 Number *number = (Number *) ast;
1942 token = number->token;
1944 if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
1949 dbl_val = g_ascii_strtod (token, &end);
1950 if (dbl_val != 0.0 && errno == ERANGE)
1952 ast_set_error (ast, error, NULL,
1953 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1954 "number too big for any type");
1958 /* silence uninitialised warnings... */
1965 negative = token[0] == '-';
1966 if (token[0] == '-')
1970 abs_val = g_ascii_strtoull (token, &end, 0);
1971 if (abs_val == G_MAXUINT64 && errno == ERANGE)
1973 ast_set_error (ast, error, NULL,
1974 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1975 "integer too big for any type");
1982 /* silence uninitialised warning... */
1990 ref = ast->source_ref;
1991 ref.start += end - number->token;
1992 ref.end = ref.start + 1;
1994 parser_set_error (error, &ref, NULL,
1995 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1996 "invalid character in number");
2001 return g_variant_new_double (dbl_val);
2003 switch (*g_variant_type_peek_string (type))
2006 if (negative || abs_val > G_MAXUINT8)
2007 return number_overflow (ast, type, error);
2008 return g_variant_new_byte (abs_val);
2011 if (abs_val - negative > G_MAXINT16)
2012 return number_overflow (ast, type, error);
2013 if (negative && abs_val > G_MAXINT16)
2014 return g_variant_new_int16 (G_MININT16);
2015 return g_variant_new_int16 (negative ?
2016 -((gint16) abs_val) : ((gint16) abs_val));
2019 if (negative || abs_val > G_MAXUINT16)
2020 return number_overflow (ast, type, error);
2021 return g_variant_new_uint16 (abs_val);
2024 if (abs_val - negative > G_MAXINT32)
2025 return number_overflow (ast, type, error);
2026 if (negative && abs_val > G_MAXINT32)
2027 return g_variant_new_int32 (G_MININT32);
2028 return g_variant_new_int32 (negative ?
2029 -((gint32) abs_val) : ((gint32) abs_val));
2032 if (negative || abs_val > G_MAXUINT32)
2033 return number_overflow (ast, type, error);
2034 return g_variant_new_uint32 (abs_val);
2037 if (abs_val - negative > G_MAXINT64)
2038 return number_overflow (ast, type, error);
2039 if (negative && abs_val > G_MAXINT64)
2040 return g_variant_new_int64 (G_MININT64);
2041 return g_variant_new_int64 (negative ?
2042 -((gint64) abs_val) : ((gint64) abs_val));
2046 return number_overflow (ast, type, error);
2047 return g_variant_new_uint64 (abs_val);
2050 if (abs_val - negative > G_MAXINT32)
2051 return number_overflow (ast, type, error);
2052 if (negative && abs_val > G_MAXINT32)
2053 return g_variant_new_handle (G_MININT32);
2054 return g_variant_new_handle (negative ?
2055 -((gint32) abs_val) : ((gint32) abs_val));
2058 return ast_type_error (ast, type, error);
2063 number_free (AST *ast)
2065 Number *number = (Number *) ast;
2067 g_free (number->token);
2068 g_slice_free (Number, number);
2072 number_parse (TokenStream *stream,
2076 static const ASTClass number_class = {
2078 maybe_wrapper, number_get_value,
2083 number = g_slice_new (Number);
2084 number->ast.class = &number_class;
2085 number->token = token_stream_get (stream);
2086 token_stream_next (stream);
2088 return (AST *) number;
2098 boolean_get_pattern (AST *ast,
2101 return g_strdup ("Mb");
2105 boolean_get_value (AST *ast,
2106 const GVariantType *type,
2109 Boolean *boolean = (Boolean *) ast;
2111 if (!g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
2112 return ast_type_error (ast, type, error);
2114 return g_variant_new_boolean (boolean->value);
2118 boolean_free (AST *ast)
2120 Boolean *boolean = (Boolean *) ast;
2122 g_slice_free (Boolean, boolean);
2126 boolean_new (gboolean value)
2128 static const ASTClass boolean_class = {
2129 boolean_get_pattern,
2130 maybe_wrapper, boolean_get_value,
2135 boolean = g_slice_new (Boolean);
2136 boolean->ast.class = &boolean_class;
2137 boolean->value = value;
2139 return (AST *) boolean;
2150 positional_get_pattern (AST *ast,
2153 Positional *positional = (Positional *) ast;
2155 return g_strdup (g_variant_get_type_string (positional->value));
2159 positional_get_value (AST *ast,
2160 const GVariantType *type,
2163 Positional *positional = (Positional *) ast;
2166 g_assert (positional->value != NULL);
2168 if G_UNLIKELY (!g_variant_is_of_type (positional->value, type))
2169 return ast_type_error (ast, type, error);
2171 /* NOTE: if _get is called more than once then
2172 * things get messed up with respect to floating refs.
2174 * fortunately, this function should only ever get called once.
2176 g_assert (positional->value != NULL);
2177 value = positional->value;
2178 positional->value = NULL;
2184 positional_free (AST *ast)
2186 Positional *positional = (Positional *) ast;
2188 /* if positional->value is set, just leave it.
2189 * memory management doesn't matter in case of programmer error.
2191 g_slice_free (Positional, positional);
2195 positional_parse (TokenStream *stream,
2199 static const ASTClass positional_class = {
2200 positional_get_pattern,
2201 positional_get_value, NULL,
2204 Positional *positional;
2205 const gchar *endptr;
2208 token = token_stream_get (stream);
2209 g_assert (token[0] == '%');
2211 positional = g_slice_new (Positional);
2212 positional->ast.class = &positional_class;
2213 positional->value = g_variant_new_va (token + 1, &endptr, app);
2215 if (*endptr || positional->value == NULL)
2217 token_stream_set_error (stream, error, TRUE,
2218 G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING,
2219 "invalid GVariant format string");
2220 /* memory management doesn't matter in case of programmer error. */
2224 token_stream_next (stream);
2227 return (AST *) positional;
2239 typedecl_get_pattern (AST *ast,
2242 TypeDecl *decl = (TypeDecl *) ast;
2244 return g_variant_type_dup_string (decl->type);
2248 typedecl_get_value (AST *ast,
2249 const GVariantType *type,
2252 TypeDecl *decl = (TypeDecl *) ast;
2254 return ast_get_value (decl->child, type, error);
2258 typedecl_free (AST *ast)
2260 TypeDecl *decl = (TypeDecl *) ast;
2262 ast_free (decl->child);
2263 g_variant_type_free (decl->type);
2264 g_slice_free (TypeDecl, decl);
2268 typedecl_parse (TokenStream *stream,
2273 static const ASTClass typedecl_class = {
2274 typedecl_get_pattern,
2275 typedecl_get_value, NULL,
2282 if (token_stream_peek (stream, '@'))
2286 token = token_stream_get (stream);
2288 if (!g_variant_type_string_is_valid (token + 1))
2290 token_stream_set_error (stream, error, TRUE,
2291 G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING,
2292 "invalid type declaration");
2298 if (g_variant_type_string_get_depth_ (token + 1) > max_depth)
2300 token_stream_set_error (stream, error, TRUE,
2301 G_VARIANT_PARSE_ERROR_RECURSION,
2302 "type declaration recurses too deeply");
2308 type = g_variant_type_new (token + 1);
2310 if (!g_variant_type_is_definite (type))
2312 token_stream_set_error (stream, error, TRUE,
2313 G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED,
2314 "type declarations must be definite");
2315 g_variant_type_free (type);
2321 token_stream_next (stream);
2326 if (token_stream_consume (stream, "boolean"))
2327 type = g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
2329 else if (token_stream_consume (stream, "byte"))
2330 type = g_variant_type_copy (G_VARIANT_TYPE_BYTE);
2332 else if (token_stream_consume (stream, "int16"))
2333 type = g_variant_type_copy (G_VARIANT_TYPE_INT16);
2335 else if (token_stream_consume (stream, "uint16"))
2336 type = g_variant_type_copy (G_VARIANT_TYPE_UINT16);
2338 else if (token_stream_consume (stream, "int32"))
2339 type = g_variant_type_copy (G_VARIANT_TYPE_INT32);
2341 else if (token_stream_consume (stream, "handle"))
2342 type = g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
2344 else if (token_stream_consume (stream, "uint32"))
2345 type = g_variant_type_copy (G_VARIANT_TYPE_UINT32);
2347 else if (token_stream_consume (stream, "int64"))
2348 type = g_variant_type_copy (G_VARIANT_TYPE_INT64);
2350 else if (token_stream_consume (stream, "uint64"))
2351 type = g_variant_type_copy (G_VARIANT_TYPE_UINT64);
2353 else if (token_stream_consume (stream, "double"))
2354 type = g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
2356 else if (token_stream_consume (stream, "string"))
2357 type = g_variant_type_copy (G_VARIANT_TYPE_STRING);
2359 else if (token_stream_consume (stream, "objectpath"))
2360 type = g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
2362 else if (token_stream_consume (stream, "signature"))
2363 type = g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
2367 token_stream_set_error (stream, error, TRUE,
2368 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
2374 if ((child = parse (stream, max_depth - 1, app, error)) == NULL)
2376 g_variant_type_free (type);
2380 decl = g_slice_new (TypeDecl);
2381 decl->ast.class = &typedecl_class;
2383 decl->child = child;
2385 return (AST *) decl;
2389 parse (TokenStream *stream,
2394 SourceRef source_ref;
2399 token_stream_set_error (stream, error, FALSE,
2400 G_VARIANT_PARSE_ERROR_RECURSION,
2401 "variant nested too deeply");
2405 token_stream_prepare (stream);
2406 token_stream_start_ref (stream, &source_ref);
2408 if (token_stream_peek (stream, '['))
2409 result = array_parse (stream, max_depth, app, error);
2411 else if (token_stream_peek (stream, '('))
2412 result = tuple_parse (stream, max_depth, app, error);
2414 else if (token_stream_peek (stream, '<'))
2415 result = variant_parse (stream, max_depth, app, error);
2417 else if (token_stream_peek (stream, '{'))
2418 result = dictionary_parse (stream, max_depth, app, error);
2420 else if (app && token_stream_peek (stream, '%'))
2421 result = positional_parse (stream, app, error);
2423 else if (token_stream_consume (stream, "true"))
2424 result = boolean_new (TRUE);
2426 else if (token_stream_consume (stream, "false"))
2427 result = boolean_new (FALSE);
2429 else if (token_stream_is_numeric (stream) ||
2430 token_stream_peek_string (stream, "inf") ||
2431 token_stream_peek_string (stream, "nan"))
2432 result = number_parse (stream, app, error);
2434 else if (token_stream_peek (stream, 'n') ||
2435 token_stream_peek (stream, 'j'))
2436 result = maybe_parse (stream, max_depth, app, error);
2438 else if (token_stream_peek (stream, '@') ||
2439 token_stream_is_keyword (stream))
2440 result = typedecl_parse (stream, max_depth, app, error);
2442 else if (token_stream_peek (stream, '\'') ||
2443 token_stream_peek (stream, '"'))
2444 result = string_parse (stream, app, error);
2446 else if (token_stream_peek2 (stream, 'b', '\'') ||
2447 token_stream_peek2 (stream, 'b', '"'))
2448 result = bytestring_parse (stream, app, error);
2452 token_stream_set_error (stream, error, FALSE,
2453 G_VARIANT_PARSE_ERROR_VALUE_EXPECTED,
2460 token_stream_end_ref (stream, &source_ref);
2461 result->source_ref = source_ref;
2469 * @type: (nullable): a #GVariantType, or %NULL
2470 * @text: a string containing a GVariant in text form
2471 * @limit: (nullable): a pointer to the end of @text, or %NULL
2472 * @endptr: (nullable): a location to store the end pointer, or %NULL
2473 * @error: (nullable): a pointer to a %NULL #GError pointer, or %NULL
2475 * Parses a #GVariant from a text representation.
2477 * A single #GVariant is parsed from the content of @text.
2479 * The format is described [here][gvariant-text].
2481 * The memory at @limit will never be accessed and the parser behaves as
2482 * if the character at @limit is the nul terminator. This has the
2483 * effect of bounding @text.
2485 * If @endptr is non-%NULL then @text is permitted to contain data
2486 * following the value that this function parses and @endptr will be
2487 * updated to point to the first character past the end of the text
2488 * parsed by this function. If @endptr is %NULL and there is extra data
2489 * then an error is returned.
2491 * If @type is non-%NULL then the value will be parsed to have that
2492 * type. This may result in additional parse errors (in the case that
2493 * the parsed value doesn't fit the type) but may also result in fewer
2494 * errors (in the case that the type would have been ambiguous, such as
2495 * with empty arrays).
2497 * In the event that the parsing is successful, the resulting #GVariant
2498 * is returned. It is never floating, and must be freed with
2499 * g_variant_unref().
2501 * In case of any error, %NULL will be returned. If @error is non-%NULL
2502 * then it will be set to reflect the error that occurred.
2504 * Officially, the language understood by the parser is "any string
2505 * produced by g_variant_print()".
2507 * There may be implementation specific restrictions on deeply nested values,
2508 * which would result in a %G_VARIANT_PARSE_ERROR_RECURSION error. #GVariant is
2509 * guaranteed to handle nesting up to at least 64 levels.
2511 * Returns: a non-floating reference to a #GVariant, or %NULL
2514 g_variant_parse (const GVariantType *type,
2517 const gchar **endptr,
2520 TokenStream stream = { 0, };
2521 GVariant *result = NULL;
2524 g_return_val_if_fail (text != NULL, NULL);
2525 g_return_val_if_fail (text == limit || text != NULL, NULL);
2527 stream.start = text;
2528 stream.stream = text;
2531 if ((ast = parse (&stream, G_VARIANT_MAX_RECURSION_DEPTH, NULL, error)))
2534 result = ast_resolve (ast, error);
2536 result = ast_get_value (ast, type, error);
2540 g_variant_ref_sink (result);
2544 while (stream.stream != limit &&
2545 g_ascii_isspace (*stream.stream))
2548 if (stream.stream != limit && *stream.stream != '\0')
2550 SourceRef ref = { stream.stream - text,
2551 stream.stream - text };
2553 parser_set_error (error, &ref, NULL,
2554 G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END,
2555 "expected end of input");
2556 g_variant_unref (result);
2562 *endptr = stream.stream;
2572 * g_variant_new_parsed_va:
2573 * @format: a text format #GVariant
2574 * @app: a pointer to a #va_list
2576 * Parses @format and returns the result.
2578 * This is the version of g_variant_new_parsed() intended to be used
2581 * The return value will be floating if it was a newly created GVariant
2582 * instance. In the case that @format simply specified the collection
2583 * of a #GVariant pointer (eg: @format was "%*") then the collected
2584 * #GVariant pointer will be returned unmodified, without adding any
2585 * additional references.
2587 * Note that the arguments in @app must be of the correct width for their types
2588 * specified in @format when collected into the #va_list. See
2589 * the [GVariant varargs documentation][gvariant-varargs].
2591 * In order to behave correctly in all cases it is necessary for the
2592 * calling function to g_variant_ref_sink() the return result before
2593 * returning control to the user that originally provided the pointer.
2594 * At this point, the caller will have their own full reference to the
2595 * result. This can also be done by adding the result to a container,
2596 * or by passing it to another g_variant_new() call.
2598 * Returns: a new, usually floating, #GVariant
2601 g_variant_new_parsed_va (const gchar *format,
2604 TokenStream stream = { 0, };
2605 GVariant *result = NULL;
2606 GError *error = NULL;
2609 g_return_val_if_fail (format != NULL, NULL);
2610 g_return_val_if_fail (app != NULL, NULL);
2612 stream.start = format;
2613 stream.stream = format;
2616 if ((ast = parse (&stream, G_VARIANT_MAX_RECURSION_DEPTH, app, &error)))
2618 result = ast_resolve (ast, &error);
2623 g_error ("g_variant_new_parsed: %s", error->message);
2626 g_error ("g_variant_new_parsed: trailing text after value");
2628 g_clear_error (&error);
2634 * g_variant_new_parsed:
2635 * @format: a text format #GVariant
2636 * @...: arguments as per @format
2638 * Parses @format and returns the result.
2640 * @format must be a text format #GVariant with one extension: at any
2641 * point that a value may appear in the text, a '%' character followed
2642 * by a GVariant format string (as per g_variant_new()) may appear. In
2643 * that case, the same arguments are collected from the argument list as
2644 * g_variant_new() would have collected.
2646 * Note that the arguments must be of the correct width for their types
2647 * specified in @format. This can be achieved by casting them. See
2648 * the [GVariant varargs documentation][gvariant-varargs].
2650 * Consider this simple example:
2651 * |[<!-- language="C" -->
2652 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2655 * In the example, the variable argument parameters are collected and
2656 * filled in as if they were part of the original string to produce the
2658 * |[<!-- language="C" -->
2659 * [('one', 1), ('two', 2), ('three', 3)]
2662 * This function is intended only to be used with @format as a string
2663 * literal. Any parse error is fatal to the calling process. If you
2664 * want to parse data from untrusted sources, use g_variant_parse().
2666 * You may not use this function to return, unmodified, a single
2667 * #GVariant pointer from the argument list. ie: @format may not solely
2668 * be anything along the lines of "%*", "%?", "\%r", or anything starting
2671 * Returns: a new floating #GVariant instance
2674 g_variant_new_parsed (const gchar *format,
2680 va_start (ap, format);
2681 result = g_variant_new_parsed_va (format, &ap);
2688 * g_variant_builder_add_parsed:
2689 * @builder: a #GVariantBuilder
2690 * @format: a text format #GVariant
2691 * @...: arguments as per @format
2693 * Adds to a #GVariantBuilder.
2695 * This call is a convenience wrapper that is exactly equivalent to
2696 * calling g_variant_new_parsed() followed by
2697 * g_variant_builder_add_value().
2699 * Note that the arguments must be of the correct width for their types
2700 * specified in @format_string. This can be achieved by casting them. See
2701 * the [GVariant varargs documentation][gvariant-varargs].
2703 * This function might be used as follows:
2705 * |[<!-- language="C" -->
2707 * make_pointless_dictionary (void)
2709 * GVariantBuilder builder;
2712 * g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2713 * g_variant_builder_add_parsed (&builder, "{'width', <%i>}", 600);
2714 * g_variant_builder_add_parsed (&builder, "{'title', <%s>}", "foo");
2715 * g_variant_builder_add_parsed (&builder, "{'transparency', <0.5>}");
2716 * return g_variant_builder_end (&builder);
2723 g_variant_builder_add_parsed (GVariantBuilder *builder,
2724 const gchar *format,
2729 va_start (ap, format);
2730 g_variant_builder_add_value (builder, g_variant_new_parsed_va (format, &ap));
2735 parse_num (const gchar *num,
2742 bignum = g_ascii_strtoll (num, &endptr, 10);
2744 if (endptr != limit)
2747 if (bignum < 0 || bignum > G_MAXINT)
2750 *result = (guint) bignum;
2756 add_last_line (GString *err,
2759 const gchar *last_nl;
2763 /* This is an error at the end of input. If we have a file
2764 * with newlines, that's probably the empty string after the
2765 * last newline, which is not the most useful thing to show.
2767 * Instead, show the last line of non-whitespace that we have
2768 * and put the pointer at the end of it.
2770 chomped = g_strchomp (g_strdup (str));
2771 last_nl = strrchr (chomped, '\n');
2772 if (last_nl == NULL)
2777 /* Print the last line like so:
2782 g_string_append (err, " ");
2784 g_string_append (err, last_nl);
2786 g_string_append (err, "(empty input)");
2787 g_string_append (err, "\n ");
2788 for (i = 0; last_nl[i]; i++)
2789 g_string_append_c (err, ' ');
2790 g_string_append (err, "^\n");
2795 add_lines_from_range (GString *err,
2797 const gchar *start1,
2799 const gchar *start2,
2802 while (str < end1 || str < end2)
2806 nl = str + strcspn (str, "\n");
2808 if ((start1 < nl && str < end1) || (start2 < nl && str < end2))
2812 /* We're going to print this line */
2813 g_string_append (err, " ");
2814 g_string_append_len (err, str, nl - str);
2815 g_string_append (err, "\n ");
2817 /* And add underlines... */
2818 for (s = str; s < nl; s++)
2820 if ((start1 <= s && s < end1) || (start2 <= s && s < end2))
2821 g_string_append_c (err, '^');
2823 g_string_append_c (err, ' ');
2825 g_string_append_c (err, '\n');
2836 * g_variant_parse_error_print_context:
2837 * @error: a #GError from the #GVariantParseError domain
2838 * @source_str: the string that was given to the parser
2840 * Pretty-prints a message showing the context of a #GVariant parse
2841 * error within the string for which parsing was attempted.
2843 * The resulting string is suitable for output to the console or other
2844 * monospace media where newlines are treated in the usual way.
2846 * The message will typically look something like one of the following:
2849 * unterminated string constant:
2857 * unable to find a common type:
2862 * The format of the message may change in a future version.
2864 * @error must have come from a failed attempt to g_variant_parse() and
2865 * @source_str must be exactly the same string that caused the error.
2866 * If @source_str was not nul-terminated when you passed it to
2867 * g_variant_parse() then you must add nul termination before using this
2870 * Returns: (transfer full): the printed message
2875 g_variant_parse_error_print_context (GError *error,
2876 const gchar *source_str)
2878 const gchar *colon, *dash, *comma;
2879 gboolean success = FALSE;
2882 g_return_val_if_fail (error->domain == G_VARIANT_PARSE_ERROR, FALSE);
2884 /* We can only have a limited number of possible types of ranges
2885 * emitted from the parser:
2887 * - a: -- usually errors from the tokeniser (eof, invalid char, etc.)
2888 * - a-b: -- usually errors from handling one single token
2889 * - a-b,c-d: -- errors involving two tokens (ie: type inferencing)
2891 * We never see, for example "a,c".
2894 colon = strchr (error->message, ':');
2895 dash = strchr (error->message, '-');
2896 comma = strchr (error->message, ',');
2901 err = g_string_new (colon + 1);
2902 g_string_append (err, ":\n");
2904 if (dash == NULL || colon < dash)
2908 /* we have a single point */
2909 if (!parse_num (error->message, colon, &point))
2912 if (point >= strlen (source_str))
2913 /* the error is at the end of the input */
2914 add_last_line (err, source_str);
2916 /* otherwise just treat it as an error at a thin range */
2917 add_lines_from_range (err, source_str, source_str + point, source_str + point + 1, NULL, NULL);
2921 /* We have one or two ranges... */
2922 if (comma && comma < colon)
2924 guint start1, end1, start2, end2;
2928 dash2 = strchr (comma, '-');
2930 if (!parse_num (error->message, dash, &start1) || !parse_num (dash + 1, comma, &end1) ||
2931 !parse_num (comma + 1, dash2, &start2) || !parse_num (dash2 + 1, colon, &end2))
2934 add_lines_from_range (err, source_str,
2935 source_str + start1, source_str + end1,
2936 source_str + start2, source_str + end2);
2943 if (!parse_num (error->message, dash, &start) || !parse_num (dash + 1, colon, &end))
2946 add_lines_from_range (err, source_str, source_str + start, source_str + end, NULL, NULL);
2953 return g_string_free (err, !success);