Coverage Report

Created: 2025-11-16 06:56

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