Branch data Line data Source code
1 : : /*
2 : : * Copyright © 2009, 2010 Codethink Limited
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
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.
10 : : *
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.
15 : : *
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/>.
18 : : *
19 : : * Author: Ryan Lortie <desrt@desrt.ca>
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include <stdlib.h>
25 : : #include <string.h>
26 : : #include <errno.h>
27 : :
28 : : #include "gerror.h"
29 : : #include "gquark.h"
30 : : #include "gstring.h"
31 : : #include "gstrfuncs.h"
32 : : #include "gtestutils.h"
33 : : #include "gvariant.h"
34 : : #include "glib/gvariant-core.h"
35 : : #include "gvariant-internal.h"
36 : : #include "gvarianttype.h"
37 : : #include "gslice.h"
38 : : #include "gthread.h"
39 : :
40 : : /*
41 : : * two-pass algorithm
42 : : * designed by ryan lortie and william hua
43 : : * designed in itb-229 and at ghazi's, 2009.
44 : : */
45 : :
46 : : /**
47 : : * G_VARIANT_PARSE_ERROR:
48 : : *
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.
52 : : **/
53 : : /**
54 : : * GVariantParseError:
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)
74 : : *
75 : : * Error codes returned by parsing text-format GVariants.
76 : : **/
77 : 289 : G_DEFINE_QUARK (g-variant-parse-error-quark, g_variant_parse_error)
78 : :
79 : : /**
80 : : * g_variant_parser_get_error_quark:
81 : : *
82 : : * Same as g_variant_error_quark().
83 : : *
84 : : * Deprecated: Use g_variant_parse_error_quark() instead.
85 : : */
86 : : GQuark
87 : 2 : g_variant_parser_get_error_quark (void)
88 : : {
89 : 2 : return g_variant_parse_error_quark ();
90 : : }
91 : :
92 : : typedef struct
93 : : {
94 : : /* Offsets from the start of the input, in bytes. Can be equal when referring
95 : : * to a point rather than a range. The invariant `end >= start` always holds. */
96 : : size_t start, end;
97 : : } SourceRef;
98 : :
99 : : G_GNUC_PRINTF(5, 0)
100 : : static void
101 : 267 : parser_set_error_va (GError **error,
102 : : SourceRef *location,
103 : : SourceRef *other,
104 : : gint code,
105 : : const gchar *format,
106 : : va_list ap)
107 : : {
108 : 267 : GString *msg = g_string_new (NULL);
109 : :
110 : 267 : if (location->start == location->end)
111 : 77 : g_string_append_printf (msg, "%" G_GSIZE_FORMAT, location->start);
112 : : else
113 : 190 : g_string_append_printf (msg, "%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT,
114 : : location->start, location->end);
115 : :
116 : 267 : if (other != NULL)
117 : : {
118 : 31 : g_assert (other->start != other->end);
119 : 31 : g_string_append_printf (msg, ",%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT,
120 : : other->start, other->end);
121 : : }
122 : : g_string_append_c (msg, ':');
123 : :
124 : 267 : g_string_append_vprintf (msg, format, ap);
125 : 267 : g_set_error_literal (error, G_VARIANT_PARSE_ERROR, code, msg->str);
126 : 267 : g_string_free (msg, TRUE);
127 : 267 : }
128 : :
129 : : G_GNUC_PRINTF(5, 6)
130 : : static void
131 : 74 : parser_set_error (GError **error,
132 : : SourceRef *location,
133 : : SourceRef *other,
134 : : gint code,
135 : : const gchar *format,
136 : : ...)
137 : : {
138 : : va_list ap;
139 : :
140 : 74 : va_start (ap, format);
141 : 74 : parser_set_error_va (error, location, other, code, format, ap);
142 : 74 : va_end (ap);
143 : 74 : }
144 : :
145 : : typedef struct
146 : : {
147 : : /* We should always have the following ordering constraint:
148 : : * start <= this <= stream <= end
149 : : * Additionally, unless in an error or EOF state, `this < stream`.
150 : : */
151 : : const gchar *start;
152 : : const gchar *stream;
153 : : const gchar *end;
154 : :
155 : : const gchar *this; /* (nullable) */
156 : : } TokenStream;
157 : :
158 : :
159 : : G_GNUC_PRINTF(5, 6)
160 : : static void
161 : 66 : token_stream_set_error (TokenStream *stream,
162 : : GError **error,
163 : : gboolean this_token,
164 : : gint code,
165 : : const gchar *format,
166 : : ...)
167 : : {
168 : : SourceRef ref;
169 : : va_list ap;
170 : :
171 : 66 : ref.start = stream->this - stream->start;
172 : :
173 : 66 : if (this_token)
174 : 14 : ref.end = stream->stream - stream->start;
175 : : else
176 : 52 : ref.end = ref.start;
177 : :
178 : 66 : va_start (ap, format);
179 : 66 : parser_set_error_va (error, &ref, NULL, code, format, ap);
180 : 66 : va_end (ap);
181 : 66 : }
182 : :
183 : : static gboolean
184 : 11682739 : token_stream_prepare (TokenStream *stream)
185 : : {
186 : 11682739 : gssize brackets = 0;
187 : : const gchar *end;
188 : :
189 : 11682739 : if (stream->this != NULL)
190 : 9732502 : return TRUE;
191 : :
192 : 2906364 : while (stream->stream != stream->end && g_ascii_isspace (*stream->stream))
193 : 956127 : stream->stream++;
194 : :
195 : 1950237 : if (stream->stream == stream->end || *stream->stream == '\0')
196 : : {
197 : 16 : stream->this = stream->stream;
198 : 16 : return FALSE;
199 : : }
200 : :
201 : 1950221 : switch (stream->stream[0])
202 : : {
203 : 943721 : case '-': case '+': case '.': case '0': case '1': case '2':
204 : : case '3': case '4': case '5': case '6': case '7': case '8':
205 : : case '9':
206 : 6053220 : for (end = stream->stream; end != stream->end; end++)
207 : 6053187 : if (!g_ascii_isalnum (*end) &&
208 : 1393661 : *end != '-' && *end != '+' && *end != '.')
209 : 943688 : break;
210 : 943721 : break;
211 : :
212 : 184 : case 'b':
213 : 184 : if (stream->stream + 1 != stream->end &&
214 : 183 : (stream->stream[1] == '\'' || stream->stream[1] == '"'))
215 : : {
216 : 89 : for (end = stream->stream + 2; end != stream->end; end++)
217 : 81 : if (*end == stream->stream[1] || *end == '\0' ||
218 : 66 : (*end == '\\' && (++end == stream->end || *end == '\0')))
219 : : break;
220 : :
221 : 27 : if (end != stream->end && *end)
222 : 7 : end++;
223 : 27 : break;
224 : : }
225 : :
226 : : G_GNUC_FALLTHROUGH;
227 : :
228 : : case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
229 : : case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
230 : : case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
231 : : case 's': case 't': case 'u': case 'v': case 'w': case 'x':
232 : : case 'y': case 'z':
233 : 24049 : for (end = stream->stream; end != stream->end; end++)
234 : 24040 : if (!g_ascii_isalnum (*end))
235 : 3697 : break;
236 : 3706 : break;
237 : :
238 : 8259 : case '\'': case '"':
239 : 818217 : for (end = stream->stream + 1; end != stream->end; end++)
240 : 818216 : if (*end == stream->stream[0] || *end == '\0' ||
241 : 809960 : (*end == '\\' && (++end == stream->end || *end == '\0')))
242 : : break;
243 : :
244 : 8259 : if (end != stream->end && *end)
245 : 8254 : end++;
246 : 8259 : break;
247 : :
248 : 778 : case '@': case '%':
249 : : /* stop at the first space, comma, colon or unmatched bracket.
250 : : * deals nicely with cases like (%i, %i) or {%i: %i}.
251 : : * Also: ] and > are never in format strings.
252 : : */
253 : 778 : for (end = stream->stream + 1;
254 : 2052 : end != stream->end && *end != '\0' && *end != ',' &&
255 : 4075 : *end != ':' && *end != '>' && *end != ']' && !g_ascii_isspace (*end);
256 : 1274 : end++)
257 : :
258 : 1282 : if (*end == '(' || *end == '{')
259 : 42 : brackets++;
260 : :
261 : 1240 : else if ((*end == ')' || *end == '}') && !brackets--)
262 : 8 : break;
263 : :
264 : 778 : break;
265 : :
266 : 993730 : default:
267 : 993730 : end = stream->stream + 1;
268 : 993730 : break;
269 : : }
270 : :
271 : 1950221 : stream->this = stream->stream;
272 : 1950221 : stream->stream = end;
273 : :
274 : : /* We must have at least one byte in a token. */
275 : 1950221 : g_assert (stream->stream - stream->this >= 1);
276 : :
277 : 1950221 : return TRUE;
278 : : }
279 : :
280 : : static void
281 : 1950112 : token_stream_next (TokenStream *stream)
282 : : {
283 : 1950112 : stream->this = NULL;
284 : 1950112 : }
285 : :
286 : : static gboolean
287 : 3895525 : token_stream_peek (TokenStream *stream,
288 : : gchar first_char)
289 : : {
290 : 3895525 : if (!token_stream_prepare (stream))
291 : 0 : return FALSE;
292 : :
293 : 7790942 : return stream->stream - stream->this >= 1 &&
294 : 3895417 : stream->this[0] == first_char;
295 : : }
296 : :
297 : : static gboolean
298 : 71 : token_stream_peek2 (TokenStream *stream,
299 : : gchar first_char,
300 : : gchar second_char)
301 : : {
302 : 71 : if (!token_stream_prepare (stream))
303 : 0 : return FALSE;
304 : :
305 : 108 : return stream->stream - stream->this >= 2 &&
306 : 108 : stream->this[0] == first_char &&
307 : 37 : stream->this[1] == second_char;
308 : : }
309 : :
310 : : static gboolean
311 : 9854 : token_stream_is_keyword (TokenStream *stream)
312 : : {
313 : 9854 : if (!token_stream_prepare (stream))
314 : 0 : return FALSE;
315 : :
316 : 19691 : return stream->stream - stream->this >= 2 &&
317 : 11432 : g_ascii_isalpha (stream->this[0]) &&
318 : 1578 : g_ascii_isalpha (stream->this[1]);
319 : : }
320 : :
321 : : static gboolean
322 : 954339 : token_stream_is_numeric (TokenStream *stream)
323 : : {
324 : 954339 : if (!token_stream_prepare (stream))
325 : 0 : return FALSE;
326 : :
327 : 1908666 : return (stream->stream - stream->this >= 1 &&
328 : 954327 : (g_ascii_isdigit (stream->this[0]) ||
329 : 459026 : stream->this[0] == '-' ||
330 : 10622 : stream->this[0] == '+' ||
331 : 10622 : stream->this[0] == '.'));
332 : : }
333 : :
334 : : static gboolean
335 : 3908950 : token_stream_peek_string (TokenStream *stream,
336 : : const gchar *token)
337 : : {
338 : 3908950 : size_t length = strlen (token);
339 : :
340 : 3908950 : return token_stream_prepare (stream) &&
341 : 6441538 : (size_t) (stream->stream - stream->this) == length &&
342 : 2532588 : memcmp (stream->this, token, length) == 0;
343 : : }
344 : :
345 : : static gboolean
346 : 3887684 : token_stream_consume (TokenStream *stream,
347 : : const gchar *token)
348 : : {
349 : 3887684 : if (!token_stream_peek_string (stream, token))
350 : 2890280 : return FALSE;
351 : :
352 : 997404 : token_stream_next (stream);
353 : 997404 : return TRUE;
354 : : }
355 : :
356 : : static gboolean
357 : 955185 : token_stream_require (TokenStream *stream,
358 : : const gchar *token,
359 : : const gchar *purpose,
360 : : GError **error)
361 : : {
362 : :
363 : 955185 : if (!token_stream_consume (stream, token))
364 : : {
365 : 34 : token_stream_set_error (stream, error, FALSE,
366 : : G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN,
367 : : "expected '%s'%s", token, purpose);
368 : 34 : return FALSE;
369 : : }
370 : :
371 : 955151 : return TRUE;
372 : : }
373 : :
374 : : static void
375 : 19981 : token_stream_assert (TokenStream *stream,
376 : : const gchar *token)
377 : : {
378 : : gboolean correct_token G_GNUC_UNUSED /* when compiling with G_DISABLE_ASSERT */;
379 : :
380 : 19981 : correct_token = token_stream_consume (stream, token);
381 : 19981 : g_assert (correct_token);
382 : 19981 : }
383 : :
384 : : static gchar *
385 : 952772 : token_stream_get (TokenStream *stream)
386 : : {
387 : : gchar *result;
388 : :
389 : 952772 : if (!token_stream_prepare (stream))
390 : 0 : return NULL;
391 : :
392 : 952772 : result = g_strndup (stream->this, stream->stream - stream->this);
393 : :
394 : 952772 : return result;
395 : : }
396 : :
397 : : static void
398 : 984757 : token_stream_start_ref (TokenStream *stream,
399 : : SourceRef *ref)
400 : : {
401 : 984757 : token_stream_prepare (stream);
402 : 984757 : ref->start = stream->this - stream->start;
403 : 984757 : }
404 : :
405 : : static void
406 : 984477 : token_stream_end_ref (TokenStream *stream,
407 : : SourceRef *ref)
408 : : {
409 : 984477 : ref->end = stream->stream - stream->start;
410 : 984477 : }
411 : :
412 : : /* This is guaranteed to write exactly as many bytes to `out` as it consumes
413 : : * from `in`. i.e. The `out` buffer doesn’t need to be any longer than `in`. */
414 : : static void
415 : 240 : pattern_copy (gchar **out,
416 : : const gchar **in)
417 : : {
418 : 240 : gssize brackets = 0;
419 : :
420 : 386 : while (**in == 'a' || **in == 'm' || **in == 'M')
421 : 146 : *(*out)++ = *(*in)++;
422 : :
423 : : do
424 : : {
425 : 254 : if (**in == '(' || **in == '{')
426 : 2 : brackets++;
427 : :
428 : 252 : else if (**in == ')' || **in == '}')
429 : 2 : brackets--;
430 : :
431 : 254 : *(*out)++ = *(*in)++;
432 : : }
433 : 254 : while (brackets);
434 : 240 : }
435 : :
436 : : /* Returns the most general pattern that is subpattern of left and subpattern
437 : : * of right, or NULL if there is no such pattern. */
438 : : static gchar *
439 : 477231 : pattern_coalesce (const gchar *left,
440 : : const gchar *right)
441 : : {
442 : : gchar *result;
443 : : gchar *out;
444 : : size_t buflen;
445 : 477231 : size_t left_len = strlen (left), right_len = strlen (right);
446 : :
447 : : /* the length of the output is loosely bound by the sum of the input
448 : : * lengths, not simply the greater of the two lengths.
449 : : *
450 : : * (*(iii)) + ((iii)*) = ((iii)(iii))
451 : : *
452 : : * 8 + 8 = 12
453 : : *
454 : : * This can be proven by the fact that `out` is never incremented by more
455 : : * bytes than are consumed from `left` or `right` in each iteration.
456 : : */
457 : 477231 : g_assert (left_len < G_MAXSIZE - right_len);
458 : 477231 : buflen = left_len + right_len + 1;
459 : 477231 : out = result = g_malloc (buflen);
460 : :
461 : 1461864 : while (*left && *right)
462 : : {
463 : 984695 : if (*left == *right)
464 : : {
465 : 965545 : *out++ = *left++;
466 : 965545 : right++;
467 : : }
468 : :
469 : : else
470 : : {
471 : 19150 : const gchar **one = &left, **the_other = &right;
472 : :
473 : 38279 : again:
474 : 38279 : if (**one == '*' && **the_other != ')')
475 : : {
476 : 240 : pattern_copy (&out, the_other);
477 : 240 : (*one)++;
478 : : }
479 : :
480 : 38039 : else if (**one == 'M' && **the_other == 'm')
481 : : {
482 : 172 : *out++ = *(*the_other)++;
483 : : }
484 : :
485 : 37867 : else if (**one == 'M' && **the_other != 'm' && **the_other != '*')
486 : : {
487 : 9299 : (*one)++;
488 : : }
489 : :
490 : 28568 : else if (**one == 'N' && strchr ("ynqiuxthd", **the_other))
491 : : {
492 : 8084 : *out++ = *(*the_other)++;
493 : 8084 : (*one)++;
494 : : }
495 : :
496 : 20484 : else if (**one == 'S' && strchr ("sog", **the_other))
497 : : {
498 : 1293 : *out++ = *(*the_other)++;
499 : 1293 : (*one)++;
500 : : }
501 : :
502 : 19191 : else if (one == &left)
503 : : {
504 : 19129 : one = &right, the_other = &left;
505 : 19129 : goto again;
506 : : }
507 : :
508 : : else
509 : 62 : break;
510 : : }
511 : : }
512 : :
513 : : /* Need at least one byte remaining for trailing nul. */
514 : 477231 : g_assert (out < result + buflen);
515 : :
516 : 477231 : if (*left || *right)
517 : : {
518 : 62 : g_free (result);
519 : 62 : result = NULL;
520 : : }
521 : : else
522 : 477169 : *out++ = '\0';
523 : :
524 : 477231 : return result;
525 : : }
526 : :
527 : : typedef struct _AST AST;
528 : : typedef gchar * (*get_pattern_func) (AST *ast,
529 : : GError **error);
530 : : typedef GVariant * (*get_value_func) (AST *ast,
531 : : const GVariantType *type,
532 : : GError **error);
533 : : typedef GVariant * (*get_base_value_func) (AST *ast,
534 : : const GVariantType *type,
535 : : GError **error);
536 : : typedef void (*free_func) (AST *ast);
537 : :
538 : : typedef struct
539 : : {
540 : : gchar * (* get_pattern) (AST *ast,
541 : : GError **error);
542 : : GVariant * (* get_value) (AST *ast,
543 : : const GVariantType *type,
544 : : GError **error);
545 : : GVariant * (* get_base_value) (AST *ast,
546 : : const GVariantType *type,
547 : : GError **error);
548 : : void (* free) (AST *ast);
549 : : } ASTClass;
550 : :
551 : : struct _AST
552 : : {
553 : : const ASTClass *class;
554 : : SourceRef source_ref;
555 : : };
556 : :
557 : : static gchar *
558 : 496579 : ast_get_pattern (AST *ast,
559 : : GError **error)
560 : : {
561 : 496579 : return ast->class->get_pattern (ast, error);
562 : : }
563 : :
564 : : static GVariant *
565 : 975932 : ast_get_value (AST *ast,
566 : : const GVariantType *type,
567 : : GError **error)
568 : : {
569 : 975932 : return ast->class->get_value (ast, type, error);
570 : : }
571 : :
572 : : static void
573 : 976191 : ast_free (AST *ast)
574 : : {
575 : 976191 : ast->class->free (ast);
576 : 976191 : }
577 : :
578 : : G_GNUC_PRINTF(5, 6)
579 : : static void
580 : 127 : ast_set_error (AST *ast,
581 : : GError **error,
582 : : AST *other_ast,
583 : : gint code,
584 : : const gchar *format,
585 : : ...)
586 : : {
587 : : va_list ap;
588 : :
589 : 127 : va_start (ap, format);
590 : 127 : parser_set_error_va (error, &ast->source_ref,
591 : : other_ast ? & other_ast->source_ref : NULL,
592 : : code,
593 : : format, ap);
594 : 127 : va_end (ap);
595 : 127 : }
596 : :
597 : : static GVariant *
598 : 43 : ast_type_error (AST *ast,
599 : : const GVariantType *type,
600 : : GError **error)
601 : : {
602 : : gchar *typestr;
603 : :
604 : 43 : typestr = g_variant_type_dup_string (type);
605 : 43 : ast_set_error (ast, error, NULL,
606 : : G_VARIANT_PARSE_ERROR_TYPE_ERROR,
607 : : "can not parse as value of type '%s'",
608 : : typestr);
609 : 43 : g_free (typestr);
610 : :
611 : 43 : return NULL;
612 : : }
613 : :
614 : : static GVariant *
615 : 2078 : ast_resolve (AST *ast,
616 : : GError **error)
617 : : {
618 : : GVariant *value;
619 : : gchar *pattern;
620 : 2078 : size_t i, j = 0;
621 : :
622 : 2078 : pattern = ast_get_pattern (ast, error);
623 : :
624 : 2078 : if (pattern == NULL)
625 : 35 : return NULL;
626 : :
627 : : /* choose reasonable defaults
628 : : *
629 : : * 1) favour non-maybe values where possible
630 : : * 2) default type for strings is 's'
631 : : * 3) default type for integers is 'i'
632 : : */
633 : 10091 : for (i = 0; pattern[i]; i++)
634 : 8054 : switch (pattern[i])
635 : : {
636 : 6 : case '*':
637 : 6 : ast_set_error (ast, error, NULL,
638 : : G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE,
639 : : "unable to infer type");
640 : 6 : g_free (pattern);
641 : 6 : return NULL;
642 : :
643 : 2329 : case 'M':
644 : 2329 : break;
645 : :
646 : 297 : case 'S':
647 : 297 : pattern[j++] = 's';
648 : 297 : break;
649 : :
650 : 244 : case 'N':
651 : 244 : pattern[j++] = 'i';
652 : 244 : break;
653 : :
654 : 5178 : default:
655 : 5178 : pattern[j++] = pattern[i];
656 : 5178 : break;
657 : : }
658 : 2037 : pattern[j++] = '\0';
659 : :
660 : 2037 : value = ast_get_value (ast, G_VARIANT_TYPE (pattern), error);
661 : 2037 : g_free (pattern);
662 : :
663 : 2037 : return value;
664 : : }
665 : :
666 : :
667 : : static AST *parse (TokenStream *stream,
668 : : guint max_depth,
669 : : va_list *app,
670 : : GError **error);
671 : :
672 : : static void
673 : 971866 : ast_array_append (AST ***array,
674 : : size_t *n_items,
675 : : AST *ast)
676 : : {
677 : 971866 : if ((*n_items & (*n_items - 1)) == 0)
678 : 114498 : *array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
679 : :
680 : 971866 : (*array)[(*n_items)++] = ast;
681 : 971866 : }
682 : :
683 : : static void
684 : 19555 : ast_array_free (AST **array,
685 : : size_t n_items)
686 : : {
687 : : size_t i;
688 : :
689 : 991421 : for (i = 0; i < n_items; i++)
690 : 971866 : ast_free (array[i]);
691 : 19555 : g_free (array);
692 : 19555 : }
693 : :
694 : : static gchar *
695 : 8472 : ast_array_get_pattern (AST **array,
696 : : size_t n_items,
697 : : GError **error)
698 : : {
699 : : gchar *pattern;
700 : : size_t i;
701 : :
702 : : /* Find the pattern which applies to all children in the array, by l-folding a
703 : : * coalesce operation.
704 : : */
705 : 8472 : pattern = ast_get_pattern (array[0], error);
706 : :
707 : 8472 : if (pattern == NULL)
708 : 4 : return NULL;
709 : :
710 : 485635 : for (i = 1; i < n_items; i++)
711 : : {
712 : : gchar *tmp, *merged;
713 : :
714 : 477200 : tmp = ast_get_pattern (array[i], error);
715 : :
716 : 477200 : if (tmp == NULL)
717 : : {
718 : 2 : g_free (pattern);
719 : 2 : return NULL;
720 : : }
721 : :
722 : 477198 : merged = pattern_coalesce (pattern, tmp);
723 : 477198 : g_free (pattern);
724 : 477198 : pattern = merged;
725 : :
726 : 477198 : if (merged == NULL)
727 : : /* set coalescence implies pairwise coalescence (i think).
728 : : * we should therefore be able to trace the failure to a single
729 : : * pair of values.
730 : : */
731 : : {
732 : 31 : size_t j = 0;
733 : :
734 : : while (TRUE)
735 : 2 : {
736 : : gchar *tmp2;
737 : : gchar *m;
738 : :
739 : : /* if 'j' reaches 'i' then we didn't find the pair that failed
740 : : * to coalesce. This shouldn't happen (see above), but just in
741 : : * case report an error:
742 : : */
743 : 33 : if (j >= i)
744 : : {
745 : 0 : ast_set_error (array[i], error, NULL,
746 : : G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE,
747 : : "unable to find a common type");
748 : 0 : g_free (tmp);
749 : 0 : return NULL;
750 : : }
751 : :
752 : 33 : tmp2 = ast_get_pattern (array[j], NULL);
753 : 33 : g_assert (tmp2 != NULL);
754 : :
755 : 33 : m = pattern_coalesce (tmp, tmp2);
756 : 33 : g_free (tmp2);
757 : 33 : g_free (m);
758 : :
759 : 33 : if (m == NULL)
760 : : {
761 : : /* we found a conflict between 'i' and 'j'.
762 : : *
763 : : * report the error. note: 'j' is first.
764 : : */
765 : 31 : ast_set_error (array[j], error, array[i],
766 : : G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE,
767 : : "unable to find a common type");
768 : 31 : g_free (tmp);
769 : 31 : return NULL;
770 : : }
771 : :
772 : 2 : j++;
773 : : }
774 : :
775 : : }
776 : :
777 : 477167 : g_free (tmp);
778 : : }
779 : :
780 : 8435 : return pattern;
781 : : }
782 : :
783 : : typedef struct
784 : : {
785 : : AST ast;
786 : :
787 : : AST *child;
788 : : } Maybe;
789 : :
790 : : static gchar *
791 : 153 : maybe_get_pattern (AST *ast,
792 : : GError **error)
793 : : {
794 : 153 : Maybe *maybe = (Maybe *) ast;
795 : :
796 : 153 : if (maybe->child != NULL)
797 : : {
798 : : gchar *child_pattern;
799 : : gchar *pattern;
800 : :
801 : 2 : child_pattern = ast_get_pattern (maybe->child, error);
802 : :
803 : 2 : if (child_pattern == NULL)
804 : 2 : return NULL;
805 : :
806 : 0 : pattern = g_strdup_printf ("m%s", child_pattern);
807 : 0 : g_free (child_pattern);
808 : :
809 : 0 : return pattern;
810 : : }
811 : :
812 : 151 : return g_strdup ("m*");
813 : : }
814 : :
815 : : static GVariant *
816 : 393 : maybe_get_value (AST *ast,
817 : : const GVariantType *type,
818 : : GError **error)
819 : : {
820 : 393 : Maybe *maybe = (Maybe *) ast;
821 : : GVariant *value;
822 : :
823 : 393 : if (!g_variant_type_is_maybe (type))
824 : 4 : return ast_type_error (ast, type, error);
825 : :
826 : 389 : type = g_variant_type_element (type);
827 : :
828 : 389 : if (maybe->child)
829 : : {
830 : 8 : value = ast_get_value (maybe->child, type, error);
831 : :
832 : 8 : if (value == NULL)
833 : 2 : return NULL;
834 : : }
835 : : else
836 : 381 : value = NULL;
837 : :
838 : 387 : return g_variant_new_maybe (type, value);
839 : : }
840 : :
841 : : static void
842 : 397 : maybe_free (AST *ast)
843 : : {
844 : 397 : Maybe *maybe = (Maybe *) ast;
845 : :
846 : 397 : if (maybe->child != NULL)
847 : 12 : ast_free (maybe->child);
848 : :
849 : 397 : g_slice_free (Maybe, maybe);
850 : 397 : }
851 : :
852 : : static AST *
853 : 403 : maybe_parse (TokenStream *stream,
854 : : guint max_depth,
855 : : va_list *app,
856 : : GError **error)
857 : : {
858 : : static const ASTClass maybe_class = {
859 : : maybe_get_pattern,
860 : : maybe_get_value, NULL,
861 : : maybe_free
862 : : };
863 : 403 : AST *child = NULL;
864 : : Maybe *maybe;
865 : :
866 : 403 : if (token_stream_consume (stream, "just"))
867 : : {
868 : 14 : child = parse (stream, max_depth - 1, app, error);
869 : 14 : if (child == NULL)
870 : 2 : return NULL;
871 : : }
872 : :
873 : 389 : else if (!token_stream_consume (stream, "nothing"))
874 : : {
875 : 4 : token_stream_set_error (stream, error, TRUE,
876 : : G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
877 : : "unknown keyword");
878 : 4 : return NULL;
879 : : }
880 : :
881 : 397 : maybe = g_slice_new (Maybe);
882 : 397 : maybe->ast.class = &maybe_class;
883 : 397 : maybe->child = child;
884 : :
885 : 397 : return (AST *) maybe;
886 : : }
887 : :
888 : : static GVariant *
889 : 973226 : maybe_wrapper (AST *ast,
890 : : const GVariantType *type,
891 : : GError **error)
892 : : {
893 : : const GVariantType *base_type;
894 : : GVariant *base_value;
895 : 973226 : GVariant *value = NULL;
896 : : unsigned int depth;
897 : : gboolean trusted;
898 : 973226 : GVariantTypeInfo *base_type_info = NULL;
899 : : gsize base_serialised_fixed_size, base_serialised_size, serialised_size, n_suffix_zeros;
900 : 973226 : guint8 *serialised = NULL;
901 : 973226 : GBytes *bytes = NULL;
902 : : gsize i;
903 : :
904 : 973226 : for (depth = 0, base_type = type;
905 : 973677 : g_variant_type_is_maybe (base_type);
906 : 451 : depth++, base_type = g_variant_type_element (base_type));
907 : :
908 : 973226 : base_value = ast->class->get_base_value (ast, base_type, error);
909 : :
910 : 973226 : if (base_value == NULL || depth == 0)
911 : 972781 : return g_steal_pointer (&base_value);
912 : :
913 : : /* This is the equivalent of calling g_variant_new_maybe() in a loop enough
914 : : * times to match the number of nested maybe types in @type. It does the same
915 : : * in a single `GVariant` allocation, though.
916 : : *
917 : : * This avoids maybe_wrapper() becoming an attack vector where a malicious
918 : : * text-form variant can create a long array, and insert a typedecl for a
919 : : * deeply nested maybe type on one of its elements. This is achievable with a
920 : : * relatively short text form, but results in O(array length × typedecl depth)
921 : : * allocations. This is a denial of service attack.
922 : : *
923 : : * Instead of constructing a tree of `GVariant`s in tree-form to match the
924 : : * @ast, construct a single `GVariant` containing the serialised form of the
925 : : * maybe-wrappers and the base value that they contain. This is relatively
926 : : * straightforward: serialise the base value, and then append the correct
927 : : * number of zero bytes for the maybe-wrappers.
928 : : *
929 : : * This is a bit of a layering violation, unfortunately.
930 : : *
931 : : * By doing this, the typedecl depth variable is reduced to O(1).
932 : : */
933 : 445 : trusted = g_variant_is_trusted (base_value);
934 : :
935 : : /* See https://developer.gnome.org/documentation/specifications/gvariant-specification-1.0.html#maybes
936 : : *
937 : : * The serialised form of a `Just x` is the serialised form of `x` if `x` is
938 : : * fixed-size, and the serialised form of `x` plus a trailing zero byte if `x`
939 : : * is variable-size. A `Maybe` variant is always variable-size, even if its
940 : : * child element is fixed-size, because it might be `Nothing`. This means that
941 : : * all the maybe-wrappers which are not the innermost are always serialised
942 : : * with one trailing zero byte each.
943 : : *
944 : : * The serialised form of a `Nothing` is an empty byte sequence, but that’s
945 : : * already handled above in the `base_value == NULL` case.
946 : : */
947 : 445 : base_type_info = g_variant_type_info_get (base_type);
948 : 445 : g_variant_type_info_query (base_type_info, NULL, &base_serialised_fixed_size);
949 : 445 : g_variant_type_info_unref (base_type_info);
950 : :
951 : 445 : base_serialised_size = g_variant_get_size (base_value);
952 : 445 : n_suffix_zeros = (base_serialised_fixed_size > 0) ? depth - 1 : depth;
953 : 445 : g_assert (base_serialised_size <= G_MAXSIZE - n_suffix_zeros);
954 : 445 : serialised_size = base_serialised_size + n_suffix_zeros;
955 : :
956 : 445 : g_assert (serialised_size >= base_serialised_size);
957 : :
958 : : /* Serialise the base value. */
959 : 445 : serialised = g_malloc (serialised_size);
960 : 445 : g_variant_store (base_value, serialised);
961 : :
962 : : /* Zero-out the suffix zeros to complete the serialisation of the maybe wrappers. */
963 : 494 : for (i = base_serialised_size; i < serialised_size; i++)
964 : 49 : serialised[i] = 0;
965 : :
966 : 445 : bytes = g_bytes_new_take (g_steal_pointer (&serialised), serialised_size);
967 : 445 : value = g_variant_new_from_bytes (type, bytes, trusted);
968 : 445 : g_bytes_unref (bytes);
969 : :
970 : 445 : g_variant_unref (base_value);
971 : :
972 : 445 : return g_steal_pointer (&value);
973 : : }
974 : :
975 : : typedef struct
976 : : {
977 : : AST ast;
978 : :
979 : : AST **children;
980 : : size_t n_children;
981 : : } Array;
982 : :
983 : : static gchar *
984 : 8207 : array_get_pattern (AST *ast,
985 : : GError **error)
986 : : {
987 : 8207 : Array *array = (Array *) ast;
988 : : gchar *pattern;
989 : : gchar *result;
990 : :
991 : 8207 : if (array->n_children == 0)
992 : 97 : return g_strdup ("Ma*");
993 : :
994 : 8110 : pattern = ast_array_get_pattern (array->children, array->n_children, error);
995 : :
996 : 8110 : if (pattern == NULL)
997 : 35 : return NULL;
998 : :
999 : 8075 : result = g_strdup_printf ("Ma%s", pattern);
1000 : 8075 : g_free (pattern);
1001 : :
1002 : 8075 : return result;
1003 : : }
1004 : :
1005 : : static GVariant *
1006 : 15562 : array_get_value (AST *ast,
1007 : : const GVariantType *type,
1008 : : GError **error)
1009 : : {
1010 : 15562 : Array *array = (Array *) ast;
1011 : : const GVariantType *childtype;
1012 : : GVariantBuilder builder;
1013 : : size_t i;
1014 : :
1015 : 15562 : if (!g_variant_type_is_array (type))
1016 : 6 : return ast_type_error (ast, type, error);
1017 : :
1018 : 15556 : g_variant_builder_init_static (&builder, type);
1019 : 15556 : childtype = g_variant_type_element (type);
1020 : :
1021 : 967662 : for (i = 0; i < array->n_children; i++)
1022 : : {
1023 : : GVariant *child;
1024 : :
1025 : 952108 : if (!(child = ast_get_value (array->children[i], childtype, error)))
1026 : : {
1027 : 2 : g_variant_builder_clear (&builder);
1028 : 2 : return NULL;
1029 : : }
1030 : :
1031 : 952106 : g_variant_builder_add_value (&builder, child);
1032 : : }
1033 : :
1034 : 15554 : return g_variant_builder_end (&builder);
1035 : : }
1036 : :
1037 : : static void
1038 : 15623 : array_free (AST *ast)
1039 : : {
1040 : 15623 : Array *array = (Array *) ast;
1041 : :
1042 : 15623 : ast_array_free (array->children, array->n_children);
1043 : 15623 : g_slice_free (Array, array);
1044 : 15623 : }
1045 : :
1046 : : static AST *
1047 : 15635 : array_parse (TokenStream *stream,
1048 : : guint max_depth,
1049 : : va_list *app,
1050 : : GError **error)
1051 : : {
1052 : : static const ASTClass array_class = {
1053 : : array_get_pattern,
1054 : : maybe_wrapper, array_get_value,
1055 : : array_free
1056 : : };
1057 : 15635 : gboolean need_comma = FALSE;
1058 : : Array *array;
1059 : :
1060 : 15635 : array = g_slice_new (Array);
1061 : 15635 : array->ast.class = &array_class;
1062 : 15635 : array->children = NULL;
1063 : 15635 : array->n_children = 0;
1064 : :
1065 : 15635 : token_stream_assert (stream, "[");
1066 : 967869 : while (!token_stream_consume (stream, "]"))
1067 : : {
1068 : : AST *child;
1069 : :
1070 : 1889053 : if (need_comma &&
1071 : 936807 : !token_stream_require (stream, ",",
1072 : : " or ']' to follow array element",
1073 : : error))
1074 : 9 : goto error;
1075 : :
1076 : 952237 : child = parse (stream, max_depth - 1, app, error);
1077 : :
1078 : 952237 : if (!child)
1079 : 3 : goto error;
1080 : :
1081 : 952234 : ast_array_append (&array->children, &array->n_children, child);
1082 : 952234 : need_comma = TRUE;
1083 : : }
1084 : :
1085 : 15623 : return (AST *) array;
1086 : :
1087 : 12 : error:
1088 : 12 : ast_array_free (array->children, array->n_children);
1089 : 12 : g_slice_free (Array, array);
1090 : :
1091 : 12 : return NULL;
1092 : : }
1093 : :
1094 : : typedef struct
1095 : : {
1096 : : AST ast;
1097 : :
1098 : : AST **children;
1099 : : size_t n_children;
1100 : : } Tuple;
1101 : :
1102 : : static gchar *
1103 : 1330 : tuple_get_pattern (AST *ast,
1104 : : GError **error)
1105 : : {
1106 : 1330 : Tuple *tuple = (Tuple *) ast;
1107 : 1330 : gchar *result = NULL;
1108 : : gchar **parts;
1109 : : size_t i;
1110 : :
1111 : 1330 : parts = g_new (gchar *, tuple->n_children + 4);
1112 : 1330 : parts[tuple->n_children + 1] = (gchar *) ")";
1113 : 1330 : parts[tuple->n_children + 2] = NULL;
1114 : 1330 : parts[0] = (gchar *) "M(";
1115 : :
1116 : 9766 : for (i = 0; i < tuple->n_children; i++)
1117 : 8438 : if (!(parts[i + 1] = ast_get_pattern (tuple->children[i], error)))
1118 : 2 : break;
1119 : :
1120 : 1330 : if (i == tuple->n_children)
1121 : 1328 : result = g_strjoinv ("", parts);
1122 : :
1123 : : /* parts[0] should not be freed */
1124 : 9766 : while (i)
1125 : 8436 : g_free (parts[i--]);
1126 : 1330 : g_free (parts);
1127 : :
1128 : 1330 : return result;
1129 : : }
1130 : :
1131 : : static GVariant *
1132 : 2289 : tuple_get_value (AST *ast,
1133 : : const GVariantType *type,
1134 : : GError **error)
1135 : : {
1136 : 2289 : Tuple *tuple = (Tuple *) ast;
1137 : : const GVariantType *childtype;
1138 : : GVariantBuilder builder;
1139 : : size_t i;
1140 : :
1141 : 2289 : if (!g_variant_type_is_tuple (type))
1142 : 4 : return ast_type_error (ast, type, error);
1143 : :
1144 : 2285 : g_variant_builder_init_static (&builder, type);
1145 : 2285 : childtype = g_variant_type_first (type);
1146 : :
1147 : 19762 : for (i = 0; i < tuple->n_children; i++)
1148 : : {
1149 : : GVariant *child;
1150 : :
1151 : 17479 : if (childtype == NULL)
1152 : : {
1153 : 0 : g_variant_builder_clear (&builder);
1154 : 0 : return ast_type_error (ast, type, error);
1155 : : }
1156 : :
1157 : 17479 : if (!(child = ast_get_value (tuple->children[i], childtype, error)))
1158 : : {
1159 : 2 : g_variant_builder_clear (&builder);
1160 : 2 : return FALSE;
1161 : : }
1162 : :
1163 : 17477 : g_variant_builder_add_value (&builder, child);
1164 : 17477 : childtype = g_variant_type_next (childtype);
1165 : : }
1166 : :
1167 : 2283 : if (childtype != NULL)
1168 : : {
1169 : 0 : g_variant_builder_clear (&builder);
1170 : 0 : return ast_type_error (ast, type, error);
1171 : : }
1172 : :
1173 : 2283 : return g_variant_builder_end (&builder);
1174 : : }
1175 : :
1176 : : static void
1177 : 2291 : tuple_free (AST *ast)
1178 : : {
1179 : 2291 : Tuple *tuple = (Tuple *) ast;
1180 : :
1181 : 2291 : ast_array_free (tuple->children, tuple->n_children);
1182 : 2291 : g_slice_free (Tuple, tuple);
1183 : 2291 : }
1184 : :
1185 : : static AST *
1186 : 2308 : tuple_parse (TokenStream *stream,
1187 : : guint max_depth,
1188 : : va_list *app,
1189 : : GError **error)
1190 : : {
1191 : : static const ASTClass tuple_class = {
1192 : : tuple_get_pattern,
1193 : : maybe_wrapper, tuple_get_value,
1194 : : tuple_free
1195 : : };
1196 : 2308 : gboolean need_comma = FALSE;
1197 : 2308 : gboolean first = TRUE;
1198 : : Tuple *tuple;
1199 : :
1200 : 2308 : tuple = g_slice_new (Tuple);
1201 : 2308 : tuple->ast.class = &tuple_class;
1202 : 2308 : tuple->children = NULL;
1203 : 2308 : tuple->n_children = 0;
1204 : :
1205 : 2308 : token_stream_assert (stream, "(");
1206 : 19802 : while (!token_stream_consume (stream, ")"))
1207 : : {
1208 : : AST *child;
1209 : :
1210 : 30906 : if (need_comma &&
1211 : 13395 : !token_stream_require (stream, ",",
1212 : : " or ')' to follow tuple element",
1213 : : error))
1214 : 2 : goto error;
1215 : :
1216 : 17509 : child = parse (stream, max_depth - 1, app, error);
1217 : :
1218 : 17509 : if (!child)
1219 : 11 : goto error;
1220 : :
1221 : 17498 : ast_array_append (&tuple->children, &tuple->n_children, child);
1222 : :
1223 : : /* the first time, we absolutely require a comma, so grab it here
1224 : : * and leave need_comma = FALSE so that the code above doesn't
1225 : : * require a second comma.
1226 : : *
1227 : : * the second and remaining times, we set need_comma = TRUE.
1228 : : */
1229 : 17498 : if (first)
1230 : : {
1231 : 2280 : if (!token_stream_require (stream, ",",
1232 : : " after first tuple element", error))
1233 : 4 : goto error;
1234 : :
1235 : 2276 : first = FALSE;
1236 : : }
1237 : : else
1238 : 15218 : need_comma = TRUE;
1239 : : }
1240 : :
1241 : 2291 : return (AST *) tuple;
1242 : :
1243 : 17 : error:
1244 : 17 : ast_array_free (tuple->children, tuple->n_children);
1245 : 17 : g_slice_free (Tuple, tuple);
1246 : :
1247 : 17 : return NULL;
1248 : : }
1249 : :
1250 : : typedef struct
1251 : : {
1252 : : AST ast;
1253 : :
1254 : : AST *value;
1255 : : } Variant;
1256 : :
1257 : : static gchar *
1258 : 642 : variant_get_pattern (AST *ast,
1259 : : GError **error)
1260 : : {
1261 : 642 : return g_strdup ("Mv");
1262 : : }
1263 : :
1264 : : static GVariant *
1265 : 1219 : variant_get_value (AST *ast,
1266 : : const GVariantType *type,
1267 : : GError **error)
1268 : : {
1269 : 1219 : Variant *variant = (Variant *) ast;
1270 : : GVariant *child;
1271 : :
1272 : 1219 : if (!g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
1273 : 0 : return ast_type_error (ast, type, error);
1274 : :
1275 : 1219 : child = ast_resolve (variant->value, error);
1276 : :
1277 : 1219 : if (child == NULL)
1278 : 2 : return NULL;
1279 : :
1280 : 1217 : return g_variant_new_variant (child);
1281 : : }
1282 : :
1283 : : static void
1284 : 1219 : variant_free (AST *ast)
1285 : : {
1286 : 1219 : Variant *variant = (Variant *) ast;
1287 : :
1288 : 1219 : ast_free (variant->value);
1289 : 1219 : g_slice_free (Variant, variant);
1290 : 1219 : }
1291 : :
1292 : : static AST *
1293 : 1232 : variant_parse (TokenStream *stream,
1294 : : guint max_depth,
1295 : : va_list *app,
1296 : : GError **error)
1297 : : {
1298 : : static const ASTClass variant_class = {
1299 : : variant_get_pattern,
1300 : : maybe_wrapper, variant_get_value,
1301 : : variant_free
1302 : : };
1303 : : Variant *variant;
1304 : : AST *value;
1305 : :
1306 : 1232 : token_stream_assert (stream, "<");
1307 : 1232 : value = parse (stream, max_depth - 1, app, error);
1308 : :
1309 : 1232 : if (!value)
1310 : 2 : return NULL;
1311 : :
1312 : 1230 : if (!token_stream_require (stream, ">", " to follow variant value", error))
1313 : : {
1314 : 11 : ast_free (value);
1315 : 11 : return NULL;
1316 : : }
1317 : :
1318 : 1219 : variant = g_slice_new (Variant);
1319 : 1219 : variant->ast.class = &variant_class;
1320 : 1219 : variant->value = value;
1321 : :
1322 : 1219 : return (AST *) variant;
1323 : : }
1324 : :
1325 : : typedef struct
1326 : : {
1327 : : AST ast;
1328 : :
1329 : : AST **keys;
1330 : : AST **values;
1331 : :
1332 : : /* Iff this is DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY then this struct
1333 : : * represents a single freestanding dict entry (`{1, "one"}`) rather than a
1334 : : * full dict. In the freestanding case, @keys and @values have exactly one
1335 : : * member each. */
1336 : : size_t n_children;
1337 : : } Dictionary;
1338 : :
1339 : : #define DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY ((size_t) -1)
1340 : :
1341 : : static gchar *
1342 : 364 : dictionary_get_pattern (AST *ast,
1343 : : GError **error)
1344 : : {
1345 : 364 : Dictionary *dict = (Dictionary *) ast;
1346 : : gchar *value_pattern;
1347 : : gchar *key_pattern;
1348 : : gchar key_char;
1349 : : gchar *result;
1350 : :
1351 : 364 : if (dict->n_children == 0)
1352 : 2 : return g_strdup ("Ma{**}");
1353 : :
1354 : 362 : key_pattern = ast_array_get_pattern (dict->keys,
1355 : 362 : (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY) ? 1 : dict->n_children,
1356 : : error);
1357 : :
1358 : 362 : if (key_pattern == NULL)
1359 : 2 : return NULL;
1360 : :
1361 : : /* we can not have maybe keys */
1362 : 360 : if (key_pattern[0] == 'M')
1363 : 259 : key_char = key_pattern[1];
1364 : : else
1365 : 101 : key_char = key_pattern[0];
1366 : :
1367 : 360 : g_free (key_pattern);
1368 : :
1369 : : /* the basic types,
1370 : : * plus undetermined number type and undetermined string type.
1371 : : */
1372 : 360 : if (!strchr ("bynqiuxthdsogNS", key_char))
1373 : : {
1374 : 4 : ast_set_error (ast, error, NULL,
1375 : : G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED,
1376 : : "dictionary keys must have basic types");
1377 : 4 : return NULL;
1378 : : }
1379 : :
1380 : 356 : value_pattern = ast_get_pattern (dict->values[0], error);
1381 : :
1382 : 356 : if (value_pattern == NULL)
1383 : 2 : return NULL;
1384 : :
1385 : 354 : result = g_strdup_printf ("M%s{%c%s}",
1386 : 354 : (dict->n_children > 0 && dict->n_children != DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY) ? "a" : "",
1387 : : key_char, value_pattern);
1388 : 354 : g_free (value_pattern);
1389 : :
1390 : 354 : return result;
1391 : : }
1392 : :
1393 : : static GVariant *
1394 : 652 : dictionary_get_value (AST *ast,
1395 : : const GVariantType *type,
1396 : : GError **error)
1397 : : {
1398 : 652 : Dictionary *dict = (Dictionary *) ast;
1399 : :
1400 : 652 : if (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY)
1401 : : {
1402 : : const GVariantType *subtype;
1403 : : GVariantBuilder builder;
1404 : : GVariant *subvalue;
1405 : :
1406 : 611 : if (!g_variant_type_is_dict_entry (type))
1407 : 2 : return ast_type_error (ast, type, error);
1408 : :
1409 : 609 : g_variant_builder_init_static (&builder, type);
1410 : :
1411 : 609 : subtype = g_variant_type_key (type);
1412 : 609 : if (!(subvalue = ast_get_value (dict->keys[0], subtype, error)))
1413 : : {
1414 : 2 : g_variant_builder_clear (&builder);
1415 : 2 : return NULL;
1416 : : }
1417 : 607 : g_variant_builder_add_value (&builder, subvalue);
1418 : :
1419 : 607 : subtype = g_variant_type_value (type);
1420 : 607 : if (!(subvalue = ast_get_value (dict->values[0], subtype, error)))
1421 : : {
1422 : 2 : g_variant_builder_clear (&builder);
1423 : 2 : return NULL;
1424 : : }
1425 : 605 : g_variant_builder_add_value (&builder, subvalue);
1426 : :
1427 : 605 : return g_variant_builder_end (&builder);
1428 : : }
1429 : : else
1430 : : {
1431 : : const GVariantType *entry, *key, *val;
1432 : : GVariantBuilder builder;
1433 : : size_t i;
1434 : :
1435 : 41 : if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
1436 : 3 : return ast_type_error (ast, type, error);
1437 : :
1438 : 38 : entry = g_variant_type_element (type);
1439 : 38 : key = g_variant_type_key (entry);
1440 : 38 : val = g_variant_type_value (entry);
1441 : :
1442 : 38 : g_variant_builder_init_static (&builder, type);
1443 : :
1444 : 467 : for (i = 0; i < dict->n_children; i++)
1445 : : {
1446 : : GVariant *subvalue;
1447 : :
1448 : 433 : g_variant_builder_open (&builder, entry);
1449 : :
1450 : 433 : if (!(subvalue = ast_get_value (dict->keys[i], key, error)))
1451 : : {
1452 : 2 : g_variant_builder_clear (&builder);
1453 : 2 : return NULL;
1454 : : }
1455 : 431 : g_variant_builder_add_value (&builder, subvalue);
1456 : :
1457 : 431 : if (!(subvalue = ast_get_value (dict->values[i], val, error)))
1458 : : {
1459 : 2 : g_variant_builder_clear (&builder);
1460 : 2 : return NULL;
1461 : : }
1462 : 429 : g_variant_builder_add_value (&builder, subvalue);
1463 : 429 : g_variant_builder_close (&builder);
1464 : : }
1465 : :
1466 : 34 : return g_variant_builder_end (&builder);
1467 : : }
1468 : : }
1469 : :
1470 : : static void
1471 : 662 : dictionary_free (AST *ast)
1472 : : {
1473 : 662 : Dictionary *dict = (Dictionary *) ast;
1474 : : size_t n_children;
1475 : :
1476 : 662 : if (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY)
1477 : 617 : n_children = 1;
1478 : : else
1479 : 45 : n_children = dict->n_children;
1480 : :
1481 : 662 : ast_array_free (dict->keys, n_children);
1482 : 662 : ast_array_free (dict->values, n_children);
1483 : 662 : g_slice_free (Dictionary, dict);
1484 : 662 : }
1485 : :
1486 : : static AST *
1487 : 806 : dictionary_parse (TokenStream *stream,
1488 : : guint max_depth,
1489 : : va_list *app,
1490 : : GError **error)
1491 : : {
1492 : : static const ASTClass dictionary_class = {
1493 : : dictionary_get_pattern,
1494 : : maybe_wrapper, dictionary_get_value,
1495 : : dictionary_free
1496 : : };
1497 : : size_t n_keys, n_values;
1498 : : gboolean only_one;
1499 : : Dictionary *dict;
1500 : : AST *first;
1501 : :
1502 : 806 : dict = g_slice_new (Dictionary);
1503 : 806 : dict->ast.class = &dictionary_class;
1504 : 806 : dict->keys = NULL;
1505 : 806 : dict->values = NULL;
1506 : 806 : n_keys = n_values = 0;
1507 : :
1508 : 806 : token_stream_assert (stream, "{");
1509 : :
1510 : 806 : if (token_stream_consume (stream, "}"))
1511 : : {
1512 : 5 : dict->n_children = 0;
1513 : 5 : return (AST *) dict;
1514 : : }
1515 : :
1516 : 801 : if ((first = parse (stream, max_depth - 1, app, error)) == NULL)
1517 : 130 : goto error;
1518 : :
1519 : 671 : ast_array_append (&dict->keys, &n_keys, first);
1520 : :
1521 : 671 : only_one = token_stream_consume (stream, ",");
1522 : 721 : if (!only_one &&
1523 : 50 : !token_stream_require (stream, ":",
1524 : : " or ',' to follow dictionary entry key",
1525 : : error))
1526 : 2 : goto error;
1527 : :
1528 : 669 : if ((first = parse (stream, max_depth - 1, app, error)) == NULL)
1529 : 2 : goto error;
1530 : :
1531 : 667 : ast_array_append (&dict->values, &n_values, first);
1532 : :
1533 : 667 : if (only_one)
1534 : : {
1535 : 619 : if (!token_stream_require (stream, "}", " at end of dictionary entry",
1536 : : error))
1537 : 2 : goto error;
1538 : :
1539 : 617 : g_assert (n_keys == 1 && n_values == 1);
1540 : 617 : dict->n_children = DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY;
1541 : :
1542 : 617 : return (AST *) dict;
1543 : : }
1544 : :
1545 : 444 : while (!token_stream_consume (stream, "}"))
1546 : : {
1547 : : AST *child;
1548 : :
1549 : 404 : if (!token_stream_require (stream, ",",
1550 : : " or '}' to follow dictionary entry", error))
1551 : 2 : goto error;
1552 : :
1553 : 402 : child = parse (stream, max_depth - 1, app, error);
1554 : :
1555 : 402 : if (!child)
1556 : 2 : goto error;
1557 : :
1558 : 400 : ast_array_append (&dict->keys, &n_keys, child);
1559 : :
1560 : 400 : if (!token_stream_require (stream, ":",
1561 : : " to follow dictionary entry key", error))
1562 : 2 : goto error;
1563 : :
1564 : 398 : child = parse (stream, max_depth - 1, app, error);
1565 : :
1566 : 398 : if (!child)
1567 : 2 : goto error;
1568 : :
1569 : 396 : ast_array_append (&dict->values, &n_values, child);
1570 : : }
1571 : :
1572 : 40 : g_assert (n_keys == n_values);
1573 : 40 : g_assert (n_keys != DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY);
1574 : 40 : dict->n_children = n_keys;
1575 : :
1576 : 40 : return (AST *) dict;
1577 : :
1578 : 144 : error:
1579 : 144 : ast_array_free (dict->keys, n_keys);
1580 : 144 : ast_array_free (dict->values, n_values);
1581 : 144 : g_slice_free (Dictionary, dict);
1582 : :
1583 : 144 : return NULL;
1584 : : }
1585 : :
1586 : : typedef struct
1587 : : {
1588 : : AST ast;
1589 : : gchar *string;
1590 : : } String;
1591 : :
1592 : : static gchar *
1593 : 3963 : string_get_pattern (AST *ast,
1594 : : GError **error)
1595 : : {
1596 : 3963 : return g_strdup ("MS");
1597 : : }
1598 : :
1599 : : static GVariant *
1600 : 8193 : string_get_value (AST *ast,
1601 : : const GVariantType *type,
1602 : : GError **error)
1603 : : {
1604 : 8193 : String *string = (String *) ast;
1605 : :
1606 : 8193 : if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
1607 : 5085 : return g_variant_new_string (string->string);
1608 : :
1609 : 3108 : else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
1610 : : {
1611 : 1712 : if (!g_variant_is_object_path (string->string))
1612 : : {
1613 : 2 : ast_set_error (ast, error, NULL,
1614 : : G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH,
1615 : : "not a valid object path");
1616 : 2 : return NULL;
1617 : : }
1618 : :
1619 : 1710 : return g_variant_new_object_path (string->string);
1620 : : }
1621 : :
1622 : 1396 : else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
1623 : : {
1624 : 1382 : if (!g_variant_is_signature (string->string))
1625 : : {
1626 : 2 : ast_set_error (ast, error, NULL,
1627 : : G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE,
1628 : : "not a valid signature");
1629 : 2 : return NULL;
1630 : : }
1631 : :
1632 : 1380 : return g_variant_new_signature (string->string);
1633 : : }
1634 : :
1635 : : else
1636 : 14 : return ast_type_error (ast, type, error);
1637 : : }
1638 : :
1639 : : static void
1640 : 8220 : string_free (AST *ast)
1641 : : {
1642 : 8220 : String *string = (String *) ast;
1643 : :
1644 : 8220 : g_free (string->string);
1645 : 8220 : g_slice_free (String, string);
1646 : 8220 : }
1647 : :
1648 : : /* Accepts exactly @length hexadecimal digits. No leading sign or `0x`/`0X` prefix allowed.
1649 : : * No leading/trailing space allowed.
1650 : : *
1651 : : * It's OK to pass a length greater than the actual length of the src buffer,
1652 : : * provided src must be null-terminated.
1653 : : */
1654 : : static gboolean
1655 : 61 : unicode_unescape (const gchar *src,
1656 : : size_t *src_ofs,
1657 : : gchar *dest,
1658 : : size_t *dest_ofs,
1659 : : gsize length,
1660 : : SourceRef *ref,
1661 : : GError **error)
1662 : : {
1663 : : gchar buffer[9];
1664 : 61 : guint64 value = 0;
1665 : 61 : gchar *end = NULL;
1666 : : gsize n_valid_chars;
1667 : :
1668 : 61 : (*src_ofs)++;
1669 : :
1670 : 61 : g_assert (length < sizeof (buffer));
1671 : 61 : strncpy (buffer, src + *src_ofs, length);
1672 : 61 : buffer[length] = '\0';
1673 : :
1674 : 205 : for (n_valid_chars = 0; n_valid_chars < length; n_valid_chars++)
1675 : 178 : if (!g_ascii_isxdigit (buffer[n_valid_chars]))
1676 : 34 : break;
1677 : :
1678 : 61 : if (n_valid_chars == length)
1679 : 27 : value = g_ascii_strtoull (buffer, &end, 0x10);
1680 : :
1681 : 61 : if (value == 0 || end != buffer + length)
1682 : : {
1683 : : SourceRef escape_ref;
1684 : :
1685 : 34 : escape_ref = *ref;
1686 : 34 : escape_ref.start += *src_ofs;
1687 : 34 : escape_ref.end = escape_ref.start + n_valid_chars;
1688 : :
1689 : 34 : parser_set_error (error, &escape_ref, NULL,
1690 : : G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1691 : : "invalid %" G_GSIZE_FORMAT "-character unicode escape", length);
1692 : 34 : return FALSE;
1693 : : }
1694 : :
1695 : 27 : g_assert (value <= G_MAXUINT32);
1696 : :
1697 : 27 : *dest_ofs += g_unichar_to_utf8 (value, dest + *dest_ofs);
1698 : 27 : *src_ofs += length;
1699 : :
1700 : 27 : return TRUE;
1701 : : }
1702 : :
1703 : : static AST *
1704 : 8259 : string_parse (TokenStream *stream,
1705 : : va_list *app,
1706 : : GError **error)
1707 : : {
1708 : : static const ASTClass string_class = {
1709 : : string_get_pattern,
1710 : : maybe_wrapper, string_get_value,
1711 : : string_free
1712 : : };
1713 : : String *string;
1714 : : SourceRef ref;
1715 : : gchar *token;
1716 : : gsize length;
1717 : : gchar quote;
1718 : : gchar *str;
1719 : : size_t i, j;
1720 : :
1721 : 8259 : token_stream_start_ref (stream, &ref);
1722 : 8259 : token = token_stream_get (stream);
1723 : 8259 : token_stream_end_ref (stream, &ref);
1724 : 8259 : length = strlen (token);
1725 : 8259 : quote = token[0];
1726 : :
1727 : : /* The output will always be at least one byte smaller than the input,
1728 : : * because we skip over the initial quote character.
1729 : : */
1730 : 8259 : str = g_malloc (length);
1731 : 8259 : g_assert (quote == '"' || quote == '\'');
1732 : 8259 : j = 0;
1733 : 8259 : i = 1;
1734 : 817953 : while (token[i] != quote)
1735 : 809733 : switch (token[i])
1736 : : {
1737 : 3 : case '\0':
1738 : 3 : parser_set_error (error, &ref, NULL,
1739 : : G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1740 : : "unterminated string constant");
1741 : 3 : g_free (token);
1742 : 3 : g_free (str);
1743 : 3 : return NULL;
1744 : :
1745 : 86 : case '\\':
1746 : 86 : switch (token[++i])
1747 : : {
1748 : 2 : case '\0':
1749 : 2 : parser_set_error (error, &ref, NULL,
1750 : : G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1751 : : "unterminated string constant");
1752 : 2 : g_free (token);
1753 : 2 : g_free (str);
1754 : 2 : return NULL;
1755 : :
1756 : 43 : case 'u':
1757 : 43 : if (!unicode_unescape (token, &i, str, &j, 4, &ref, error))
1758 : : {
1759 : 17 : g_free (token);
1760 : 17 : g_free (str);
1761 : 17 : return NULL;
1762 : : }
1763 : 26 : continue;
1764 : :
1765 : 18 : case 'U':
1766 : 18 : if (!unicode_unescape (token, &i, str, &j, 8, &ref, error))
1767 : : {
1768 : 17 : g_free (token);
1769 : 17 : g_free (str);
1770 : 17 : return NULL;
1771 : : }
1772 : 1 : continue;
1773 : :
1774 : 2 : case 'a': str[j++] = '\a'; i++; continue;
1775 : 2 : case 'b': str[j++] = '\b'; i++; continue;
1776 : 2 : case 'f': str[j++] = '\f'; i++; continue;
1777 : 3 : case 'n': str[j++] = '\n'; i++; continue;
1778 : 2 : case 'r': str[j++] = '\r'; i++; continue;
1779 : 3 : case 't': str[j++] = '\t'; i++; continue;
1780 : 2 : case 'v': str[j++] = '\v'; i++; continue;
1781 : 0 : case '\n': i++; continue;
1782 : : }
1783 : :
1784 : : G_GNUC_FALLTHROUGH;
1785 : :
1786 : : default:
1787 : 809651 : str[j++] = token[i++];
1788 : : }
1789 : 8220 : str[j++] = '\0';
1790 : 8220 : g_free (token);
1791 : :
1792 : 8220 : string = g_slice_new (String);
1793 : 8220 : string->ast.class = &string_class;
1794 : 8220 : string->string = str;
1795 : :
1796 : 8220 : token_stream_next (stream);
1797 : :
1798 : 8220 : return (AST *) string;
1799 : : }
1800 : :
1801 : : typedef struct
1802 : : {
1803 : : AST ast;
1804 : : gchar *string;
1805 : : } ByteString;
1806 : :
1807 : : static gchar *
1808 : 5 : bytestring_get_pattern (AST *ast,
1809 : : GError **error)
1810 : : {
1811 : 5 : return g_strdup ("May");
1812 : : }
1813 : :
1814 : : static GVariant *
1815 : 7 : bytestring_get_value (AST *ast,
1816 : : const GVariantType *type,
1817 : : GError **error)
1818 : : {
1819 : 7 : ByteString *string = (ByteString *) ast;
1820 : :
1821 : 7 : if (!g_variant_type_equal (type, G_VARIANT_TYPE_BYTESTRING))
1822 : 0 : return ast_type_error (ast, type, error);
1823 : :
1824 : 7 : return g_variant_new_bytestring (string->string);
1825 : : }
1826 : :
1827 : : static void
1828 : 7 : bytestring_free (AST *ast)
1829 : : {
1830 : 7 : ByteString *string = (ByteString *) ast;
1831 : :
1832 : 7 : g_free (string->string);
1833 : 7 : g_slice_free (ByteString, string);
1834 : 7 : }
1835 : :
1836 : : static AST *
1837 : 27 : bytestring_parse (TokenStream *stream,
1838 : : va_list *app,
1839 : : GError **error)
1840 : : {
1841 : : static const ASTClass bytestring_class = {
1842 : : bytestring_get_pattern,
1843 : : maybe_wrapper, bytestring_get_value,
1844 : : bytestring_free
1845 : : };
1846 : : ByteString *string;
1847 : : SourceRef ref;
1848 : : gchar *token;
1849 : : gsize length;
1850 : : gchar quote;
1851 : : gchar *str;
1852 : : size_t i, j;
1853 : :
1854 : 27 : token_stream_start_ref (stream, &ref);
1855 : 27 : token = token_stream_get (stream);
1856 : 27 : token_stream_end_ref (stream, &ref);
1857 : 27 : g_assert (token[0] == 'b');
1858 : 27 : length = strlen (token);
1859 : 27 : quote = token[1];
1860 : :
1861 : : /* The output will always be smaller than the input, because we skip over the
1862 : : * initial b and the quote character.
1863 : : */
1864 : 27 : str = g_malloc (length);
1865 : 27 : g_assert (quote == '"' || quote == '\'');
1866 : 27 : j = 0;
1867 : 27 : i = 2;
1868 : 87 : while (token[i] != quote)
1869 : 80 : switch (token[i])
1870 : : {
1871 : 16 : case '\0':
1872 : 16 : parser_set_error (error, &ref, NULL,
1873 : : G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1874 : : "unterminated string constant");
1875 : 16 : g_free (str);
1876 : 16 : g_free (token);
1877 : 16 : return NULL;
1878 : :
1879 : 13 : case '\\':
1880 : 13 : switch (token[++i])
1881 : : {
1882 : 4 : case '\0':
1883 : 4 : parser_set_error (error, &ref, NULL,
1884 : : G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1885 : : "unterminated string constant");
1886 : 4 : g_free (str);
1887 : 4 : g_free (token);
1888 : 4 : return NULL;
1889 : :
1890 : 1 : case '0': case '1': case '2': case '3':
1891 : : case '4': case '5': case '6': case '7':
1892 : : {
1893 : : /* up to 3 characters */
1894 : 1 : guchar val = token[i++] - '0';
1895 : :
1896 : 1 : if ('0' <= token[i] && token[i] < '8')
1897 : 1 : val = (val << 3) | (token[i++] - '0');
1898 : :
1899 : 1 : if ('0' <= token[i] && token[i] < '8')
1900 : 1 : val = (val << 3) | (token[i++] - '0');
1901 : :
1902 : 1 : str[j++] = val;
1903 : : }
1904 : 1 : continue;
1905 : :
1906 : 0 : case 'a': str[j++] = '\a'; i++; continue;
1907 : 0 : case 'b': str[j++] = '\b'; i++; continue;
1908 : 0 : case 'f': str[j++] = '\f'; i++; continue;
1909 : 0 : case 'n': str[j++] = '\n'; i++; continue;
1910 : 0 : case 'r': str[j++] = '\r'; i++; continue;
1911 : 0 : case 't': str[j++] = '\t'; i++; continue;
1912 : 0 : case 'v': str[j++] = '\v'; i++; continue;
1913 : 0 : case '\n': i++; continue;
1914 : : }
1915 : :
1916 : : G_GNUC_FALLTHROUGH;
1917 : :
1918 : : default:
1919 : 59 : str[j++] = token[i++];
1920 : : }
1921 : 7 : str[j++] = '\0';
1922 : 7 : g_free (token);
1923 : :
1924 : 7 : string = g_slice_new (ByteString);
1925 : 7 : string->ast.class = &bytestring_class;
1926 : 7 : string->string = str;
1927 : :
1928 : 7 : token_stream_next (stream);
1929 : :
1930 : 7 : return (AST *) string;
1931 : : }
1932 : :
1933 : : typedef struct
1934 : : {
1935 : : AST ast;
1936 : :
1937 : : gchar *token;
1938 : : } Number;
1939 : :
1940 : : static gchar *
1941 : 478761 : number_get_pattern (AST *ast,
1942 : : GError **error)
1943 : : {
1944 : 478761 : Number *number = (Number *) ast;
1945 : :
1946 : 478761 : if (strchr (number->token, '.') ||
1947 : 477692 : (!g_str_has_prefix (number->token, "0x") && strchr (number->token, 'e')) ||
1948 : 477692 : strstr (number->token, "inf") ||
1949 : 477690 : strstr (number->token, "nan"))
1950 : 1072 : return g_strdup ("Md");
1951 : :
1952 : 477689 : return g_strdup ("MN");
1953 : : }
1954 : :
1955 : : static GVariant *
1956 : 31 : number_overflow (AST *ast,
1957 : : const GVariantType *type,
1958 : : GError **error)
1959 : : {
1960 : 31 : ast_set_error (ast, error, NULL,
1961 : : G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE,
1962 : : "number out of range for type '%c'",
1963 : 31 : g_variant_type_peek_string (type)[0]);
1964 : 31 : return NULL;
1965 : : }
1966 : :
1967 : : static GVariant *
1968 : 943557 : number_get_value (AST *ast,
1969 : : const GVariantType *type,
1970 : : GError **error)
1971 : : {
1972 : 943557 : Number *number = (Number *) ast;
1973 : : const gchar *token;
1974 : : gboolean negative;
1975 : : gboolean floating;
1976 : : guint64 abs_val;
1977 : : gdouble dbl_val;
1978 : : gchar *end;
1979 : :
1980 : 943557 : token = number->token;
1981 : :
1982 : 943557 : if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
1983 : : {
1984 : 1577 : floating = TRUE;
1985 : :
1986 : 1577 : errno = 0;
1987 : 1577 : dbl_val = g_ascii_strtod (token, &end);
1988 : 1577 : if (dbl_val != 0.0 && errno == ERANGE)
1989 : : {
1990 : 2 : ast_set_error (ast, error, NULL,
1991 : : G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1992 : : "number too big for any type");
1993 : 2 : return NULL;
1994 : : }
1995 : :
1996 : : /* silence uninitialised warnings... */
1997 : 1575 : negative = FALSE;
1998 : 1575 : abs_val = 0;
1999 : : }
2000 : : else
2001 : : {
2002 : 941980 : floating = FALSE;
2003 : 941980 : negative = token[0] == '-';
2004 : 941980 : if (token[0] == '-')
2005 : 448402 : token++;
2006 : :
2007 : 941980 : errno = 0;
2008 : 941980 : abs_val = g_ascii_strtoull (token, &end, 0);
2009 : 941980 : if (abs_val == G_MAXUINT64 && errno == ERANGE)
2010 : : {
2011 : 6 : ast_set_error (ast, error, NULL,
2012 : : G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
2013 : : "integer too big for any type");
2014 : 6 : return NULL;
2015 : : }
2016 : :
2017 : 941974 : if (abs_val == 0)
2018 : 187 : negative = FALSE;
2019 : :
2020 : : /* silence uninitialised warning... */
2021 : 941974 : dbl_val = 0.0;
2022 : : }
2023 : :
2024 : 943549 : if (*end != '\0')
2025 : : {
2026 : : SourceRef ref;
2027 : :
2028 : 11 : ref = ast->source_ref;
2029 : 11 : ref.start += end - number->token;
2030 : 11 : ref.end = ref.start + 1;
2031 : :
2032 : 11 : parser_set_error (error, &ref, NULL,
2033 : : G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
2034 : : "invalid character in number");
2035 : 11 : return NULL;
2036 : : }
2037 : :
2038 : 943538 : if (floating)
2039 : 1573 : return g_variant_new_double (dbl_val);
2040 : :
2041 : 941965 : switch (*g_variant_type_peek_string (type))
2042 : : {
2043 : 19963 : case 'y':
2044 : 19963 : if (negative || abs_val > G_MAXUINT8)
2045 : 5 : return number_overflow (ast, type, error);
2046 : 19958 : return g_variant_new_byte (abs_val);
2047 : :
2048 : 876758 : case 'n':
2049 : 876758 : if (abs_val - negative > G_MAXINT16)
2050 : 4 : return number_overflow (ast, type, error);
2051 : 876754 : if (negative && abs_val > G_MAXINT16)
2052 : 14 : return g_variant_new_int16 (G_MININT16);
2053 : 1753480 : return g_variant_new_int16 (negative ?
2054 : 876740 : -((gint16) abs_val) : ((gint16) abs_val));
2055 : :
2056 : 1902 : case 'q':
2057 : 1902 : if (negative || abs_val > G_MAXUINT16)
2058 : 4 : return number_overflow (ast, type, error);
2059 : 1898 : return g_variant_new_uint16 (abs_val);
2060 : :
2061 : 19122 : case 'i':
2062 : 19122 : if (abs_val - negative > G_MAXINT32)
2063 : 4 : return number_overflow (ast, type, error);
2064 : 19118 : if (negative && abs_val > G_MAXINT32)
2065 : 3 : return g_variant_new_int32 (G_MININT32);
2066 : 28503 : return g_variant_new_int32 (negative ?
2067 : 9388 : -((gint32) abs_val) : ((gint32) abs_val));
2068 : :
2069 : 17429 : case 'u':
2070 : 17429 : if (negative || abs_val > G_MAXUINT32)
2071 : 4 : return number_overflow (ast, type, error);
2072 : 17425 : return g_variant_new_uint32 (abs_val);
2073 : :
2074 : 2042 : case 'x':
2075 : 2042 : if (abs_val - negative > G_MAXINT64)
2076 : 4 : return number_overflow (ast, type, error);
2077 : 2038 : if (negative && abs_val > G_MAXINT64)
2078 : 2 : return g_variant_new_int64 (G_MININT64);
2079 : 3037 : return g_variant_new_int64 (negative ?
2080 : 1001 : -((gint64) abs_val) : ((gint64) abs_val));
2081 : :
2082 : 2470 : case 't':
2083 : 2470 : if (negative)
2084 : 2 : return number_overflow (ast, type, error);
2085 : 2468 : return g_variant_new_uint64 (abs_val);
2086 : :
2087 : 2273 : case 'h':
2088 : 2273 : if (abs_val - negative > G_MAXINT32)
2089 : 4 : return number_overflow (ast, type, error);
2090 : 2269 : if (negative && abs_val > G_MAXINT32)
2091 : 1 : return g_variant_new_handle (G_MININT32);
2092 : 3412 : return g_variant_new_handle (negative ?
2093 : 1144 : -((gint32) abs_val) : ((gint32) abs_val));
2094 : :
2095 : 6 : default:
2096 : 6 : return ast_type_error (ast, type, error);
2097 : : }
2098 : : }
2099 : :
2100 : : static void
2101 : 943708 : number_free (AST *ast)
2102 : : {
2103 : 943708 : Number *number = (Number *) ast;
2104 : :
2105 : 943708 : g_free (number->token);
2106 : 943708 : g_slice_free (Number, number);
2107 : 943708 : }
2108 : :
2109 : : static AST *
2110 : 943708 : number_parse (TokenStream *stream,
2111 : : va_list *app,
2112 : : GError **error)
2113 : : {
2114 : : static const ASTClass number_class = {
2115 : : number_get_pattern,
2116 : : maybe_wrapper, number_get_value,
2117 : : number_free
2118 : : };
2119 : : Number *number;
2120 : :
2121 : 943708 : number = g_slice_new (Number);
2122 : 943708 : number->ast.class = &number_class;
2123 : 943708 : number->token = token_stream_get (stream);
2124 : 943708 : token_stream_next (stream);
2125 : :
2126 : 943708 : return (AST *) number;
2127 : : }
2128 : :
2129 : : typedef struct
2130 : : {
2131 : : AST ast;
2132 : : gboolean value;
2133 : : } Boolean;
2134 : :
2135 : : static gchar *
2136 : 853 : boolean_get_pattern (AST *ast,
2137 : : GError **error)
2138 : : {
2139 : 853 : return g_strdup ("Mb");
2140 : : }
2141 : :
2142 : : static GVariant *
2143 : 1747 : boolean_get_value (AST *ast,
2144 : : const GVariantType *type,
2145 : : GError **error)
2146 : : {
2147 : 1747 : Boolean *boolean = (Boolean *) ast;
2148 : :
2149 : 1747 : if (!g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
2150 : 4 : return ast_type_error (ast, type, error);
2151 : :
2152 : 1743 : return g_variant_new_boolean (boolean->value);
2153 : : }
2154 : :
2155 : : static void
2156 : 1747 : boolean_free (AST *ast)
2157 : : {
2158 : 1747 : Boolean *boolean = (Boolean *) ast;
2159 : :
2160 : 1747 : g_slice_free (Boolean, boolean);
2161 : 1747 : }
2162 : :
2163 : : static AST *
2164 : 1747 : boolean_new (gboolean value)
2165 : : {
2166 : : static const ASTClass boolean_class = {
2167 : : boolean_get_pattern,
2168 : : maybe_wrapper, boolean_get_value,
2169 : : boolean_free
2170 : : };
2171 : : Boolean *boolean;
2172 : :
2173 : 1747 : boolean = g_slice_new (Boolean);
2174 : 1747 : boolean->ast.class = &boolean_class;
2175 : 1747 : boolean->value = value;
2176 : :
2177 : 1747 : return (AST *) boolean;
2178 : : }
2179 : :
2180 : : typedef struct
2181 : : {
2182 : : AST ast;
2183 : :
2184 : : GVariant *value;
2185 : : } Positional;
2186 : :
2187 : : static gchar *
2188 : 388 : positional_get_pattern (AST *ast,
2189 : : GError **error)
2190 : : {
2191 : 388 : Positional *positional = (Positional *) ast;
2192 : :
2193 : 776 : return g_strdup (g_variant_get_type_string (positional->value));
2194 : : }
2195 : :
2196 : : static GVariant *
2197 : 404 : positional_get_value (AST *ast,
2198 : : const GVariantType *type,
2199 : : GError **error)
2200 : : {
2201 : 404 : Positional *positional = (Positional *) ast;
2202 : : GVariant *value;
2203 : :
2204 : 404 : g_assert (positional->value != NULL);
2205 : :
2206 : 404 : if G_UNLIKELY (!g_variant_is_of_type (positional->value, type))
2207 : 0 : return ast_type_error (ast, type, error);
2208 : :
2209 : : /* NOTE: if _get is called more than once then
2210 : : * things get messed up with respect to floating refs.
2211 : : *
2212 : : * fortunately, this function should only ever get called once.
2213 : : */
2214 : 404 : g_assert (positional->value != NULL);
2215 : 404 : value = positional->value;
2216 : 404 : positional->value = NULL;
2217 : :
2218 : 404 : return value;
2219 : : }
2220 : :
2221 : : static void
2222 : 404 : positional_free (AST *ast)
2223 : : {
2224 : 404 : Positional *positional = (Positional *) ast;
2225 : :
2226 : : /* if positional->value is set, just leave it.
2227 : : * memory management doesn't matter in case of programmer error.
2228 : : */
2229 : 404 : g_slice_free (Positional, positional);
2230 : 404 : }
2231 : :
2232 : : static AST *
2233 : 404 : positional_parse (TokenStream *stream,
2234 : : va_list *app,
2235 : : GError **error)
2236 : : {
2237 : : static const ASTClass positional_class = {
2238 : : positional_get_pattern,
2239 : : positional_get_value, NULL,
2240 : : positional_free
2241 : : };
2242 : : Positional *positional;
2243 : : const gchar *endptr;
2244 : : gchar *token;
2245 : :
2246 : 404 : token = token_stream_get (stream);
2247 : 404 : g_assert (token[0] == '%');
2248 : :
2249 : 404 : positional = g_slice_new (Positional);
2250 : 404 : positional->ast.class = &positional_class;
2251 : 404 : positional->value = g_variant_new_va (token + 1, &endptr, app);
2252 : :
2253 : 404 : if (*endptr || positional->value == NULL)
2254 : : {
2255 : 0 : token_stream_set_error (stream, error, TRUE,
2256 : : G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING,
2257 : : "invalid GVariant format string");
2258 : : /* memory management doesn't matter in case of programmer error. */
2259 : 0 : return NULL;
2260 : : }
2261 : :
2262 : 404 : token_stream_next (stream);
2263 : 404 : g_free (token);
2264 : :
2265 : 404 : return (AST *) positional;
2266 : : }
2267 : :
2268 : : typedef struct
2269 : : {
2270 : : AST ast;
2271 : :
2272 : : GVariantType *type;
2273 : : AST *child;
2274 : : } TypeDecl;
2275 : :
2276 : : static gchar *
2277 : 1913 : typedecl_get_pattern (AST *ast,
2278 : : GError **error)
2279 : : {
2280 : 1913 : TypeDecl *decl = (TypeDecl *) ast;
2281 : :
2282 : 1913 : return g_variant_type_dup_string (decl->type);
2283 : : }
2284 : :
2285 : : static GVariant *
2286 : 1909 : typedecl_get_value (AST *ast,
2287 : : const GVariantType *type,
2288 : : GError **error)
2289 : : {
2290 : 1909 : TypeDecl *decl = (TypeDecl *) ast;
2291 : :
2292 : 1909 : return ast_get_value (decl->child, type, error);
2293 : : }
2294 : :
2295 : : static void
2296 : 1913 : typedecl_free (AST *ast)
2297 : : {
2298 : 1913 : TypeDecl *decl = (TypeDecl *) ast;
2299 : :
2300 : 1913 : ast_free (decl->child);
2301 : 1913 : g_variant_type_free (decl->type);
2302 : 1913 : g_slice_free (TypeDecl, decl);
2303 : 1913 : }
2304 : :
2305 : : static AST *
2306 : 1925 : typedecl_parse (TokenStream *stream,
2307 : : guint max_depth,
2308 : : va_list *app,
2309 : : GError **error)
2310 : : {
2311 : : static const ASTClass typedecl_class = {
2312 : : typedecl_get_pattern,
2313 : : typedecl_get_value, NULL,
2314 : : typedecl_free
2315 : : };
2316 : : GVariantType *type;
2317 : : TypeDecl *decl;
2318 : : AST *child;
2319 : :
2320 : 1925 : if (token_stream_peek (stream, '@'))
2321 : : {
2322 : : gchar *token;
2323 : :
2324 : 374 : token = token_stream_get (stream);
2325 : :
2326 : 374 : if (!g_variant_type_string_is_valid (token + 1))
2327 : : {
2328 : 2 : token_stream_set_error (stream, error, TRUE,
2329 : : G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING,
2330 : : "invalid type declaration");
2331 : 2 : g_free (token);
2332 : :
2333 : 2 : return NULL;
2334 : : }
2335 : :
2336 : 372 : if (g_variant_type_string_get_depth_ (token + 1) > max_depth)
2337 : : {
2338 : 1 : token_stream_set_error (stream, error, TRUE,
2339 : : G_VARIANT_PARSE_ERROR_RECURSION,
2340 : : "type declaration recurses too deeply");
2341 : 1 : g_free (token);
2342 : :
2343 : 1 : return NULL;
2344 : : }
2345 : :
2346 : 371 : type = g_variant_type_new (token + 1);
2347 : :
2348 : 371 : if (!g_variant_type_is_definite (type))
2349 : : {
2350 : 2 : token_stream_set_error (stream, error, TRUE,
2351 : : G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED,
2352 : : "type declarations must be definite");
2353 : 2 : g_variant_type_free (type);
2354 : 2 : g_free (token);
2355 : :
2356 : 2 : return NULL;
2357 : : }
2358 : :
2359 : 369 : token_stream_next (stream);
2360 : 369 : g_free (token);
2361 : : }
2362 : : else
2363 : : {
2364 : 1551 : if (token_stream_consume (stream, "boolean"))
2365 : 2 : type = g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
2366 : :
2367 : 1549 : else if (token_stream_consume (stream, "byte"))
2368 : 153 : type = g_variant_type_copy (G_VARIANT_TYPE_BYTE);
2369 : :
2370 : 1396 : else if (token_stream_consume (stream, "int16"))
2371 : 193 : type = g_variant_type_copy (G_VARIANT_TYPE_INT16);
2372 : :
2373 : 1203 : else if (token_stream_consume (stream, "uint16"))
2374 : 186 : type = g_variant_type_copy (G_VARIANT_TYPE_UINT16);
2375 : :
2376 : 1017 : else if (token_stream_consume (stream, "int32"))
2377 : 5 : type = g_variant_type_copy (G_VARIANT_TYPE_INT32);
2378 : :
2379 : 1012 : else if (token_stream_consume (stream, "handle"))
2380 : 168 : type = g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
2381 : :
2382 : 844 : else if (token_stream_consume (stream, "uint32"))
2383 : 180 : type = g_variant_type_copy (G_VARIANT_TYPE_UINT32);
2384 : :
2385 : 664 : else if (token_stream_consume (stream, "int64"))
2386 : 174 : type = g_variant_type_copy (G_VARIANT_TYPE_INT64);
2387 : :
2388 : 490 : else if (token_stream_consume (stream, "uint64"))
2389 : 172 : type = g_variant_type_copy (G_VARIANT_TYPE_UINT64);
2390 : :
2391 : 318 : else if (token_stream_consume (stream, "double"))
2392 : 2 : type = g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
2393 : :
2394 : 316 : else if (token_stream_consume (stream, "string"))
2395 : 2 : type = g_variant_type_copy (G_VARIANT_TYPE_STRING);
2396 : :
2397 : 314 : else if (token_stream_consume (stream, "objectpath"))
2398 : 151 : type = g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
2399 : :
2400 : 163 : else if (token_stream_consume (stream, "signature"))
2401 : 158 : type = g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
2402 : :
2403 : : else
2404 : : {
2405 : 5 : token_stream_set_error (stream, error, TRUE,
2406 : : G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
2407 : : "unknown keyword");
2408 : 5 : return NULL;
2409 : : }
2410 : : }
2411 : :
2412 : 1915 : if ((child = parse (stream, max_depth - 1, app, error)) == NULL)
2413 : : {
2414 : 2 : g_variant_type_free (type);
2415 : 2 : return NULL;
2416 : : }
2417 : :
2418 : 1913 : decl = g_slice_new (TypeDecl);
2419 : 1913 : decl->ast.class = &typedecl_class;
2420 : 1913 : decl->type = type;
2421 : 1913 : decl->child = child;
2422 : :
2423 : 1913 : return (AST *) decl;
2424 : : }
2425 : :
2426 : : static AST *
2427 : 976472 : parse (TokenStream *stream,
2428 : : guint max_depth,
2429 : : va_list *app,
2430 : : GError **error)
2431 : : {
2432 : : SourceRef source_ref;
2433 : : AST *result;
2434 : :
2435 : 976472 : if (max_depth == 0)
2436 : : {
2437 : 1 : token_stream_set_error (stream, error, FALSE,
2438 : : G_VARIANT_PARSE_ERROR_RECURSION,
2439 : : "variant nested too deeply");
2440 : 1 : return NULL;
2441 : : }
2442 : :
2443 : 976471 : token_stream_prepare (stream);
2444 : 976471 : token_stream_start_ref (stream, &source_ref);
2445 : :
2446 : 976471 : if (token_stream_peek (stream, '['))
2447 : 15635 : result = array_parse (stream, max_depth, app, error);
2448 : :
2449 : 960836 : else if (token_stream_peek (stream, '('))
2450 : 2308 : result = tuple_parse (stream, max_depth, app, error);
2451 : :
2452 : 958528 : else if (token_stream_peek (stream, '<'))
2453 : 1232 : result = variant_parse (stream, max_depth, app, error);
2454 : :
2455 : 957296 : else if (token_stream_peek (stream, '{'))
2456 : 806 : result = dictionary_parse (stream, max_depth, app, error);
2457 : :
2458 : 956490 : else if (app && token_stream_peek (stream, '%'))
2459 : 404 : result = positional_parse (stream, app, error);
2460 : :
2461 : 956086 : else if (token_stream_consume (stream, "true"))
2462 : 875 : result = boolean_new (TRUE);
2463 : :
2464 : 955211 : else if (token_stream_consume (stream, "false"))
2465 : 872 : result = boolean_new (FALSE);
2466 : :
2467 : 964973 : else if (token_stream_is_numeric (stream) ||
2468 : 21266 : token_stream_peek_string (stream, "inf") ||
2469 : 10632 : token_stream_peek_string (stream, "nan"))
2470 : 943708 : result = number_parse (stream, app, error);
2471 : :
2472 : 20875 : else if (token_stream_peek (stream, 'n') ||
2473 : 10244 : token_stream_peek (stream, 'j'))
2474 : 403 : result = maybe_parse (stream, max_depth, app, error);
2475 : :
2476 : 20082 : else if (token_stream_peek (stream, '@') ||
2477 : 9854 : token_stream_is_keyword (stream))
2478 : 1925 : result = typedecl_parse (stream, max_depth, app, error);
2479 : :
2480 : 8368 : else if (token_stream_peek (stream, '\'') ||
2481 : 65 : token_stream_peek (stream, '"'))
2482 : 8259 : result = string_parse (stream, app, error);
2483 : :
2484 : 71 : else if (token_stream_peek2 (stream, 'b', '\'') ||
2485 : 27 : token_stream_peek2 (stream, 'b', '"'))
2486 : 27 : result = bytestring_parse (stream, app, error);
2487 : :
2488 : : else
2489 : : {
2490 : 17 : token_stream_set_error (stream, error, FALSE,
2491 : : G_VARIANT_PARSE_ERROR_VALUE_EXPECTED,
2492 : : "expected value");
2493 : 17 : return NULL;
2494 : : }
2495 : :
2496 : 976454 : if (result != NULL)
2497 : : {
2498 : 976191 : token_stream_end_ref (stream, &source_ref);
2499 : 976191 : result->source_ref = source_ref;
2500 : : }
2501 : :
2502 : 976454 : return result;
2503 : : }
2504 : :
2505 : : /**
2506 : : * g_variant_parse:
2507 : : * @type: (nullable): a #GVariantType, or %NULL
2508 : : * @text: a string containing a GVariant in text form
2509 : : * @limit: (nullable): a pointer to the end of @text, or %NULL
2510 : : * @endptr: (nullable): a location to store the end pointer, or %NULL
2511 : : * @error: (nullable): a pointer to a %NULL #GError pointer, or %NULL
2512 : : *
2513 : : * Parses a #GVariant from a text representation.
2514 : : *
2515 : : * A single #GVariant is parsed from the content of @text.
2516 : : *
2517 : : * The format is described [here](gvariant-text-format.html).
2518 : : *
2519 : : * The memory at @limit will never be accessed and the parser behaves as
2520 : : * if the character at @limit is the nul terminator. This has the
2521 : : * effect of bounding @text.
2522 : : *
2523 : : * If @endptr is non-%NULL then @text is permitted to contain data
2524 : : * following the value that this function parses and @endptr will be
2525 : : * updated to point to the first character past the end of the text
2526 : : * parsed by this function. If @endptr is %NULL and there is extra data
2527 : : * then an error is returned.
2528 : : *
2529 : : * If @type is non-%NULL then the value will be parsed to have that
2530 : : * type. This may result in additional parse errors (in the case that
2531 : : * the parsed value doesn't fit the type) but may also result in fewer
2532 : : * errors (in the case that the type would have been ambiguous, such as
2533 : : * with empty arrays).
2534 : : *
2535 : : * In the event that the parsing is successful, the resulting #GVariant
2536 : : * is returned. It is never floating, and must be freed with
2537 : : * [method@GLib.Variant.unref].
2538 : : *
2539 : : * In case of any error, %NULL will be returned. If @error is non-%NULL
2540 : : * then it will be set to reflect the error that occurred.
2541 : : *
2542 : : * Officially, the language understood by the parser is “any string
2543 : : * produced by [method@GLib.Variant.print]”. This explicitly includes
2544 : : * `g_variant_print()`’s annotated types like `int64 -1000`.
2545 : : *
2546 : : * There may be implementation specific restrictions on deeply nested values,
2547 : : * which would result in a %G_VARIANT_PARSE_ERROR_RECURSION error. #GVariant is
2548 : : * guaranteed to handle nesting up to at least 64 levels.
2549 : : *
2550 : : * Returns: a non-floating reference to a #GVariant, or %NULL
2551 : : **/
2552 : : GVariant *
2553 : 729 : g_variant_parse (const GVariantType *type,
2554 : : const gchar *text,
2555 : : const gchar *limit,
2556 : : const gchar **endptr,
2557 : : GError **error)
2558 : : {
2559 : 729 : TokenStream stream = { 0, };
2560 : 729 : GVariant *result = NULL;
2561 : : AST *ast;
2562 : :
2563 : 729 : g_return_val_if_fail (text != NULL, NULL);
2564 : 729 : g_return_val_if_fail (text == limit || text != NULL, NULL);
2565 : :
2566 : 729 : stream.start = text;
2567 : 729 : stream.stream = text;
2568 : 729 : stream.end = limit;
2569 : :
2570 : 729 : if ((ast = parse (&stream, G_VARIANT_MAX_RECURSION_DEPTH, NULL, error)))
2571 : : {
2572 : 604 : if (type == NULL)
2573 : 293 : result = ast_resolve (ast, error);
2574 : : else
2575 : 311 : result = ast_get_value (ast, type, error);
2576 : :
2577 : 604 : if (result != NULL)
2578 : : {
2579 : 466 : g_variant_ref_sink (result);
2580 : :
2581 : 466 : if (endptr == NULL)
2582 : : {
2583 : 474 : while (stream.stream != limit &&
2584 : 469 : g_ascii_isspace (*stream.stream))
2585 : 9 : stream.stream++;
2586 : :
2587 : 465 : if (stream.stream != limit && *stream.stream != '\0')
2588 : : {
2589 : 4 : SourceRef ref = { stream.stream - text,
2590 : 4 : stream.stream - text };
2591 : :
2592 : 4 : parser_set_error (error, &ref, NULL,
2593 : : G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END,
2594 : : "expected end of input");
2595 : 4 : g_variant_unref (result);
2596 : :
2597 : 4 : result = NULL;
2598 : : }
2599 : : }
2600 : : else
2601 : 1 : *endptr = stream.stream;
2602 : : }
2603 : :
2604 : 604 : ast_free (ast);
2605 : : }
2606 : :
2607 : 729 : return result;
2608 : : }
2609 : :
2610 : : /**
2611 : : * g_variant_new_parsed_va:
2612 : : * @format: a text format #GVariant
2613 : : * @app: a pointer to a #va_list
2614 : : *
2615 : : * Parses @format and returns the result.
2616 : : *
2617 : : * This is the version of g_variant_new_parsed() intended to be used
2618 : : * from libraries.
2619 : : *
2620 : : * The return value will be floating if it was a newly created GVariant
2621 : : * instance. In the case that @format simply specified the collection
2622 : : * of a #GVariant pointer (eg: @format was "%*") then the collected
2623 : : * #GVariant pointer will be returned unmodified, without adding any
2624 : : * additional references.
2625 : : *
2626 : : * Note that the arguments in @app must be of the correct width for their types
2627 : : * specified in @format when collected into the #va_list. See
2628 : : * the [GVariant varargs documentation](gvariant-format-strings.html#varargs).
2629 : : *
2630 : : * In order to behave correctly in all cases it is necessary for the
2631 : : * calling function to g_variant_ref_sink() the return result before
2632 : : * returning control to the user that originally provided the pointer.
2633 : : * At this point, the caller will have their own full reference to the
2634 : : * result. This can also be done by adding the result to a container,
2635 : : * or by passing it to another g_variant_new() call.
2636 : : *
2637 : : * Returns: a new, usually floating, #GVariant
2638 : : **/
2639 : : GVariant *
2640 : 566 : g_variant_new_parsed_va (const gchar *format,
2641 : : va_list *app)
2642 : : {
2643 : 566 : TokenStream stream = { 0, };
2644 : 566 : GVariant *result = NULL;
2645 : 566 : GError *error = NULL;
2646 : : AST *ast;
2647 : :
2648 : 566 : g_return_val_if_fail (format != NULL, NULL);
2649 : 566 : g_return_val_if_fail (app != NULL, NULL);
2650 : :
2651 : 566 : stream.start = format;
2652 : 566 : stream.stream = format;
2653 : 566 : stream.end = NULL;
2654 : :
2655 : 566 : if ((ast = parse (&stream, G_VARIANT_MAX_RECURSION_DEPTH, app, &error)))
2656 : : {
2657 : 566 : result = ast_resolve (ast, &error);
2658 : 566 : ast_free (ast);
2659 : : }
2660 : :
2661 : 566 : if (error != NULL)
2662 : 0 : g_error ("g_variant_new_parsed: %s", error->message);
2663 : :
2664 : 566 : if (*stream.stream)
2665 : 0 : g_error ("g_variant_new_parsed: trailing text after value");
2666 : :
2667 : 566 : g_clear_error (&error);
2668 : :
2669 : 566 : return result;
2670 : : }
2671 : :
2672 : : /**
2673 : : * g_variant_new_parsed:
2674 : : * @format: a text format #GVariant
2675 : : * @...: arguments as per @format
2676 : : *
2677 : : * Parses @format and returns the result.
2678 : : *
2679 : : * @format must be a text format #GVariant with one extension: at any
2680 : : * point that a value may appear in the text, a '%' character followed
2681 : : * by a GVariant format string (as per g_variant_new()) may appear. In
2682 : : * that case, the same arguments are collected from the argument list as
2683 : : * g_variant_new() would have collected.
2684 : : *
2685 : : * Note that the arguments must be of the correct width for their types
2686 : : * specified in @format. This can be achieved by casting them. See
2687 : : * the [GVariant varargs documentation](gvariant-format-strings.html#varargs).
2688 : : *
2689 : : * Consider this simple example:
2690 : : * |[<!-- language="C" -->
2691 : : * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2692 : : * ]|
2693 : : *
2694 : : * In the example, the variable argument parameters are collected and
2695 : : * filled in as if they were part of the original string to produce the
2696 : : * result of
2697 : : * |[<!-- language="C" -->
2698 : : * [('one', 1), ('two', 2), ('three', 3)]
2699 : : * ]|
2700 : : *
2701 : : * This function is intended only to be used with @format as a string
2702 : : * literal. Any parse error is fatal to the calling process. If you
2703 : : * want to parse data from untrusted sources, use g_variant_parse().
2704 : : *
2705 : : * You may not use this function to return, unmodified, a single
2706 : : * #GVariant pointer from the argument list. ie: @format may not solely
2707 : : * be anything along the lines of "%*", "%?", "\%r", or anything starting
2708 : : * with "%@".
2709 : : *
2710 : : * Returns: a new floating #GVariant instance
2711 : : **/
2712 : : GVariant *
2713 : 561 : g_variant_new_parsed (const gchar *format,
2714 : : ...)
2715 : : {
2716 : : GVariant *result;
2717 : : va_list ap;
2718 : :
2719 : 561 : va_start (ap, format);
2720 : 561 : result = g_variant_new_parsed_va (format, &ap);
2721 : 561 : va_end (ap);
2722 : :
2723 : 561 : return result;
2724 : : }
2725 : :
2726 : : /**
2727 : : * g_variant_builder_add_parsed:
2728 : : * @builder: a #GVariantBuilder
2729 : : * @format: a text format #GVariant
2730 : : * @...: arguments as per @format
2731 : : *
2732 : : * Adds to a #GVariantBuilder.
2733 : : *
2734 : : * This call is a convenience wrapper that is exactly equivalent to
2735 : : * calling g_variant_new_parsed() followed by
2736 : : * g_variant_builder_add_value().
2737 : : *
2738 : : * Note that the arguments must be of the correct width for their types
2739 : : * specified in @format_string. This can be achieved by casting them. See
2740 : : * the [GVariant varargs documentation](gvariant-format-strings.html#varargs).
2741 : : *
2742 : : * This function might be used as follows:
2743 : : *
2744 : : * |[<!-- language="C" -->
2745 : : * GVariant *
2746 : : * make_pointless_dictionary (void)
2747 : : * {
2748 : : * GVariantBuilder builder;
2749 : : * int i;
2750 : : *
2751 : : * g_variant_builder_init_static (&builder, G_VARIANT_TYPE_ARRAY);
2752 : : * g_variant_builder_add_parsed (&builder, "{'width', <%i>}", 600);
2753 : : * g_variant_builder_add_parsed (&builder, "{'title', <%s>}", "foo");
2754 : : * g_variant_builder_add_parsed (&builder, "{'transparency', <0.5>}");
2755 : : * return g_variant_builder_end (&builder);
2756 : : * }
2757 : : * ]|
2758 : : *
2759 : : * Since: 2.26
2760 : : */
2761 : : void
2762 : 5 : g_variant_builder_add_parsed (GVariantBuilder *builder,
2763 : : const gchar *format,
2764 : : ...)
2765 : : {
2766 : : va_list ap;
2767 : :
2768 : 5 : va_start (ap, format);
2769 : 5 : g_variant_builder_add_value (builder, g_variant_new_parsed_va (format, &ap));
2770 : 5 : va_end (ap);
2771 : 5 : }
2772 : :
2773 : : static gboolean
2774 : 12 : parse_num (const gchar *num,
2775 : : const gchar *limit,
2776 : : size_t *result)
2777 : : {
2778 : : gchar *endptr;
2779 : : gint64 bignum;
2780 : :
2781 : 12 : bignum = g_ascii_strtoll (num, &endptr, 10);
2782 : :
2783 : 12 : if (endptr != limit)
2784 : 0 : return FALSE;
2785 : :
2786 : : /* The upper bound here is more restrictive than it technically needs to be,
2787 : : * but should be enough for any practical situation: */
2788 : 12 : if (bignum < 0 || bignum > G_MAXINT)
2789 : 0 : return FALSE;
2790 : :
2791 : 12 : *result = (size_t) bignum;
2792 : :
2793 : 12 : return TRUE;
2794 : : }
2795 : :
2796 : : static void
2797 : 1 : add_last_line (GString *err,
2798 : : const gchar *str)
2799 : : {
2800 : : const gchar *last_nl;
2801 : : gchar *chomped;
2802 : : size_t i;
2803 : :
2804 : : /* This is an error at the end of input. If we have a file
2805 : : * with newlines, that's probably the empty string after the
2806 : : * last newline, which is not the most useful thing to show.
2807 : : *
2808 : : * Instead, show the last line of non-whitespace that we have
2809 : : * and put the pointer at the end of it.
2810 : : */
2811 : 1 : chomped = g_strchomp (g_strdup (str));
2812 : 1 : last_nl = strrchr (chomped, '\n');
2813 : 1 : if (last_nl == NULL)
2814 : 1 : last_nl = chomped;
2815 : : else
2816 : 0 : last_nl++;
2817 : :
2818 : : /* Print the last line like so:
2819 : : *
2820 : : * [1, 2, 3,
2821 : : * ^
2822 : : */
2823 : 1 : g_string_append (err, " ");
2824 : 1 : if (last_nl[0])
2825 : : g_string_append (err, last_nl);
2826 : : else
2827 : 0 : g_string_append (err, "(empty input)");
2828 : 1 : g_string_append (err, "\n ");
2829 : 3 : for (i = 0; last_nl[i]; i++)
2830 : : g_string_append_c (err, ' ');
2831 : 1 : g_string_append (err, "^\n");
2832 : 1 : g_free (chomped);
2833 : 1 : }
2834 : :
2835 : : static void
2836 : 5 : add_lines_from_range (GString *err,
2837 : : const gchar *str,
2838 : : const gchar *start1,
2839 : : const gchar *end1,
2840 : : const gchar *start2,
2841 : : const gchar *end2)
2842 : : {
2843 : 5 : while (str < end1 || str < end2)
2844 : : {
2845 : : const gchar *nl;
2846 : :
2847 : 5 : nl = str + strcspn (str, "\n");
2848 : :
2849 : 5 : if ((start1 < nl && str < end1) || (start2 < nl && str < end2))
2850 : : {
2851 : : const gchar *s;
2852 : :
2853 : : /* We're going to print this line */
2854 : 5 : g_string_append (err, " ");
2855 : 5 : g_string_append_len (err, str, nl - str);
2856 : 5 : g_string_append (err, "\n ");
2857 : :
2858 : : /* And add underlines... */
2859 : 68 : for (s = str; s < nl; s++)
2860 : : {
2861 : 63 : if ((start1 <= s && s < end1) || (start2 <= s && s < end2))
2862 : 30 : g_string_append_c (err, '^');
2863 : : else
2864 : : g_string_append_c (err, ' ');
2865 : : }
2866 : : g_string_append_c (err, '\n');
2867 : : }
2868 : :
2869 : 5 : if (!*nl)
2870 : 5 : break;
2871 : :
2872 : 0 : str = nl + 1;
2873 : : }
2874 : 5 : }
2875 : :
2876 : : /**
2877 : : * g_variant_parse_error_print_context:
2878 : : * @error: a #GError from the #GVariantParseError domain
2879 : : * @source_str: the string that was given to the parser
2880 : : *
2881 : : * Pretty-prints a message showing the context of a #GVariant parse
2882 : : * error within the string for which parsing was attempted.
2883 : : *
2884 : : * The resulting string is suitable for output to the console or other
2885 : : * monospace media where newlines are treated in the usual way.
2886 : : *
2887 : : * The message will typically look something like one of the following:
2888 : : *
2889 : : * |[
2890 : : * unterminated string constant:
2891 : : * (1, 2, 3, 'abc
2892 : : * ^^^^
2893 : : * ]|
2894 : : *
2895 : : * or
2896 : : *
2897 : : * |[
2898 : : * unable to find a common type:
2899 : : * [1, 2, 3, 'str']
2900 : : * ^ ^^^^^
2901 : : * ]|
2902 : : *
2903 : : * The format of the message may change in a future version.
2904 : : *
2905 : : * @error must have come from a failed attempt to g_variant_parse() and
2906 : : * @source_str must be exactly the same string that caused the error.
2907 : : * If @source_str was not nul-terminated when you passed it to
2908 : : * g_variant_parse() then you must add nul termination before using this
2909 : : * function.
2910 : : *
2911 : : * Returns: (transfer full): the printed message
2912 : : *
2913 : : * Since: 2.40
2914 : : **/
2915 : : gchar *
2916 : 6 : g_variant_parse_error_print_context (GError *error,
2917 : : const gchar *source_str)
2918 : : {
2919 : : const gchar *colon, *dash, *comma;
2920 : 6 : gboolean success = FALSE;
2921 : : GString *err;
2922 : :
2923 : 6 : g_return_val_if_fail (error->domain == G_VARIANT_PARSE_ERROR, FALSE);
2924 : :
2925 : : /* We can only have a limited number of possible types of ranges
2926 : : * emitted from the parser:
2927 : : *
2928 : : * - a: -- usually errors from the tokeniser (eof, invalid char, etc.)
2929 : : * - a-b: -- usually errors from handling one single token
2930 : : * - a-b,c-d: -- errors involving two tokens (ie: type inferencing)
2931 : : *
2932 : : * We never see, for example "a,c".
2933 : : */
2934 : :
2935 : 6 : colon = strchr (error->message, ':');
2936 : 6 : dash = strchr (error->message, '-');
2937 : 6 : comma = strchr (error->message, ',');
2938 : :
2939 : 6 : if (!colon)
2940 : 0 : return NULL;
2941 : :
2942 : 6 : err = g_string_new (colon + 1);
2943 : 6 : g_string_append (err, ":\n");
2944 : :
2945 : 6 : if (dash == NULL || colon < dash)
2946 : 2 : {
2947 : : size_t point;
2948 : :
2949 : : /* we have a single point */
2950 : 2 : if (!parse_num (error->message, colon, &point))
2951 : 0 : goto out;
2952 : :
2953 : 2 : if (point >= strlen (source_str))
2954 : : /* the error is at the end of the input */
2955 : 1 : add_last_line (err, source_str);
2956 : : else
2957 : : /* otherwise just treat it as an error at a thin range */
2958 : 1 : add_lines_from_range (err, source_str, source_str + point, source_str + point + 1, NULL, NULL);
2959 : : }
2960 : : else
2961 : : {
2962 : : /* We have one or two ranges... */
2963 : 4 : if (comma && comma < colon)
2964 : 1 : {
2965 : : size_t start1, end1, start2, end2;
2966 : : const gchar *dash2;
2967 : :
2968 : : /* Two ranges */
2969 : 1 : dash2 = strchr (comma, '-');
2970 : :
2971 : 2 : if (!parse_num (error->message, dash, &start1) || !parse_num (dash + 1, comma, &end1) ||
2972 : 2 : !parse_num (comma + 1, dash2, &start2) || !parse_num (dash2 + 1, colon, &end2))
2973 : 0 : goto out;
2974 : :
2975 : 1 : add_lines_from_range (err, source_str,
2976 : : source_str + start1, source_str + end1,
2977 : : source_str + start2, source_str + end2);
2978 : : }
2979 : : else
2980 : : {
2981 : : size_t start, end;
2982 : :
2983 : : /* One range */
2984 : 3 : if (!parse_num (error->message, dash, &start) || !parse_num (dash + 1, colon, &end))
2985 : 0 : goto out;
2986 : :
2987 : 3 : add_lines_from_range (err, source_str, source_str + start, source_str + end, NULL, NULL);
2988 : : }
2989 : : }
2990 : :
2991 : 6 : success = TRUE;
2992 : :
2993 : 6 : out:
2994 : 6 : return g_string_free (err, !success);
2995 : : }
|