LCOV - code coverage report
Current view: top level - glib/glib - gvariant-parser.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 1082 1122 96.4 %
Date: 2024-04-16 05:15:53 Functions: 85 85 100.0 %
Branches: 624 705 88.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright © 2009, 2010 Codethink Limited
       3                 :            :  *
       4                 :            :  * SPDX-License-Identifier: LGPL-2.1-or-later
       5                 :            :  *
       6                 :            :  * This library is free software; you can redistribute it and/or
       7                 :            :  * modify it under the terms of the GNU Lesser General Public
       8                 :            :  * License as published by the Free Software Foundation; either
       9                 :            :  * version 2.1 of the License, or (at your option) any later version.
      10                 :            :  *
      11                 :            :  * This library is distributed in the hope that it will be useful,
      12                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14                 :            :  * Lesser General Public License for more details.
      15                 :            :  *
      16                 :            :  * You should have received a copy of the GNU Lesser General Public
      17                 :            :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18                 :            :  *
      19                 :            :  * Author: Ryan Lortie <desrt@desrt.ca>
      20                 :            :  */
      21                 :            : 
      22                 :            : #include "config.h"
      23                 :            : 
      24                 :            : #include <stdlib.h>
      25                 :            : #include <string.h>
      26                 :            : #include <errno.h>
      27                 :            : 
      28                 :            : #include "gerror.h"
      29                 :            : #include "gquark.h"
      30                 :            : #include "gstring.h"
      31                 :            : #include "gstrfuncs.h"
      32                 :            : #include "gtestutils.h"
      33                 :            : #include "gvariant.h"
      34                 :            : #include "glib/gvariant-core.h"
      35                 :            : #include "gvariant-internal.h"
      36                 :            : #include "gvarianttype.h"
      37                 :            : #include "gslice.h"
      38                 :            : #include "gthread.h"
      39                 :            : 
      40                 :            : /*
      41                 :            :  * two-pass algorithm
      42                 :            :  * designed by ryan lortie and william hua
      43                 :            :  * designed in itb-229 and at ghazi's, 2009.
      44                 :            :  */
      45                 :            : 
      46                 :            : /**
      47                 :            :  * G_VARIANT_PARSE_ERROR:
      48                 :            :  *
      49                 :            :  * Error domain for GVariant text format parsing.  Specific error codes
      50                 :            :  * are not currently defined for this domain.  See #GError for
      51                 :            :  * information on error domains.
      52                 :            :  **/
      53                 :            : /**
      54                 :            :  * GVariantParseError:
      55                 :            :  * @G_VARIANT_PARSE_ERROR_FAILED: generic error (unused)
      56                 :            :  * @G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED: a non-basic #GVariantType was given where a basic type was expected
      57                 :            :  * @G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE: cannot infer the #GVariantType
      58                 :            :  * @G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED: an indefinite #GVariantType was given where a definite type was expected
      59                 :            :  * @G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END: extra data after parsing finished
      60                 :            :  * @G_VARIANT_PARSE_ERROR_INVALID_CHARACTER: invalid character in number or unicode escape
      61                 :            :  * @G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING: not a valid #GVariant format string
      62                 :            :  * @G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH: not a valid object path
      63                 :            :  * @G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE: not a valid type signature
      64                 :            :  * @G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING: not a valid #GVariant type string
      65                 :            :  * @G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE: could not find a common type for array entries
      66                 :            :  * @G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE: the numerical value is out of range of the given type
      67                 :            :  * @G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG: the numerical value is out of range for any type
      68                 :            :  * @G_VARIANT_PARSE_ERROR_TYPE_ERROR: cannot parse as variant of the specified type
      69                 :            :  * @G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN: an unexpected token was encountered
      70                 :            :  * @G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD: an unknown keyword was encountered
      71                 :            :  * @G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT: unterminated string constant
      72                 :            :  * @G_VARIANT_PARSE_ERROR_VALUE_EXPECTED: no value given
      73                 :            :  * @G_VARIANT_PARSE_ERROR_RECURSION: variant was too deeply nested; #GVariant is only guaranteed to handle nesting up to 64 levels (Since: 2.64)
      74                 :            :  *
      75                 :            :  * Error codes returned by parsing text-format GVariants.
      76                 :            :  **/
      77         [ +  + ]:        289 : G_DEFINE_QUARK (g-variant-parse-error-quark, g_variant_parse_error)
      78                 :            : 
      79                 :            : /**
      80                 :            :  * g_variant_parser_get_error_quark:
      81                 :            :  *
      82                 :            :  * Same as g_variant_error_quark().
      83                 :            :  *
      84                 :            :  * Deprecated: Use g_variant_parse_error_quark() instead.
      85                 :            :  */
      86                 :            : GQuark
      87                 :          2 : g_variant_parser_get_error_quark (void)
      88                 :            : {
      89                 :          2 :   return g_variant_parse_error_quark ();
      90                 :            : }
      91                 :            : 
      92                 :            : typedef struct
      93                 :            : {
      94                 :            :   gint start, end;
      95                 :            : } SourceRef;
      96                 :            : 
      97                 :            : G_GNUC_PRINTF(5, 0)
      98                 :            : static void
      99                 :        267 : parser_set_error_va (GError      **error,
     100                 :            :                      SourceRef    *location,
     101                 :            :                      SourceRef    *other,
     102                 :            :                      gint          code,
     103                 :            :                      const gchar  *format,
     104                 :            :                      va_list       ap)
     105                 :            : {
     106                 :        267 :   GString *msg = g_string_new (NULL);
     107                 :            : 
     108         [ +  + ]:        267 :   if (location->start == location->end)
     109                 :         77 :     g_string_append_printf (msg, "%d", location->start);
     110                 :            :   else
     111                 :        190 :     g_string_append_printf (msg, "%d-%d", location->start, location->end);
     112                 :            : 
     113         [ +  + ]:        267 :   if (other != NULL)
     114                 :            :     {
     115                 :         31 :       g_assert (other->start != other->end);
     116                 :         31 :       g_string_append_printf (msg, ",%d-%d", other->start, other->end);
     117                 :            :     }
     118                 :            :   g_string_append_c (msg, ':');
     119                 :            : 
     120                 :        267 :   g_string_append_vprintf (msg, format, ap);
     121                 :        267 :   g_set_error_literal (error, G_VARIANT_PARSE_ERROR, code, msg->str);
     122                 :        267 :   g_string_free (msg, TRUE);
     123                 :        267 : }
     124                 :            : 
     125                 :            : G_GNUC_PRINTF(5, 6)
     126                 :            : static void
     127                 :         74 : parser_set_error (GError      **error,
     128                 :            :                   SourceRef    *location,
     129                 :            :                   SourceRef    *other,
     130                 :            :                   gint          code,
     131                 :            :                   const gchar  *format,
     132                 :            :                   ...)
     133                 :            : {
     134                 :            :   va_list ap;
     135                 :            : 
     136                 :         74 :   va_start (ap, format);
     137                 :         74 :   parser_set_error_va (error, location, other, code, format, ap);
     138                 :         74 :   va_end (ap);
     139                 :         74 : }
     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                 :         66 : token_stream_set_error (TokenStream  *stream,
     154                 :            :                         GError      **error,
     155                 :            :                         gboolean      this_token,
     156                 :            :                         gint          code,
     157                 :            :                         const gchar  *format,
     158                 :            :                         ...)
     159                 :            : {
     160                 :            :   SourceRef ref;
     161                 :            :   va_list ap;
     162                 :            : 
     163                 :         66 :   ref.start = stream->this - stream->start;
     164                 :            : 
     165         [ +  + ]:         66 :   if (this_token)
     166                 :         14 :     ref.end = stream->stream - stream->start;
     167                 :            :   else
     168                 :         52 :     ref.end = ref.start;
     169                 :            : 
     170                 :         66 :   va_start (ap, format);
     171                 :         66 :   parser_set_error_va (error, &ref, NULL, code, format, ap);
     172                 :         66 :   va_end (ap);
     173                 :         66 : }
     174                 :            : 
     175                 :            : static gboolean
     176                 :   12278507 : token_stream_prepare (TokenStream *stream)
     177                 :            : {
     178                 :   12278507 :   gint brackets = 0;
     179                 :            :   const gchar *end;
     180                 :            : 
     181         [ +  + ]:   12278507 :   if (stream->this != NULL)
     182                 :   10249586 :     return TRUE;
     183                 :            : 
     184   [ +  +  +  + ]:    3021211 :   while (stream->stream != stream->end && g_ascii_isspace (*stream->stream))
     185                 :     992290 :     stream->stream++;
     186                 :            : 
     187   [ +  +  +  + ]:    2028921 :   if (stream->stream == stream->end || *stream->stream == '\0')
     188                 :            :     {
     189                 :         16 :       stream->this = stream->stream;
     190                 :         16 :       return FALSE;
     191                 :            :     }
     192                 :            : 
     193   [ +  +  +  +  :    2028905 :   switch (stream->stream[0])
                   +  + ]
     194                 :            :     {
     195                 :     939069 :     case '-': case '+': case '.': case '0': case '1': case '2':
     196                 :            :     case '3': case '4': case '5': case '6': case '7': case '8':
     197                 :            :     case '9':
     198         [ +  + ]:   14438821 :       for (end = stream->stream; end != stream->end; end++)
     199         [ +  + ]:   14438788 :         if (!g_ascii_isalnum (*end) &&
     200   [ +  +  +  -  :    1614087 :             *end != '-' && *end != '+' && *end != '.')
                   +  + ]
     201                 :     939036 :           break;
     202                 :     939069 :       break;
     203                 :            : 
     204                 :        300 :     case 'b':
     205         [ +  + ]:        300 :       if (stream->stream + 1 != stream->end &&
     206   [ +  +  +  + ]:        299 :           (stream->stream[1] == '\'' || stream->stream[1] == '"'))
     207                 :            :         {
     208         [ +  + ]:         89 :           for (end = stream->stream + 2; end != stream->end; end++)
     209   [ +  +  +  + ]:         81 :             if (*end == stream->stream[1] || *end == '\0' ||
     210   [ +  +  +  +  :         66 :                 (*end == '\\' && (++end == stream->end || *end == '\0')))
                   +  + ]
     211                 :            :               break;
     212                 :            : 
     213   [ +  +  +  + ]:         27 :           if (end != stream->end && *end)
     214                 :          7 :             end++;
     215                 :         27 :           break;
     216                 :            :         }
     217                 :            : 
     218                 :            :       G_GNUC_FALLTHROUGH;
     219                 :            : 
     220                 :            :     case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
     221                 :            :     case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
     222                 :            :     case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
     223                 :            :     case 's': case 't': case 'u': case 'v': case 'w': case 'x':
     224                 :            :     case 'y': case 'z':
     225         [ +  + ]:     132953 :       for (end = stream->stream; end != stream->end; end++)
     226         [ +  + ]:     132944 :         if (!g_ascii_isalnum (*end))
     227                 :      23061 :           break;
     228                 :      23070 :       break;
     229                 :            : 
     230                 :      29730 :     case '\'': case '"':
     231         [ +  + ]:    3078239 :       for (end = stream->stream + 1; end != stream->end; end++)
     232   [ +  +  +  + ]:    3078238 :         if (*end == stream->stream[0] || *end == '\0' ||
     233   [ +  +  +  +  :    3048511 :             (*end == '\\' && (++end == stream->end || *end == '\0')))
                   +  + ]
     234                 :            :           break;
     235                 :            : 
     236   [ +  +  +  + ]:      29730 :       if (end != stream->end && *end)
     237                 :      29725 :         end++;
     238                 :      29730 :       break;
     239                 :            : 
     240                 :        812 :     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                 :        812 :       for (end = stream->stream + 1;
     246   [ +  -  +  + ]:       2355 :            end != stream->end && *end != '\0' && *end != ',' &&
     247   [ +  -  +  +  :       4681 :            *end != ':' && *end != '>' && *end != ']' && !g_ascii_isspace (*end);
          +  +  +  -  +  
                      + ]
     248                 :       1543 :            end++)
     249                 :            : 
     250   [ +  +  +  + ]:       1551 :         if (*end == '(' || *end == '{')
     251                 :         62 :           brackets++;
     252                 :            : 
     253   [ +  +  +  +  :       1489 :         else if ((*end == ')' || *end == '}') && !brackets--)
                   +  + ]
     254                 :          8 :           break;
     255                 :            : 
     256                 :        812 :       break;
     257                 :            : 
     258                 :    1036197 :     default:
     259                 :    1036197 :       end = stream->stream + 1;
     260                 :    1036197 :       break;
     261                 :            :     }
     262                 :            : 
     263                 :    2028905 :   stream->this = stream->stream;
     264                 :    2028905 :   stream->stream = end;
     265                 :            : 
     266                 :            :   /* We must have at least one byte in a token. */
     267                 :    2028905 :   g_assert (stream->stream - stream->this >= 1);
     268                 :            : 
     269                 :    2028905 :   return TRUE;
     270                 :            : }
     271                 :            : 
     272                 :            : static void
     273                 :    2028796 : token_stream_next (TokenStream *stream)
     274                 :            : {
     275                 :    2028796 :   stream->this = NULL;
     276                 :    2028796 : }
     277                 :            : 
     278                 :            : static gboolean
     279                 :    4138951 : token_stream_peek (TokenStream *stream,
     280                 :            :                    gchar        first_char)
     281                 :            : {
     282         [ -  + ]:    4138951 :   if (!token_stream_prepare (stream))
     283                 :          0 :     return FALSE;
     284                 :            : 
     285         [ +  + ]:    8277794 :   return stream->stream - stream->this >= 1 &&
     286         [ +  + ]:    4138843 :          stream->this[0] == first_char;
     287                 :            : }
     288                 :            : 
     289                 :            : static gboolean
     290                 :         71 : token_stream_peek2 (TokenStream *stream,
     291                 :            :                     gchar        first_char,
     292                 :            :                     gchar        second_char)
     293                 :            : {
     294         [ -  + ]:         71 :   if (!token_stream_prepare (stream))
     295                 :          0 :     return FALSE;
     296                 :            : 
     297                 :        108 :   return stream->stream - stream->this >= 2 &&
     298   [ +  +  +  - ]:        108 :          stream->this[0] == first_char &&
     299         [ +  + ]:         37 :          stream->this[1] == second_char;
     300                 :            : }
     301                 :            : 
     302                 :            : static gboolean
     303                 :      32046 : token_stream_is_keyword (TokenStream *stream)
     304                 :            : {
     305         [ -  + ]:      32046 :   if (!token_stream_prepare (stream))
     306                 :          0 :     return FALSE;
     307                 :            : 
     308                 :      64075 :   return stream->stream - stream->this >= 2 &&
     309   [ +  +  +  + ]:      34345 :          g_ascii_isalpha (stream->this[0]) &&
     310         [ +  + ]:       2299 :          g_ascii_isalpha (stream->this[1]);
     311                 :            : }
     312                 :            : 
     313                 :            : static gboolean
     314                 :     972283 : token_stream_is_numeric (TokenStream *stream)
     315                 :            : {
     316         [ -  + ]:     972283 :   if (!token_stream_prepare (stream))
     317                 :          0 :     return FALSE;
     318                 :            : 
     319         [ +  + ]:    1944554 :   return (stream->stream - stream->this >= 1 &&
     320         [ +  + ]:     972271 :           (g_ascii_isdigit (stream->this[0]) ||
     321         [ +  + ]:     260868 :            stream->this[0] == '-' ||
     322         [ +  - ]:      33218 :            stream->this[0] == '+' ||
     323         [ -  + ]:      33218 :            stream->this[0] == '.'));
     324                 :            : }
     325                 :            : 
     326                 :            : static gboolean
     327                 :    4103290 : token_stream_peek_string (TokenStream *stream,
     328                 :            :                           const gchar *token)
     329                 :            : {
     330                 :    4103290 :   gint length = strlen (token);
     331                 :            : 
     332                 :    4103290 :   return token_stream_prepare (stream) &&
     333   [ +  +  +  + ]:    6178759 :          stream->stream - stream->this == length &&
     334         [ +  + ]:    2075469 :          memcmp (stream->this, token, length) == 0;
     335                 :            : }
     336                 :            : 
     337                 :            : static gboolean
     338                 :    4036832 : token_stream_consume (TokenStream *stream,
     339                 :            :                       const gchar *token)
     340                 :            : {
     341         [ +  + ]:    4036832 :   if (!token_stream_peek_string (stream, token))
     342                 :    2977597 :     return FALSE;
     343                 :            : 
     344                 :    1059235 :   token_stream_next (stream);
     345                 :    1059235 :   return TRUE;
     346                 :            : }
     347                 :            : 
     348                 :            : static gboolean
     349                 :     991570 : token_stream_require (TokenStream  *stream,
     350                 :            :                       const gchar  *token,
     351                 :            :                       const gchar  *purpose,
     352                 :            :                       GError      **error)
     353                 :            : {
     354                 :            : 
     355         [ +  + ]:     991570 :   if (!token_stream_consume (stream, token))
     356                 :            :     {
     357                 :         34 :       token_stream_set_error (stream, error, FALSE,
     358                 :            :                               G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN,
     359                 :            :                               "expected '%s'%s", token, purpose);
     360                 :         34 :       return FALSE;
     361                 :            :     }
     362                 :            : 
     363                 :     991536 :   return TRUE;
     364                 :            : }
     365                 :            : 
     366                 :            : static void
     367                 :      23535 : token_stream_assert (TokenStream *stream,
     368                 :            :                      const gchar *token)
     369                 :            : {
     370                 :            :   gboolean correct_token G_GNUC_UNUSED  /* when compiling with G_DISABLE_ASSERT */;
     371                 :            : 
     372                 :      23535 :   correct_token = token_stream_consume (stream, token);
     373                 :      23535 :   g_assert (correct_token);
     374                 :      23535 : }
     375                 :            : 
     376                 :            : static gchar *
     377                 :     969625 : token_stream_get (TokenStream *stream)
     378                 :            : {
     379                 :            :   gchar *result;
     380                 :            : 
     381         [ -  + ]:     969625 :   if (!token_stream_prepare (stream))
     382                 :          0 :     return NULL;
     383                 :            : 
     384                 :     969625 :   result = g_strndup (stream->this, stream->stream - stream->this);
     385                 :            : 
     386                 :     969625 :   return result;
     387                 :            : }
     388                 :            : 
     389                 :            : static void
     390                 :    1045999 : token_stream_start_ref (TokenStream *stream,
     391                 :            :                         SourceRef   *ref)
     392                 :            : {
     393                 :    1045999 :   token_stream_prepare (stream);
     394                 :    1045999 :   ref->start = stream->this - stream->start;
     395                 :    1045999 : }
     396                 :            : 
     397                 :            : static void
     398                 :    1045719 : token_stream_end_ref (TokenStream *stream,
     399                 :            :                       SourceRef   *ref)
     400                 :            : {
     401                 :    1045719 :   ref->end = stream->stream - stream->start;
     402                 :    1045719 : }
     403                 :            : 
     404                 :            : static void
     405                 :        371 : pattern_copy (gchar       **out,
     406                 :            :               const gchar **in)
     407                 :            : {
     408                 :        371 :   gint brackets = 0;
     409                 :            : 
     410   [ +  +  -  +  :        558 :   while (**in == 'a' || **in == 'm' || **in == 'M')
                   +  + ]
     411                 :        187 :     *(*out)++ = *(*in)++;
     412                 :            : 
     413                 :            :   do
     414                 :            :     {
     415   [ +  -  +  + ]:        383 :       if (**in == '(' || **in == '{')
     416                 :          4 :         brackets++;
     417                 :            : 
     418   [ +  -  +  + ]:        379 :       else if (**in == ')' || **in == '}')
     419                 :          4 :         brackets--;
     420                 :            : 
     421                 :        383 :       *(*out)++ = *(*in)++;
     422                 :            :     }
     423         [ +  + ]:        383 :   while (brackets);
     424                 :        371 : }
     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                 :     473743 : pattern_coalesce (const gchar *left,
     430                 :            :                   const gchar *right)
     431                 :            : {
     432                 :            :   gchar *result;
     433                 :            :   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                 :     473743 :   out = result = g_malloc (strlen (left) + strlen (right));
     443                 :            : 
     444   [ +  +  +  - ]:    1486897 :   while (*left && *right)
     445                 :            :     {
     446         [ +  + ]:    1013216 :       if (*left == *right)
     447                 :            :         {
     448                 :     990912 :           *out++ = *left++;
     449                 :     990912 :           right++;
     450                 :            :         }
     451                 :            : 
     452                 :            :       else
     453                 :            :         {
     454                 :      22304 :           const gchar **one = &left, **the_other = &right;
     455                 :            : 
     456                 :      44589 :          again:
     457   [ +  +  +  - ]:      44589 :           if (**one == '*' && **the_other != ')')
     458                 :            :             {
     459                 :        371 :               pattern_copy (&out, the_other);
     460                 :        371 :               (*one)++;
     461                 :            :             }
     462                 :            : 
     463   [ +  +  +  + ]:      44218 :           else if (**one == 'M' && **the_other == 'm')
     464                 :            :             {
     465                 :        355 :               *out++ = *(*the_other)++;
     466                 :            :             }
     467                 :            : 
     468   [ +  +  +  -  :      43863 :           else if (**one == 'M' && **the_other != 'm' && **the_other != '*')
                   +  + ]
     469                 :            :             {
     470                 :      10696 :               (*one)++;
     471                 :            :             }
     472                 :            : 
     473   [ +  +  +  + ]:      33167 :           else if (**one == 'N' && strchr ("ynqiuxthd", **the_other))
     474                 :            :             {
     475                 :       8820 :               *out++ = *(*the_other)++;
     476                 :       8820 :               (*one)++;
     477                 :            :             }
     478                 :            : 
     479   [ +  +  +  + ]:      24347 :           else if (**one == 'S' && strchr ("sog", **the_other))
     480                 :            :             {
     481                 :       2000 :               *out++ = *(*the_other)++;
     482                 :       2000 :               (*one)++;
     483                 :            :             }
     484                 :            : 
     485         [ +  + ]:      22347 :           else if (one == &left)
     486                 :            :             {
     487                 :      22285 :               one = &right, the_other = &left;
     488                 :      22285 :               goto again;
     489                 :            :             }
     490                 :            : 
     491                 :            :           else
     492                 :         62 :             break;
     493                 :            :         }
     494                 :            :     }
     495                 :            : 
     496   [ +  +  -  + ]:     473743 :   if (*left || *right)
     497                 :            :     {
     498                 :         62 :       g_free (result);
     499                 :         62 :       result = NULL;
     500                 :            :     }
     501                 :            :   else
     502                 :     473681 :     *out++ = '\0';
     503                 :            : 
     504                 :     473743 :   return result;
     505                 :            : }
     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                 :     511277 : ast_get_pattern (AST     *ast,
     539                 :            :                  GError **error)
     540                 :            : {
     541                 :     511277 :   return ast->class->get_pattern (ast, error);
     542                 :            : }
     543                 :            : 
     544                 :            : static GVariant *
     545                 :    1015703 : ast_get_value (AST                 *ast,
     546                 :            :                const GVariantType  *type,
     547                 :            :                GError             **error)
     548                 :            : {
     549                 :    1015703 :   return ast->class->get_value (ast, type, error);
     550                 :            : }
     551                 :            : 
     552                 :            : static void
     553                 :    1015962 : ast_free (AST *ast)
     554                 :            : {
     555                 :    1015962 :   ast->class->free (ast);
     556                 :    1015962 : }
     557                 :            : 
     558                 :            : G_GNUC_PRINTF(5, 6)
     559                 :            : static void
     560                 :        127 : ast_set_error (AST          *ast,
     561                 :            :                GError      **error,
     562                 :            :                AST          *other_ast,
     563                 :            :                gint          code,
     564                 :            :                const gchar  *format,
     565                 :            :                ...)
     566                 :            : {
     567                 :            :   va_list ap;
     568                 :            : 
     569                 :        127 :   va_start (ap, format);
     570         [ +  + ]:        127 :   parser_set_error_va (error, &ast->source_ref,
     571                 :            :                        other_ast ? & other_ast->source_ref : NULL,
     572                 :            :                        code,
     573                 :            :                        format, ap);
     574                 :        127 :   va_end (ap);
     575                 :        127 : }
     576                 :            : 
     577                 :            : static GVariant *
     578                 :         43 : ast_type_error (AST                 *ast,
     579                 :            :                 const GVariantType  *type,
     580                 :            :                 GError             **error)
     581                 :            : {
     582                 :            :   gchar *typestr;
     583                 :            : 
     584                 :         43 :   typestr = g_variant_type_dup_string (type);
     585                 :         43 :   ast_set_error (ast, error, NULL,
     586                 :            :                  G_VARIANT_PARSE_ERROR_TYPE_ERROR,
     587                 :            :                  "can not parse as value of type '%s'",
     588                 :            :                  typestr);
     589                 :         43 :   g_free (typestr);
     590                 :            : 
     591                 :         43 :   return NULL;
     592                 :            : }
     593                 :            : 
     594                 :            : static GVariant *
     595                 :       3058 : ast_resolve (AST     *ast,
     596                 :            :              GError **error)
     597                 :            : {
     598                 :            :   GVariant *value;
     599                 :            :   gchar *pattern;
     600                 :       3058 :   gint i, j = 0;
     601                 :            : 
     602                 :       3058 :   pattern = ast_get_pattern (ast, error);
     603                 :            : 
     604         [ +  + ]:       3058 :   if (pattern == NULL)
     605                 :         35 :     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         [ +  + ]:      12712 :   for (i = 0; pattern[i]; i++)
     614   [ +  +  +  +  :       9695 :     switch (pattern[i])
                      + ]
     615                 :            :       {
     616                 :          6 :       case '*':
     617                 :          6 :         ast_set_error (ast, error, NULL,
     618                 :            :                        G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE,
     619                 :            :                        "unable to infer type");
     620                 :          6 :         g_free (pattern);
     621                 :          6 :         return NULL;
     622                 :            : 
     623                 :       2650 :       case 'M':
     624                 :       2650 :         break;
     625                 :            : 
     626                 :        365 :       case 'S':
     627                 :        365 :         pattern[j++] = 's';
     628                 :        365 :         break;
     629                 :            : 
     630                 :        309 :       case 'N':
     631                 :        309 :         pattern[j++] = 'i';
     632                 :        309 :         break;
     633                 :            : 
     634                 :       6365 :       default:
     635                 :       6365 :         pattern[j++] = pattern[i];
     636                 :       6365 :         break;
     637                 :            :       }
     638                 :       3017 :   pattern[j++] = '\0';
     639                 :            : 
     640                 :       3017 :   value = ast_get_value (ast, G_VARIANT_TYPE (pattern), error);
     641                 :       3017 :   g_free (pattern);
     642                 :            : 
     643                 :       3017 :   return value;
     644                 :            : }
     645                 :            : 
     646                 :            : 
     647                 :            : static AST *parse (TokenStream  *stream,
     648                 :            :                    guint         max_depth,
     649                 :            :                    va_list      *app,
     650                 :            :                    GError      **error);
     651                 :            : 
     652                 :            : static void
     653                 :    1009870 : ast_array_append (AST  ***array,
     654                 :            :                   gint   *n_items,
     655                 :            :                   AST    *ast)
     656                 :            : {
     657         [ +  + ]:    1009870 :   if ((*n_items & (*n_items - 1)) == 0)
     658         [ +  + ]:     126680 :     *array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
     659                 :            : 
     660                 :    1009870 :   (*array)[(*n_items)++] = ast;
     661                 :    1009870 : }
     662                 :            : 
     663                 :            : static void
     664                 :      22631 : ast_array_free (AST  **array,
     665                 :            :                 gint   n_items)
     666                 :            : {
     667                 :            :   gint i;
     668                 :            : 
     669         [ +  + ]:    1032501 :   for (i = 0; i < n_items; i++)
     670                 :    1009870 :     ast_free (array[i]);
     671                 :      22631 :   g_free (array);
     672                 :      22631 : }
     673                 :            : 
     674                 :            : static gchar *
     675                 :       8650 : ast_array_get_pattern (AST    **array,
     676                 :            :                        gint     n_items,
     677                 :            :                        GError **error)
     678                 :            : {
     679                 :            :   gchar *pattern;
     680                 :            :   gint i;
     681                 :            : 
     682                 :            :   /* Find the pattern which applies to all children in the array, by l-folding a
     683                 :            :    * coalesce operation.
     684                 :            :    */
     685                 :       8650 :   pattern = ast_get_pattern (array[0], error);
     686                 :            : 
     687         [ +  + ]:       8650 :   if (pattern == NULL)
     688                 :          4 :     return NULL;
     689                 :            : 
     690         [ +  + ]:     482325 :   for (i = 1; i < n_items; i++)
     691                 :            :     {
     692                 :            :       gchar *tmp, *merged;
     693                 :            : 
     694                 :     473712 :       tmp = ast_get_pattern (array[i], error);
     695                 :            : 
     696         [ +  + ]:     473712 :       if (tmp == NULL)
     697                 :            :         {
     698                 :          2 :           g_free (pattern);
     699                 :          2 :           return NULL;
     700                 :            :         }
     701                 :            : 
     702                 :     473710 :       merged = pattern_coalesce (pattern, tmp);
     703                 :     473710 :       g_free (pattern);
     704                 :     473710 :       pattern = merged;
     705                 :            : 
     706         [ +  + ]:     473710 :       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                 :            :         {
     712                 :         31 :           int j = 0;
     713                 :            : 
     714                 :            :           while (TRUE)
     715                 :          2 :             {
     716                 :            :               gchar *tmp2;
     717                 :            :               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         [ -  + ]:         33 :               if (j >= i)
     724                 :            :                 {
     725                 :          0 :                   ast_set_error (array[i], error, NULL,
     726                 :            :                                  G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE,
     727                 :            :                                  "unable to find a common type");
     728                 :          0 :                   g_free (tmp);
     729                 :          0 :                   return NULL;
     730                 :            :                 }
     731                 :            : 
     732                 :         33 :               tmp2 = ast_get_pattern (array[j], NULL);
     733                 :         33 :               g_assert (tmp2 != NULL);
     734                 :            : 
     735                 :         33 :               m = pattern_coalesce (tmp, tmp2);
     736                 :         33 :               g_free (tmp2);
     737                 :         33 :               g_free (m);
     738                 :            : 
     739         [ +  + ]:         33 :               if (m == NULL)
     740                 :            :                 {
     741                 :            :                   /* we found a conflict between 'i' and 'j'.
     742                 :            :                    *
     743                 :            :                    * report the error.  note: 'j' is first.
     744                 :            :                    */
     745                 :         31 :                   ast_set_error (array[j], error, array[i],
     746                 :            :                                  G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE,
     747                 :            :                                  "unable to find a common type");
     748                 :         31 :                   g_free (tmp);
     749                 :         31 :                   return NULL;
     750                 :            :                 }
     751                 :            : 
     752                 :          2 :               j++;
     753                 :            :             }
     754                 :            : 
     755                 :            :         }
     756                 :            : 
     757                 :     473679 :       g_free (tmp);
     758                 :            :     }
     759                 :            : 
     760                 :       8613 :   return pattern;
     761                 :            : }
     762                 :            : 
     763                 :            : typedef struct
     764                 :            : {
     765                 :            :   AST ast;
     766                 :            : 
     767                 :            :   AST *child;
     768                 :            : } Maybe;
     769                 :            : 
     770                 :            : static gchar *
     771                 :        305 : maybe_get_pattern (AST     *ast,
     772                 :            :                    GError **error)
     773                 :            : {
     774                 :        305 :   Maybe *maybe = (Maybe *) ast;
     775                 :            : 
     776         [ +  + ]:        305 :   if (maybe->child != NULL)
     777                 :            :     {
     778                 :            :       gchar *child_pattern;
     779                 :            :       gchar *pattern;
     780                 :            : 
     781                 :          2 :       child_pattern = ast_get_pattern (maybe->child, error);
     782                 :            : 
     783         [ +  - ]:          2 :       if (child_pattern == NULL)
     784                 :          2 :         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                 :            :     }
     791                 :            : 
     792                 :        303 :   return g_strdup ("m*");
     793                 :            : }
     794                 :            : 
     795                 :            : static GVariant *
     796                 :        731 : maybe_get_value (AST                 *ast,
     797                 :            :                  const GVariantType  *type,
     798                 :            :                  GError             **error)
     799                 :            : {
     800                 :        731 :   Maybe *maybe = (Maybe *) ast;
     801                 :            :   GVariant *value;
     802                 :            : 
     803         [ +  + ]:        731 :   if (!g_variant_type_is_maybe (type))
     804                 :          4 :     return ast_type_error (ast, type, error);
     805                 :            : 
     806                 :        727 :   type = g_variant_type_element (type);
     807                 :            : 
     808         [ +  + ]:        727 :   if (maybe->child)
     809                 :            :     {
     810                 :          8 :       value = ast_get_value (maybe->child, type, error);
     811                 :            : 
     812         [ +  + ]:          8 :       if (value == NULL)
     813                 :          2 :         return NULL;
     814                 :            :     }
     815                 :            :   else
     816                 :        719 :     value = NULL;
     817                 :            : 
     818                 :        725 :   return g_variant_new_maybe (type, value);
     819                 :            : }
     820                 :            : 
     821                 :            : static void
     822                 :        735 : maybe_free (AST *ast)
     823                 :            : {
     824                 :        735 :   Maybe *maybe = (Maybe *) ast;
     825                 :            : 
     826         [ +  + ]:        735 :   if (maybe->child != NULL)
     827                 :         12 :     ast_free (maybe->child);
     828                 :            : 
     829                 :        735 :   g_slice_free (Maybe, maybe);
     830                 :        735 : }
     831                 :            : 
     832                 :            : static AST *
     833                 :        741 : maybe_parse (TokenStream  *stream,
     834                 :            :              guint         max_depth,
     835                 :            :              va_list      *app,
     836                 :            :              GError      **error)
     837                 :            : {
     838                 :            :   static const ASTClass maybe_class = {
     839                 :            :     maybe_get_pattern,
     840                 :            :     maybe_get_value, NULL,
     841                 :            :     maybe_free
     842                 :            :   };
     843                 :        741 :   AST *child = NULL;
     844                 :            :   Maybe *maybe;
     845                 :            : 
     846         [ +  + ]:        741 :   if (token_stream_consume (stream, "just"))
     847                 :            :     {
     848                 :         14 :       child = parse (stream, max_depth - 1, app, error);
     849         [ +  + ]:         14 :       if (child == NULL)
     850                 :          2 :         return NULL;
     851                 :            :     }
     852                 :            : 
     853         [ +  + ]:        727 :   else if (!token_stream_consume (stream, "nothing"))
     854                 :            :     {
     855                 :          4 :       token_stream_set_error (stream, error, TRUE,
     856                 :            :                               G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
     857                 :            :                               "unknown keyword");
     858                 :          4 :       return NULL;
     859                 :            :     }
     860                 :            : 
     861                 :        735 :   maybe = g_slice_new (Maybe);
     862                 :        735 :   maybe->ast.class = &maybe_class;
     863                 :        735 :   maybe->child = child;
     864                 :            : 
     865                 :        735 :   return (AST *) maybe;
     866                 :            : }
     867                 :            : 
     868                 :            : static GVariant *
     869                 :    1011904 : maybe_wrapper (AST                 *ast,
     870                 :            :                const GVariantType  *type,
     871                 :            :                GError             **error)
     872                 :            : {
     873                 :            :   const GVariantType *base_type;
     874                 :            :   GVariant *base_value;
     875                 :    1011904 :   GVariant *value = NULL;
     876                 :            :   unsigned int depth;
     877                 :            :   gboolean trusted;
     878                 :    1011904 :   GVariantTypeInfo *base_type_info = NULL;
     879                 :            :   gsize base_serialised_fixed_size, base_serialised_size, serialised_size, n_suffix_zeros;
     880                 :    1011904 :   guint8 *serialised = NULL;
     881                 :    1011904 :   GBytes *bytes = NULL;
     882                 :            :   gsize i;
     883                 :            : 
     884                 :    1011904 :   for (depth = 0, base_type = type;
     885         [ +  + ]:    1012777 :        g_variant_type_is_maybe (base_type);
     886                 :        873 :        depth++, base_type = g_variant_type_element (base_type));
     887                 :            : 
     888                 :    1011904 :   base_value = ast->class->get_base_value (ast, base_type, error);
     889                 :            : 
     890   [ +  +  +  + ]:    1011904 :   if (base_value == NULL || depth == 0)
     891                 :    1011037 :     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                 :        867 :   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                 :        867 :   base_type_info = g_variant_type_info_get (base_type);
     928                 :        867 :   g_variant_type_info_query (base_type_info, NULL, &base_serialised_fixed_size);
     929                 :        867 :   g_variant_type_info_unref (base_type_info);
     930                 :            : 
     931                 :        867 :   base_serialised_size = g_variant_get_size (base_value);
     932         [ +  + ]:        867 :   n_suffix_zeros = (base_serialised_fixed_size > 0) ? depth - 1 : depth;
     933                 :        867 :   g_assert (base_serialised_size <= G_MAXSIZE - n_suffix_zeros);
     934                 :        867 :   serialised_size = base_serialised_size + n_suffix_zeros;
     935                 :            : 
     936                 :        867 :   g_assert (serialised_size >= base_serialised_size);
     937                 :            : 
     938                 :            :   /* Serialise the base value. */
     939                 :        867 :   serialised = g_malloc (serialised_size);
     940                 :        867 :   g_variant_store (base_value, serialised);
     941                 :            : 
     942                 :            :   /* Zero-out the suffix zeros to complete the serialisation of the maybe wrappers. */
     943         [ +  + ]:       1372 :   for (i = base_serialised_size; i < serialised_size; i++)
     944                 :        505 :     serialised[i] = 0;
     945                 :            : 
     946                 :        867 :   bytes = g_bytes_new_take (g_steal_pointer (&serialised), serialised_size);
     947                 :        867 :   value = g_variant_new_from_bytes (type, bytes, trusted);
     948                 :        867 :   g_bytes_unref (bytes);
     949                 :            : 
     950                 :        867 :   g_variant_unref (base_value);
     951                 :            : 
     952                 :        867 :   return g_steal_pointer (&value);
     953                 :            : }
     954                 :            : 
     955                 :            : typedef struct
     956                 :            : {
     957                 :            :   AST ast;
     958                 :            : 
     959                 :            :   AST **children;
     960                 :            :   gint n_children;
     961                 :            : } Array;
     962                 :            : 
     963                 :            : static gchar *
     964                 :       8080 : array_get_pattern (AST     *ast,
     965                 :            :                    GError **error)
     966                 :            : {
     967                 :       8080 :   Array *array = (Array *) ast;
     968                 :            :   gchar *pattern;
     969                 :            :   gchar *result;
     970                 :            : 
     971         [ +  + ]:       8080 :   if (array->n_children == 0)
     972                 :         76 :     return g_strdup ("Ma*");
     973                 :            : 
     974                 :       8004 :   pattern = ast_array_get_pattern (array->children, array->n_children, error);
     975                 :            : 
     976         [ +  + ]:       8004 :   if (pattern == NULL)
     977                 :         35 :     return NULL;
     978                 :            : 
     979                 :       7969 :   result = g_strdup_printf ("Ma%s", pattern);
     980                 :       7969 :   g_free (pattern);
     981                 :            : 
     982                 :       7969 :   return result;
     983                 :            : }
     984                 :            : 
     985                 :            : static GVariant *
     986                 :      15562 : array_get_value (AST                 *ast,
     987                 :            :                  const GVariantType  *type,
     988                 :            :                  GError             **error)
     989                 :            : {
     990                 :      15562 :   Array *array = (Array *) ast;
     991                 :            :   const GVariantType *childtype;
     992                 :            :   GVariantBuilder builder;
     993                 :            :   gint i;
     994                 :            : 
     995         [ +  + ]:      15562 :   if (!g_variant_type_is_array (type))
     996                 :          6 :     return ast_type_error (ast, type, error);
     997                 :            : 
     998                 :      15556 :   g_variant_builder_init (&builder, type);
     999                 :      15556 :   childtype = g_variant_type_element (type);
    1000                 :            : 
    1001         [ +  + ]:     973380 :   for (i = 0; i < array->n_children; i++)
    1002                 :            :     {
    1003                 :            :       GVariant *child;
    1004                 :            : 
    1005         [ +  + ]:     957826 :       if (!(child = ast_get_value (array->children[i], childtype, error)))
    1006                 :            :         {
    1007                 :          2 :           g_variant_builder_clear (&builder);
    1008                 :          2 :           return NULL;
    1009                 :            :         }
    1010                 :            : 
    1011                 :     957824 :       g_variant_builder_add_value (&builder, child);
    1012                 :            :     }
    1013                 :            : 
    1014                 :      15554 :   return g_variant_builder_end (&builder);
    1015                 :            : }
    1016                 :            : 
    1017                 :            : static void
    1018                 :      15623 : array_free (AST *ast)
    1019                 :            : {
    1020                 :      15623 :   Array *array = (Array *) ast;
    1021                 :            : 
    1022                 :      15623 :   ast_array_free (array->children, array->n_children);
    1023                 :      15623 :   g_slice_free (Array, array);
    1024                 :      15623 : }
    1025                 :            : 
    1026                 :            : static AST *
    1027                 :      15635 : array_parse (TokenStream  *stream,
    1028                 :            :              guint         max_depth,
    1029                 :            :              va_list      *app,
    1030                 :            :              GError      **error)
    1031                 :            : {
    1032                 :            :   static const ASTClass array_class = {
    1033                 :            :     array_get_pattern,
    1034                 :            :     maybe_wrapper, array_get_value,
    1035                 :            :     array_free
    1036                 :            :   };
    1037                 :      15635 :   gboolean need_comma = FALSE;
    1038                 :            :   Array *array;
    1039                 :            : 
    1040                 :      15635 :   array = g_slice_new (Array);
    1041                 :      15635 :   array->ast.class = &array_class;
    1042                 :      15635 :   array->children = NULL;
    1043                 :      15635 :   array->n_children = 0;
    1044                 :            : 
    1045                 :      15635 :   token_stream_assert (stream, "[");
    1046         [ +  + ]:     973587 :   while (!token_stream_consume (stream, "]"))
    1047                 :            :     {
    1048                 :            :       AST *child;
    1049                 :            : 
    1050   [ +  +  +  + ]:    1900451 :       if (need_comma &&
    1051                 :     942487 :           !token_stream_require (stream, ",",
    1052                 :            :                                  " or ']' to follow array element",
    1053                 :            :                                  error))
    1054                 :          9 :         goto error;
    1055                 :            : 
    1056                 :     957955 :       child = parse (stream, max_depth - 1, app, error);
    1057                 :            : 
    1058         [ +  + ]:     957955 :       if (!child)
    1059                 :          3 :         goto error;
    1060                 :            : 
    1061                 :     957952 :       ast_array_append (&array->children, &array->n_children, child);
    1062                 :     957952 :       need_comma = TRUE;
    1063                 :            :     }
    1064                 :            : 
    1065                 :      15623 :   return (AST *) array;
    1066                 :            : 
    1067                 :         12 :  error:
    1068                 :         12 :   ast_array_free (array->children, array->n_children);
    1069                 :         12 :   g_slice_free (Array, array);
    1070                 :            : 
    1071                 :         12 :   return NULL;
    1072                 :            : }
    1073                 :            : 
    1074                 :            : typedef struct
    1075                 :            : {
    1076                 :            :   AST ast;
    1077                 :            : 
    1078                 :            :   AST **children;
    1079                 :            :   gint n_children;
    1080                 :            : } Tuple;
    1081                 :            : 
    1082                 :            : static gchar *
    1083                 :       2467 : tuple_get_pattern (AST     *ast,
    1084                 :            :                    GError **error)
    1085                 :            : {
    1086                 :       2467 :   Tuple *tuple = (Tuple *) ast;
    1087                 :       2467 :   gchar *result = NULL;
    1088                 :            :   gchar **parts;
    1089                 :            :   gint i;
    1090                 :            : 
    1091                 :       2467 :   parts = g_new (gchar *, tuple->n_children + 4);
    1092                 :       2467 :   parts[tuple->n_children + 1] = (gchar *) ")";
    1093                 :       2467 :   parts[tuple->n_children + 2] = NULL;
    1094                 :       2467 :   parts[0] = (gchar *) "M(";
    1095                 :            : 
    1096         [ +  + ]:      27647 :   for (i = 0; i < tuple->n_children; i++)
    1097         [ +  + ]:      25182 :     if (!(parts[i + 1] = ast_get_pattern (tuple->children[i], error)))
    1098                 :          2 :       break;
    1099                 :            : 
    1100         [ +  + ]:       2467 :   if (i == tuple->n_children)
    1101                 :       2465 :     result = g_strjoinv ("", parts);
    1102                 :            : 
    1103                 :            :   /* parts[0] should not be freed */
    1104         [ +  + ]:      27647 :   while (i)
    1105                 :      25180 :     g_free (parts[i--]);
    1106                 :       2467 :   g_free (parts);
    1107                 :            : 
    1108                 :       2467 :   return result;
    1109                 :            : }
    1110                 :            : 
    1111                 :            : static GVariant *
    1112                 :       4269 : tuple_get_value (AST                 *ast,
    1113                 :            :                  const GVariantType  *type,
    1114                 :            :                  GError             **error)
    1115                 :            : {
    1116                 :       4269 :   Tuple *tuple = (Tuple *) ast;
    1117                 :            :   const GVariantType *childtype;
    1118                 :            :   GVariantBuilder builder;
    1119                 :            :   gint i;
    1120                 :            : 
    1121         [ +  + ]:       4269 :   if (!g_variant_type_is_tuple (type))
    1122                 :          4 :     return ast_type_error (ast, type, error);
    1123                 :            : 
    1124                 :       4265 :   g_variant_builder_init (&builder, type);
    1125                 :       4265 :   childtype = g_variant_type_first (type);
    1126                 :            : 
    1127         [ +  + ]:      52808 :   for (i = 0; i < tuple->n_children; i++)
    1128                 :            :     {
    1129                 :            :       GVariant *child;
    1130                 :            : 
    1131         [ -  + ]:      48545 :       if (childtype == NULL)
    1132                 :            :         {
    1133                 :          0 :           g_variant_builder_clear (&builder);
    1134                 :          0 :           return ast_type_error (ast, type, error);
    1135                 :            :         }
    1136                 :            : 
    1137         [ +  + ]:      48545 :       if (!(child = ast_get_value (tuple->children[i], childtype, error)))
    1138                 :            :         {
    1139                 :          2 :           g_variant_builder_clear (&builder);
    1140                 :          2 :           return FALSE;
    1141                 :            :         }
    1142                 :            : 
    1143                 :      48543 :       g_variant_builder_add_value (&builder, child);
    1144                 :      48543 :       childtype = g_variant_type_next (childtype);
    1145                 :            :     }
    1146                 :            : 
    1147         [ -  + ]:       4263 :   if (childtype != NULL)
    1148                 :            :     {
    1149                 :          0 :       g_variant_builder_clear (&builder);
    1150                 :          0 :       return ast_type_error (ast, type, error);
    1151                 :            :     }
    1152                 :            : 
    1153                 :       4263 :   return g_variant_builder_end (&builder);
    1154                 :            : }
    1155                 :            : 
    1156                 :            : static void
    1157                 :       4271 : tuple_free (AST *ast)
    1158                 :            : {
    1159                 :       4271 :   Tuple *tuple = (Tuple *) ast;
    1160                 :            : 
    1161                 :       4271 :   ast_array_free (tuple->children, tuple->n_children);
    1162                 :       4271 :   g_slice_free (Tuple, tuple);
    1163                 :       4271 : }
    1164                 :            : 
    1165                 :            : static AST *
    1166                 :       4288 : tuple_parse (TokenStream  *stream,
    1167                 :            :              guint         max_depth,
    1168                 :            :              va_list      *app,
    1169                 :            :              GError      **error)
    1170                 :            : {
    1171                 :            :   static const ASTClass tuple_class = {
    1172                 :            :     tuple_get_pattern,
    1173                 :            :     maybe_wrapper, tuple_get_value,
    1174                 :            :     tuple_free
    1175                 :            :   };
    1176                 :       4288 :   gboolean need_comma = FALSE;
    1177                 :       4288 :   gboolean first = TRUE;
    1178                 :            :   Tuple *tuple;
    1179                 :            : 
    1180                 :       4288 :   tuple = g_slice_new (Tuple);
    1181                 :       4288 :   tuple->ast.class = &tuple_class;
    1182                 :       4288 :   tuple->children = NULL;
    1183                 :       4288 :   tuple->n_children = 0;
    1184                 :            : 
    1185                 :       4288 :   token_stream_assert (stream, "(");
    1186         [ +  + ]:      52848 :   while (!token_stream_consume (stream, ")"))
    1187                 :            :     {
    1188                 :            :       AST *child;
    1189                 :            : 
    1190   [ +  +  +  + ]:      88997 :       if (need_comma &&
    1191                 :      40420 :           !token_stream_require (stream, ",",
    1192                 :            :                                  " or ')' to follow tuple element",
    1193                 :            :                                  error))
    1194                 :          2 :         goto error;
    1195                 :            : 
    1196                 :      48575 :       child = parse (stream, max_depth - 1, app, error);
    1197                 :            : 
    1198         [ +  + ]:      48575 :       if (!child)
    1199                 :         11 :         goto error;
    1200                 :            : 
    1201                 :      48564 :       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         [ +  + ]:      48564 :       if (first)
    1210                 :            :         {
    1211         [ +  + ]:       4262 :           if (!token_stream_require (stream, ",",
    1212                 :            :                                      " after first tuple element", error))
    1213                 :          4 :             goto error;
    1214                 :            : 
    1215                 :       4258 :           first = FALSE;
    1216                 :            :         }
    1217                 :            :       else
    1218                 :      44302 :         need_comma = TRUE;
    1219                 :            :     }
    1220                 :            : 
    1221                 :       4271 :   return (AST *) tuple;
    1222                 :            : 
    1223                 :         17 :  error:
    1224                 :         17 :   ast_array_free (tuple->children, tuple->n_children);
    1225                 :         17 :   g_slice_free (Tuple, tuple);
    1226                 :            : 
    1227                 :         17 :   return NULL;
    1228                 :            : }
    1229                 :            : 
    1230                 :            : typedef struct
    1231                 :            : {
    1232                 :            :   AST ast;
    1233                 :            : 
    1234                 :            :   AST *value;
    1235                 :            : } Variant;
    1236                 :            : 
    1237                 :            : static gchar *
    1238                 :       1101 : variant_get_pattern (AST     *ast,
    1239                 :            :                      GError **error)
    1240                 :            : {
    1241                 :       1101 :   return g_strdup ("Mv");
    1242                 :            : }
    1243                 :            : 
    1244                 :            : static GVariant *
    1245                 :       2245 : variant_get_value (AST                 *ast,
    1246                 :            :                    const GVariantType  *type,
    1247                 :            :                    GError             **error)
    1248                 :            : {
    1249                 :       2245 :   Variant *variant = (Variant *) ast;
    1250                 :            :   GVariant *child;
    1251                 :            : 
    1252         [ -  + ]:       2245 :   if (!g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
    1253                 :          0 :     return ast_type_error (ast, type, error);
    1254                 :            : 
    1255                 :       2245 :   child = ast_resolve (variant->value, error);
    1256                 :            : 
    1257         [ +  + ]:       2245 :   if (child == NULL)
    1258                 :          2 :     return NULL;
    1259                 :            : 
    1260                 :       2243 :   return g_variant_new_variant (child);
    1261                 :            : }
    1262                 :            : 
    1263                 :            : static void
    1264                 :       2245 : variant_free (AST *ast)
    1265                 :            : {
    1266                 :       2245 :   Variant *variant = (Variant *) ast;
    1267                 :            : 
    1268                 :       2245 :   ast_free (variant->value);
    1269                 :       2245 :   g_slice_free (Variant, variant);
    1270                 :       2245 : }
    1271                 :            : 
    1272                 :            : static AST *
    1273                 :       2258 : variant_parse (TokenStream  *stream,
    1274                 :            :                guint         max_depth,
    1275                 :            :                va_list      *app,
    1276                 :            :                GError      **error)
    1277                 :            : {
    1278                 :            :   static const ASTClass variant_class = {
    1279                 :            :     variant_get_pattern,
    1280                 :            :     maybe_wrapper, variant_get_value,
    1281                 :            :     variant_free
    1282                 :            :   };
    1283                 :            :   Variant *variant;
    1284                 :            :   AST *value;
    1285                 :            : 
    1286                 :       2258 :   token_stream_assert (stream, "<");
    1287                 :       2258 :   value = parse (stream, max_depth - 1, app, error);
    1288                 :            : 
    1289         [ +  + ]:       2258 :   if (!value)
    1290                 :          2 :     return NULL;
    1291                 :            : 
    1292         [ +  + ]:       2256 :   if (!token_stream_require (stream, ">", " to follow variant value", error))
    1293                 :            :     {
    1294                 :         11 :       ast_free (value);
    1295                 :         11 :       return NULL;
    1296                 :            :     }
    1297                 :            : 
    1298                 :       2245 :   variant = g_slice_new (Variant);
    1299                 :       2245 :   variant->ast.class = &variant_class;
    1300                 :       2245 :   variant->value = value;
    1301                 :            : 
    1302                 :       2245 :   return (AST *) variant;
    1303                 :            : }
    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                 :        648 : dictionary_get_pattern (AST     *ast,
    1316                 :            :                         GError **error)
    1317                 :            : {
    1318                 :        648 :   Dictionary *dict = (Dictionary *) ast;
    1319                 :            :   gchar *value_pattern;
    1320                 :            :   gchar *key_pattern;
    1321                 :            :   gchar key_char;
    1322                 :            :   gchar *result;
    1323                 :            : 
    1324         [ +  + ]:        648 :   if (dict->n_children == 0)
    1325                 :          2 :     return g_strdup ("Ma{**}");
    1326                 :            : 
    1327                 :        646 :   key_pattern = ast_array_get_pattern (dict->keys,
    1328                 :        646 :                                        abs (dict->n_children),
    1329                 :            :                                        error);
    1330                 :            : 
    1331         [ +  + ]:        646 :   if (key_pattern == NULL)
    1332                 :          2 :     return NULL;
    1333                 :            : 
    1334                 :            :   /* we can not have maybe keys */
    1335         [ +  + ]:        644 :   if (key_pattern[0] == 'M')
    1336                 :        556 :     key_char = key_pattern[1];
    1337                 :            :   else
    1338                 :         88 :     key_char = key_pattern[0];
    1339                 :            : 
    1340                 :        644 :   g_free (key_pattern);
    1341                 :            : 
    1342                 :            :   /* the basic types,
    1343                 :            :    * plus undetermined number type and undetermined string type.
    1344                 :            :    */
    1345         [ +  + ]:        644 :   if (!strchr ("bynqiuxthdsogNS", key_char))
    1346                 :            :     {
    1347                 :          4 :       ast_set_error (ast, error, NULL,
    1348                 :            :                      G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED,
    1349                 :            :                      "dictionary keys must have basic types");
    1350                 :          4 :       return NULL;
    1351                 :            :     }
    1352                 :            : 
    1353                 :        640 :   value_pattern = ast_get_pattern (dict->values[0], error);
    1354                 :            : 
    1355         [ +  + ]:        640 :   if (value_pattern == NULL)
    1356                 :          2 :     return NULL;
    1357                 :            : 
    1358                 :        638 :   result = g_strdup_printf ("M%s{%c%s}",
    1359         [ +  + ]:        638 :                             dict->n_children > 0 ? "a" : "",
    1360                 :            :                             key_char, value_pattern);
    1361                 :        638 :   g_free (value_pattern);
    1362                 :            : 
    1363                 :        638 :   return result;
    1364                 :            : }
    1365                 :            : 
    1366                 :            : static GVariant *
    1367                 :       1200 : dictionary_get_value (AST                 *ast,
    1368                 :            :                       const GVariantType  *type,
    1369                 :            :                       GError             **error)
    1370                 :            : {
    1371                 :       1200 :   Dictionary *dict = (Dictionary *) ast;
    1372                 :            : 
    1373         [ +  + ]:       1200 :   if (dict->n_children == -1)
    1374                 :            :     {
    1375                 :            :       const GVariantType *subtype;
    1376                 :            :       GVariantBuilder builder;
    1377                 :            :       GVariant *subvalue;
    1378                 :            : 
    1379         [ +  + ]:       1157 :       if (!g_variant_type_is_dict_entry (type))
    1380                 :          2 :         return ast_type_error (ast, type, error);
    1381                 :            : 
    1382                 :       1155 :       g_variant_builder_init (&builder, type);
    1383                 :            : 
    1384                 :       1155 :       subtype = g_variant_type_key (type);
    1385         [ +  + ]:       1155 :       if (!(subvalue = ast_get_value (dict->keys[0], subtype, error)))
    1386                 :            :         {
    1387                 :          2 :           g_variant_builder_clear (&builder);
    1388                 :          2 :           return NULL;
    1389                 :            :         }
    1390                 :       1153 :       g_variant_builder_add_value (&builder, subvalue);
    1391                 :            : 
    1392                 :       1153 :       subtype = g_variant_type_value (type);
    1393         [ +  + ]:       1153 :       if (!(subvalue = ast_get_value (dict->values[0], subtype, error)))
    1394                 :            :         {
    1395                 :          2 :           g_variant_builder_clear (&builder);
    1396                 :          2 :           return NULL;
    1397                 :            :         }
    1398                 :       1151 :       g_variant_builder_add_value (&builder, subvalue);
    1399                 :            : 
    1400                 :       1151 :       return g_variant_builder_end (&builder);
    1401                 :            :     }
    1402                 :            :   else
    1403                 :            :     {
    1404                 :            :       const GVariantType *entry, *key, *val;
    1405                 :            :       GVariantBuilder builder;
    1406                 :            :       gint i;
    1407                 :            : 
    1408         [ +  + ]:         43 :       if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
    1409                 :          3 :         return ast_type_error (ast, type, error);
    1410                 :            : 
    1411                 :         40 :       entry = g_variant_type_element (type);
    1412                 :         40 :       key = g_variant_type_key (entry);
    1413                 :         40 :       val = g_variant_type_value (entry);
    1414                 :            : 
    1415                 :         40 :       g_variant_builder_init (&builder, type);
    1416                 :            : 
    1417         [ +  + ]:        533 :       for (i = 0; i < dict->n_children; i++)
    1418                 :            :         {
    1419                 :            :           GVariant *subvalue;
    1420                 :            : 
    1421                 :        497 :           g_variant_builder_open (&builder, entry);
    1422                 :            : 
    1423         [ +  + ]:        497 :           if (!(subvalue = ast_get_value (dict->keys[i], key, error)))
    1424                 :            :             {
    1425                 :          2 :               g_variant_builder_clear (&builder);
    1426                 :          2 :               return NULL;
    1427                 :            :             }
    1428                 :        495 :           g_variant_builder_add_value (&builder, subvalue);
    1429                 :            : 
    1430         [ +  + ]:        495 :           if (!(subvalue = ast_get_value (dict->values[i], val, error)))
    1431                 :            :             {
    1432                 :          2 :               g_variant_builder_clear (&builder);
    1433                 :          2 :               return NULL;
    1434                 :            :             }
    1435                 :        493 :           g_variant_builder_add_value (&builder, subvalue);
    1436                 :        493 :           g_variant_builder_close (&builder);
    1437                 :            :         }
    1438                 :            : 
    1439                 :         36 :       return g_variant_builder_end (&builder);
    1440                 :            :     }
    1441                 :            : }
    1442                 :            : 
    1443                 :            : static void
    1444                 :       1210 : dictionary_free (AST *ast)
    1445                 :            : {
    1446                 :       1210 :   Dictionary *dict = (Dictionary *) ast;
    1447                 :            :   gint n_children;
    1448                 :            : 
    1449         [ +  + ]:       1210 :   if (dict->n_children > -1)
    1450                 :         47 :     n_children = dict->n_children;
    1451                 :            :   else
    1452                 :       1163 :     n_children = 1;
    1453                 :            : 
    1454                 :       1210 :   ast_array_free (dict->keys, n_children);
    1455                 :       1210 :   ast_array_free (dict->values, n_children);
    1456                 :       1210 :   g_slice_free (Dictionary, dict);
    1457                 :       1210 : }
    1458                 :            : 
    1459                 :            : static AST *
    1460                 :       1354 : dictionary_parse (TokenStream  *stream,
    1461                 :            :                   guint         max_depth,
    1462                 :            :                   va_list      *app,
    1463                 :            :                   GError      **error)
    1464                 :            : {
    1465                 :            :   static const ASTClass dictionary_class = {
    1466                 :            :     dictionary_get_pattern,
    1467                 :            :     maybe_wrapper, dictionary_get_value,
    1468                 :            :     dictionary_free
    1469                 :            :   };
    1470                 :            :   gint n_keys, n_values;
    1471                 :            :   gboolean only_one;
    1472                 :            :   Dictionary *dict;
    1473                 :            :   AST *first;
    1474                 :            : 
    1475                 :       1354 :   dict = g_slice_new (Dictionary);
    1476                 :       1354 :   dict->ast.class = &dictionary_class;
    1477                 :       1354 :   dict->keys = NULL;
    1478                 :       1354 :   dict->values = NULL;
    1479                 :       1354 :   n_keys = n_values = 0;
    1480                 :            : 
    1481                 :       1354 :   token_stream_assert (stream, "{");
    1482                 :            : 
    1483         [ +  + ]:       1354 :   if (token_stream_consume (stream, "}"))
    1484                 :            :     {
    1485                 :          5 :       dict->n_children = 0;
    1486                 :          5 :       return (AST *) dict;
    1487                 :            :     }
    1488                 :            : 
    1489         [ +  + ]:       1349 :   if ((first = parse (stream, max_depth - 1, app, error)) == NULL)
    1490                 :        130 :     goto error;
    1491                 :            : 
    1492                 :       1219 :   ast_array_append (&dict->keys, &n_keys, first);
    1493                 :            : 
    1494                 :       1219 :   only_one = token_stream_consume (stream, ",");
    1495   [ +  +  +  + ]:       1271 :   if (!only_one &&
    1496                 :         52 :       !token_stream_require (stream, ":",
    1497                 :            :                              " or ',' to follow dictionary entry key",
    1498                 :            :                              error))
    1499                 :          2 :     goto error;
    1500                 :            : 
    1501         [ +  + ]:       1217 :   if ((first = parse (stream, max_depth - 1, app, error)) == NULL)
    1502                 :          2 :     goto error;
    1503                 :            : 
    1504                 :       1215 :   ast_array_append (&dict->values, &n_values, first);
    1505                 :            : 
    1506         [ +  + ]:       1215 :   if (only_one)
    1507                 :            :     {
    1508         [ +  + ]:       1165 :       if (!token_stream_require (stream, "}", " at end of dictionary entry",
    1509                 :            :                                  error))
    1510                 :          2 :         goto error;
    1511                 :            : 
    1512                 :       1163 :       g_assert (n_keys == 1 && n_values == 1);
    1513                 :       1163 :       dict->n_children = -1;
    1514                 :            : 
    1515                 :       1163 :       return (AST *) dict;
    1516                 :            :     }
    1517                 :            : 
    1518         [ +  + ]:        508 :   while (!token_stream_consume (stream, "}"))
    1519                 :            :     {
    1520                 :            :       AST *child;
    1521                 :            : 
    1522         [ +  + ]:        466 :       if (!token_stream_require (stream, ",",
    1523                 :            :                                  " or '}' to follow dictionary entry", error))
    1524                 :          2 :         goto error;
    1525                 :            : 
    1526                 :        464 :       child = parse (stream, max_depth - 1, app, error);
    1527                 :            : 
    1528         [ +  + ]:        464 :       if (!child)
    1529                 :          2 :         goto error;
    1530                 :            : 
    1531                 :        462 :       ast_array_append (&dict->keys, &n_keys, child);
    1532                 :            : 
    1533         [ +  + ]:        462 :       if (!token_stream_require (stream, ":",
    1534                 :            :                                  " to follow dictionary entry key", error))
    1535                 :          2 :         goto error;
    1536                 :            : 
    1537                 :        460 :       child = parse (stream, max_depth - 1, app, error);
    1538                 :            : 
    1539         [ +  + ]:        460 :       if (!child)
    1540                 :          2 :         goto error;
    1541                 :            : 
    1542                 :        458 :       ast_array_append (&dict->values, &n_values, child);
    1543                 :            :     }
    1544                 :            : 
    1545                 :         42 :   g_assert (n_keys == n_values);
    1546                 :         42 :   dict->n_children = n_keys;
    1547                 :            : 
    1548                 :         42 :   return (AST *) dict;
    1549                 :            : 
    1550                 :        144 :  error:
    1551                 :        144 :   ast_array_free (dict->keys, n_keys);
    1552                 :        144 :   ast_array_free (dict->values, n_values);
    1553                 :        144 :   g_slice_free (Dictionary, dict);
    1554                 :            : 
    1555                 :        144 :   return NULL;
    1556                 :            : }
    1557                 :            : 
    1558                 :            : typedef struct
    1559                 :            : {
    1560                 :            :   AST ast;
    1561                 :            :   gchar *string;
    1562                 :            : } String;
    1563                 :            : 
    1564                 :            : static gchar *
    1565                 :      15264 : string_get_pattern (AST     *ast,
    1566                 :            :                     GError **error)
    1567                 :            : {
    1568                 :      15264 :   return g_strdup ("MS");
    1569                 :            : }
    1570                 :            : 
    1571                 :            : static GVariant *
    1572                 :      29664 : string_get_value (AST                 *ast,
    1573                 :            :                   const GVariantType  *type,
    1574                 :            :                   GError             **error)
    1575                 :            : {
    1576                 :      29664 :   String *string = (String *) ast;
    1577                 :            : 
    1578         [ +  + ]:      29664 :   if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
    1579                 :      23102 :     return g_variant_new_string (string->string);
    1580                 :            : 
    1581         [ +  + ]:       6562 :   else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
    1582                 :            :     {
    1583         [ +  + ]:       2034 :       if (!g_variant_is_object_path (string->string))
    1584                 :            :         {
    1585                 :          2 :           ast_set_error (ast, error, NULL,
    1586                 :            :                          G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH,
    1587                 :            :                          "not a valid object path");
    1588                 :          2 :           return NULL;
    1589                 :            :         }
    1590                 :            : 
    1591                 :       2032 :       return g_variant_new_object_path (string->string);
    1592                 :            :     }
    1593                 :            : 
    1594         [ +  + ]:       4528 :   else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
    1595                 :            :     {
    1596         [ +  + ]:       4514 :       if (!g_variant_is_signature (string->string))
    1597                 :            :         {
    1598                 :          2 :           ast_set_error (ast, error, NULL,
    1599                 :            :                          G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE,
    1600                 :            :                          "not a valid signature");
    1601                 :          2 :           return NULL;
    1602                 :            :         }
    1603                 :            : 
    1604                 :       4512 :       return g_variant_new_signature (string->string);
    1605                 :            :     }
    1606                 :            : 
    1607                 :            :   else
    1608                 :         14 :     return ast_type_error (ast, type, error);
    1609                 :            : }
    1610                 :            : 
    1611                 :            : static void
    1612                 :      29691 : string_free (AST *ast)
    1613                 :            : {
    1614                 :      29691 :   String *string = (String *) ast;
    1615                 :            : 
    1616                 :      29691 :   g_free (string->string);
    1617                 :      29691 :   g_slice_free (String, string);
    1618                 :      29691 : }
    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                 :         61 : 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                 :            : {
    1631                 :            :   gchar buffer[9];
    1632                 :         61 :   guint64 value = 0;
    1633                 :         61 :   gchar *end = NULL;
    1634                 :            :   gsize n_valid_chars;
    1635                 :            : 
    1636                 :         61 :   (*src_ofs)++;
    1637                 :            : 
    1638                 :         61 :   g_assert (length < sizeof (buffer));
    1639                 :         61 :   strncpy (buffer, src + *src_ofs, length);
    1640                 :         61 :   buffer[length] = '\0';
    1641                 :            : 
    1642         [ +  + ]:        205 :   for (n_valid_chars = 0; n_valid_chars < length; n_valid_chars++)
    1643         [ +  + ]:        178 :     if (!g_ascii_isxdigit (buffer[n_valid_chars]))
    1644                 :         34 :       break;
    1645                 :            : 
    1646         [ +  + ]:         61 :   if (n_valid_chars == length)
    1647                 :         27 :     value = g_ascii_strtoull (buffer, &end, 0x10);
    1648                 :            : 
    1649   [ +  +  -  + ]:         61 :   if (value == 0 || end != buffer + length)
    1650                 :            :     {
    1651                 :            :       SourceRef escape_ref;
    1652                 :            : 
    1653                 :         34 :       escape_ref = *ref;
    1654                 :         34 :       escape_ref.start += *src_ofs;
    1655                 :         34 :       escape_ref.end = escape_ref.start + n_valid_chars;
    1656                 :            : 
    1657                 :         34 :       parser_set_error (error, &escape_ref, NULL,
    1658                 :            :                         G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
    1659                 :            :                         "invalid %" G_GSIZE_FORMAT "-character unicode escape", length);
    1660                 :         34 :       return FALSE;
    1661                 :            :     }
    1662                 :            : 
    1663                 :         27 :   g_assert (value <= G_MAXUINT32);
    1664                 :            : 
    1665                 :         27 :   *dest_ofs += g_unichar_to_utf8 (value, dest + *dest_ofs);
    1666                 :         27 :   *src_ofs += length;
    1667                 :            : 
    1668                 :         27 :   return TRUE;
    1669                 :            : }
    1670                 :            : 
    1671                 :            : static AST *
    1672                 :      29730 : string_parse (TokenStream  *stream,
    1673                 :            :               va_list      *app,
    1674                 :            :               GError      **error)
    1675                 :            : {
    1676                 :            :   static const ASTClass string_class = {
    1677                 :            :     string_get_pattern,
    1678                 :            :     maybe_wrapper, string_get_value,
    1679                 :            :     string_free
    1680                 :            :   };
    1681                 :            :   String *string;
    1682                 :            :   SourceRef ref;
    1683                 :            :   gchar *token;
    1684                 :            :   gsize length;
    1685                 :            :   gchar quote;
    1686                 :            :   gchar *str;
    1687                 :            :   gint i, j;
    1688                 :            : 
    1689                 :      29730 :   token_stream_start_ref (stream, &ref);
    1690                 :      29730 :   token = token_stream_get (stream);
    1691                 :      29730 :   token_stream_end_ref (stream, &ref);
    1692                 :      29730 :   length = strlen (token);
    1693                 :      29730 :   quote = token[0];
    1694                 :            : 
    1695                 :      29730 :   str = g_malloc (length);
    1696                 :      29730 :   g_assert (quote == '"' || quote == '\'');
    1697                 :      29730 :   j = 0;
    1698                 :      29730 :   i = 1;
    1699         [ +  + ]:    3077975 :   while (token[i] != quote)
    1700      [ +  +  + ]:    3048284 :     switch (token[i])
    1701                 :            :       {
    1702                 :          3 :       case '\0':
    1703                 :          3 :         parser_set_error (error, &ref, NULL,
    1704                 :            :                           G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
    1705                 :            :                           "unterminated string constant");
    1706                 :          3 :         g_free (token);
    1707                 :          3 :         g_free (str);
    1708                 :          3 :         return NULL;
    1709                 :            : 
    1710                 :         86 :       case '\\':
    1711   [ +  +  +  +  :         86 :         switch (token[++i])
          +  +  +  +  +  
                +  -  + ]
    1712                 :            :           {
    1713                 :          2 :           case '\0':
    1714                 :          2 :             parser_set_error (error, &ref, NULL,
    1715                 :            :                               G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
    1716                 :            :                               "unterminated string constant");
    1717                 :          2 :             g_free (token);
    1718                 :          2 :             g_free (str);
    1719                 :          2 :             return NULL;
    1720                 :            : 
    1721                 :         43 :           case 'u':
    1722         [ +  + ]:         43 :             if (!unicode_unescape (token, &i, str, &j, 4, &ref, error))
    1723                 :            :               {
    1724                 :         17 :                 g_free (token);
    1725                 :         17 :                 g_free (str);
    1726                 :         17 :                 return NULL;
    1727                 :            :               }
    1728                 :         26 :             continue;
    1729                 :            : 
    1730                 :         18 :           case 'U':
    1731         [ +  + ]:         18 :             if (!unicode_unescape (token, &i, str, &j, 8, &ref, error))
    1732                 :            :               {
    1733                 :         17 :                 g_free (token);
    1734                 :         17 :                 g_free (str);
    1735                 :         17 :                 return NULL;
    1736                 :            :               }
    1737                 :          1 :             continue;
    1738                 :            : 
    1739                 :          2 :           case 'a': str[j++] = '\a'; i++; continue;
    1740                 :          2 :           case 'b': str[j++] = '\b'; i++; continue;
    1741                 :          2 :           case 'f': str[j++] = '\f'; i++; continue;
    1742                 :          3 :           case 'n': str[j++] = '\n'; i++; continue;
    1743                 :          2 :           case 'r': str[j++] = '\r'; i++; continue;
    1744                 :          3 :           case 't': str[j++] = '\t'; i++; continue;
    1745                 :          2 :           case 'v': str[j++] = '\v'; i++; continue;
    1746                 :          0 :           case '\n': i++; continue;
    1747                 :            :           }
    1748                 :            : 
    1749                 :            :         G_GNUC_FALLTHROUGH;
    1750                 :            : 
    1751                 :            :       default:
    1752                 :    3048202 :         str[j++] = token[i++];
    1753                 :            :       }
    1754                 :      29691 :   str[j++] = '\0';
    1755                 :      29691 :   g_free (token);
    1756                 :            : 
    1757                 :      29691 :   string = g_slice_new (String);
    1758                 :      29691 :   string->ast.class = &string_class;
    1759                 :      29691 :   string->string = str;
    1760                 :            : 
    1761                 :      29691 :   token_stream_next (stream);
    1762                 :            : 
    1763                 :      29691 :   return (AST *) string;
    1764                 :            : }
    1765                 :            : 
    1766                 :            : typedef struct
    1767                 :            : {
    1768                 :            :   AST ast;
    1769                 :            :   gchar *string;
    1770                 :            : } ByteString;
    1771                 :            : 
    1772                 :            : static gchar *
    1773                 :          5 : bytestring_get_pattern (AST     *ast,
    1774                 :            :                         GError **error)
    1775                 :            : {
    1776                 :          5 :   return g_strdup ("May");
    1777                 :            : }
    1778                 :            : 
    1779                 :            : static GVariant *
    1780                 :          7 : bytestring_get_value (AST                 *ast,
    1781                 :            :                       const GVariantType  *type,
    1782                 :            :                       GError             **error)
    1783                 :            : {
    1784                 :          7 :   ByteString *string = (ByteString *) ast;
    1785                 :            : 
    1786         [ -  + ]:          7 :   if (!g_variant_type_equal (type, G_VARIANT_TYPE_BYTESTRING))
    1787                 :          0 :     return ast_type_error (ast, type, error);
    1788                 :            : 
    1789                 :          7 :   return g_variant_new_bytestring (string->string);
    1790                 :            : }
    1791                 :            : 
    1792                 :            : static void
    1793                 :          7 : bytestring_free (AST *ast)
    1794                 :            : {
    1795                 :          7 :   ByteString *string = (ByteString *) ast;
    1796                 :            : 
    1797                 :          7 :   g_free (string->string);
    1798                 :          7 :   g_slice_free (ByteString, string);
    1799                 :          7 : }
    1800                 :            : 
    1801                 :            : static AST *
    1802                 :         27 : bytestring_parse (TokenStream  *stream,
    1803                 :            :                   va_list      *app,
    1804                 :            :                   GError      **error)
    1805                 :            : {
    1806                 :            :   static const ASTClass bytestring_class = {
    1807                 :            :     bytestring_get_pattern,
    1808                 :            :     maybe_wrapper, bytestring_get_value,
    1809                 :            :     bytestring_free
    1810                 :            :   };
    1811                 :            :   ByteString *string;
    1812                 :            :   SourceRef ref;
    1813                 :            :   gchar *token;
    1814                 :            :   gsize length;
    1815                 :            :   gchar quote;
    1816                 :            :   gchar *str;
    1817                 :            :   gint i, j;
    1818                 :            : 
    1819                 :         27 :   token_stream_start_ref (stream, &ref);
    1820                 :         27 :   token = token_stream_get (stream);
    1821                 :         27 :   token_stream_end_ref (stream, &ref);
    1822                 :         27 :   g_assert (token[0] == 'b');
    1823                 :         27 :   length = strlen (token);
    1824                 :         27 :   quote = token[1];
    1825                 :            : 
    1826                 :         27 :   str = g_malloc (length);
    1827                 :         27 :   g_assert (quote == '"' || quote == '\'');
    1828                 :         27 :   j = 0;
    1829                 :         27 :   i = 2;
    1830         [ +  + ]:         87 :   while (token[i] != quote)
    1831      [ +  +  + ]:         80 :     switch (token[i])
    1832                 :            :       {
    1833                 :         16 :       case '\0':
    1834                 :         16 :         parser_set_error (error, &ref, NULL,
    1835                 :            :                           G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
    1836                 :            :                           "unterminated string constant");
    1837                 :         16 :         g_free (str);
    1838                 :         16 :         g_free (token);
    1839                 :         16 :         return NULL;
    1840                 :            : 
    1841                 :         13 :       case '\\':
    1842   [ +  +  -  -  :         13 :         switch (token[++i])
          -  -  -  -  -  
                   -  + ]
    1843                 :            :           {
    1844                 :          4 :           case '\0':
    1845                 :          4 :             parser_set_error (error, &ref, NULL,
    1846                 :            :                               G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
    1847                 :            :                               "unterminated string constant");
    1848                 :          4 :             g_free (str);
    1849                 :          4 :             g_free (token);
    1850                 :          4 :             return NULL;
    1851                 :            : 
    1852                 :          1 :           case '0': case '1': case '2': case '3':
    1853                 :            :           case '4': case '5': case '6': case '7':
    1854                 :            :             {
    1855                 :            :               /* up to 3 characters */
    1856                 :          1 :               guchar val = token[i++] - '0';
    1857                 :            : 
    1858   [ +  -  +  - ]:          1 :               if ('0' <= token[i] && token[i] < '8')
    1859                 :          1 :                 val = (val << 3) | (token[i++] - '0');
    1860                 :            : 
    1861   [ +  -  +  - ]:          1 :               if ('0' <= token[i] && token[i] < '8')
    1862                 :          1 :                 val = (val << 3) | (token[i++] - '0');
    1863                 :            : 
    1864                 :          1 :               str[j++] = val;
    1865                 :            :             }
    1866                 :          1 :             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                 :            :           }
    1877                 :            : 
    1878                 :            :         G_GNUC_FALLTHROUGH;
    1879                 :            : 
    1880                 :            :       default:
    1881                 :         59 :         str[j++] = token[i++];
    1882                 :            :       }
    1883                 :          7 :   str[j++] = '\0';
    1884                 :          7 :   g_free (token);
    1885                 :            : 
    1886                 :          7 :   string = g_slice_new (ByteString);
    1887                 :          7 :   string->ast.class = &bytestring_class;
    1888                 :          7 :   string->string = str;
    1889                 :            : 
    1890                 :          7 :   token_stream_next (stream);
    1891                 :            : 
    1892                 :          7 :   return (AST *) string;
    1893                 :            : }
    1894                 :            : 
    1895                 :            : typedef struct
    1896                 :            : {
    1897                 :            :   AST ast;
    1898                 :            : 
    1899                 :            :   gchar *token;
    1900                 :            : } Number;
    1901                 :            : 
    1902                 :            : static gchar *
    1903                 :     470377 : number_get_pattern (AST     *ast,
    1904                 :            :                     GError **error)
    1905                 :            : {
    1906                 :     470377 :   Number *number = (Number *) ast;
    1907                 :            : 
    1908         [ +  + ]:     470377 :   if (strchr (number->token, '.') ||
    1909   [ +  -  -  +  :     246084 :       (!g_str_has_prefix (number->token, "0x") && strchr (number->token, 'e')) ||
          +  +  +  +  +  
                      - ]
    1910         [ +  + ]:     246084 :       strstr (number->token, "inf") ||
    1911         [ +  + ]:     246082 :       strstr (number->token, "nan"))
    1912                 :     224296 :     return g_strdup ("Md");
    1913                 :            : 
    1914                 :     246081 :   return g_strdup ("MN");
    1915                 :            : }
    1916                 :            : 
    1917                 :            : static GVariant *
    1918                 :         31 : number_overflow (AST                 *ast,
    1919                 :            :                  const GVariantType  *type,
    1920                 :            :                  GError             **error)
    1921                 :            : {
    1922                 :         31 :   ast_set_error (ast, error, NULL,
    1923                 :            :                  G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE,
    1924                 :            :                  "number out of range for type '%c'",
    1925                 :         31 :                  g_variant_type_peek_string (type)[0]);
    1926                 :         31 :   return NULL;
    1927                 :            : }
    1928                 :            : 
    1929                 :            : static GVariant *
    1930                 :     938905 : number_get_value (AST                 *ast,
    1931                 :            :                   const GVariantType  *type,
    1932                 :            :                   GError             **error)
    1933                 :            : {
    1934                 :     938905 :   Number *number = (Number *) ast;
    1935                 :            :   const gchar *token;
    1936                 :            :   gboolean negative;
    1937                 :            :   gboolean floating;
    1938                 :            :   guint64 abs_val;
    1939                 :            :   gdouble dbl_val;
    1940                 :            :   gchar *end;
    1941                 :            : 
    1942                 :     938905 :   token = number->token;
    1943                 :            : 
    1944         [ +  + ]:     938905 :   if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
    1945                 :            :     {
    1946                 :     447363 :       floating = TRUE;
    1947                 :            : 
    1948                 :     447363 :       errno = 0;
    1949                 :     447363 :       dbl_val = g_ascii_strtod (token, &end);
    1950   [ +  +  +  + ]:     447363 :       if (dbl_val != 0.0 && errno == ERANGE)
    1951                 :            :         {
    1952                 :          2 :           ast_set_error (ast, error, NULL,
    1953                 :            :                          G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
    1954                 :            :                          "number too big for any type");
    1955                 :          2 :           return NULL;
    1956                 :            :         }
    1957                 :            : 
    1958                 :            :       /* silence uninitialised warnings... */
    1959                 :     447361 :       negative = FALSE;
    1960                 :     447361 :       abs_val = 0;
    1961                 :            :     }
    1962                 :            :   else
    1963                 :            :     {
    1964                 :     491542 :       floating = FALSE;
    1965                 :     491542 :       negative = token[0] == '-';
    1966         [ +  + ]:     491542 :       if (token[0] == '-')
    1967                 :     227648 :         token++;
    1968                 :            : 
    1969                 :     491542 :       errno = 0;
    1970                 :     491542 :       abs_val = g_ascii_strtoull (token, &end, 0);
    1971   [ +  +  +  + ]:     491542 :       if (abs_val == G_MAXUINT64 && errno == ERANGE)
    1972                 :            :         {
    1973                 :          6 :           ast_set_error (ast, error, NULL,
    1974                 :            :                          G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
    1975                 :            :                          "integer too big for any type");
    1976                 :          6 :           return NULL;
    1977                 :            :         }
    1978                 :            : 
    1979         [ +  + ]:     491536 :       if (abs_val == 0)
    1980                 :        151 :         negative = FALSE;
    1981                 :            : 
    1982                 :            :       /* silence uninitialised warning... */
    1983                 :     491536 :       dbl_val = 0.0;
    1984                 :            :     }
    1985                 :            : 
    1986         [ +  + ]:     938897 :   if (*end != '\0')
    1987                 :            :     {
    1988                 :            :       SourceRef ref;
    1989                 :            : 
    1990                 :         11 :       ref = ast->source_ref;
    1991                 :         11 :       ref.start += end - number->token;
    1992                 :         11 :       ref.end = ref.start + 1;
    1993                 :            : 
    1994                 :         11 :       parser_set_error (error, &ref, NULL,
    1995                 :            :                         G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
    1996                 :            :                         "invalid character in number");
    1997                 :         11 :       return NULL;
    1998                 :            :      }
    1999                 :            : 
    2000         [ +  + ]:     938886 :   if (floating)
    2001                 :     447359 :     return g_variant_new_double (dbl_val);
    2002                 :            : 
    2003   [ +  +  +  +  :     491527 :   switch (*g_variant_type_peek_string (type))
             +  +  +  +  
                      + ]
    2004                 :            :     {
    2005                 :      14613 :     case 'y':
    2006   [ +  +  +  + ]:      14613 :       if (negative || abs_val > G_MAXUINT8)
    2007                 :          5 :         return number_overflow (ast, type, error);
    2008                 :      14608 :       return g_variant_new_byte (abs_val);
    2009                 :            : 
    2010                 :       9888 :     case 'n':
    2011         [ +  + ]:       9888 :       if (abs_val - negative > G_MAXINT16)
    2012                 :          4 :         return number_overflow (ast, type, error);
    2013   [ +  +  +  + ]:       9884 :       if (negative && abs_val > G_MAXINT16)
    2014                 :          2 :         return g_variant_new_int16 (G_MININT16);
    2015         [ +  + ]:      19764 :       return g_variant_new_int16 (negative ?
    2016                 :       9882 :                                   -((gint16) abs_val) : ((gint16) abs_val));
    2017                 :            : 
    2018                 :       7308 :     case 'q':
    2019   [ +  +  +  + ]:       7308 :       if (negative || abs_val > G_MAXUINT16)
    2020                 :          4 :         return number_overflow (ast, type, error);
    2021                 :       7304 :       return g_variant_new_uint16 (abs_val);
    2022                 :            : 
    2023                 :     427496 :     case 'i':
    2024         [ +  + ]:     427496 :       if (abs_val - negative > G_MAXINT32)
    2025                 :          4 :         return number_overflow (ast, type, error);
    2026   [ +  +  +  + ]:     427492 :       if (negative && abs_val > G_MAXINT32)
    2027                 :          3 :         return g_variant_new_int32 (G_MININT32);
    2028         [ +  + ]:     640655 :       return g_variant_new_int32 (negative ?
    2029                 :     213166 :                                   -((gint32) abs_val) : ((gint32) abs_val));
    2030                 :            : 
    2031                 :       1457 :     case 'u':
    2032   [ +  +  +  + ]:       1457 :       if (negative || abs_val > G_MAXUINT32)
    2033                 :          4 :         return number_overflow (ast, type, error);
    2034                 :       1453 :       return g_variant_new_uint32 (abs_val);
    2035                 :            : 
    2036                 :      16622 :     case 'x':
    2037         [ +  + ]:      16622 :       if (abs_val - negative > G_MAXINT64)
    2038                 :          4 :         return number_overflow (ast, type, error);
    2039   [ +  +  +  + ]:      16618 :       if (negative && abs_val > G_MAXINT64)
    2040                 :          2 :         return g_variant_new_int64 (G_MININT64);
    2041         [ +  + ]:      24975 :       return g_variant_new_int64 (negative ?
    2042                 :       8359 :                                   -((gint64) abs_val) : ((gint64) abs_val));
    2043                 :            : 
    2044                 :      11994 :     case 't':
    2045         [ +  + ]:      11994 :       if (negative)
    2046                 :          2 :         return number_overflow (ast, type, error);
    2047                 :      11992 :       return g_variant_new_uint64 (abs_val);
    2048                 :            : 
    2049                 :       2143 :     case 'h':
    2050         [ +  + ]:       2143 :       if (abs_val - negative > G_MAXINT32)
    2051                 :          4 :         return number_overflow (ast, type, error);
    2052   [ +  +  +  + ]:       2139 :       if (negative && abs_val > G_MAXINT32)
    2053                 :          1 :         return g_variant_new_handle (G_MININT32);
    2054         [ +  + ]:       3202 :       return g_variant_new_handle (negative ?
    2055                 :       1064 :                                    -((gint32) abs_val) : ((gint32) abs_val));
    2056                 :            : 
    2057                 :          6 :     default:
    2058                 :          6 :       return ast_type_error (ast, type, error);
    2059                 :            :     }
    2060                 :            : }
    2061                 :            : 
    2062                 :            : static void
    2063                 :     939056 : number_free (AST *ast)
    2064                 :            : {
    2065                 :     939056 :   Number *number = (Number *) ast;
    2066                 :            : 
    2067                 :     939056 :   g_free (number->token);
    2068                 :     939056 :   g_slice_free (Number, number);
    2069                 :     939056 : }
    2070                 :            : 
    2071                 :            : static AST *
    2072                 :     939056 : number_parse (TokenStream  *stream,
    2073                 :            :               va_list      *app,
    2074                 :            :               GError      **error)
    2075                 :            : {
    2076                 :            :   static const ASTClass number_class = {
    2077                 :            :     number_get_pattern,
    2078                 :            :     maybe_wrapper, number_get_value,
    2079                 :            :     number_free
    2080                 :            :   };
    2081                 :            :   Number *number;
    2082                 :            : 
    2083                 :     939056 :   number = g_slice_new (Number);
    2084                 :     939056 :   number->ast.class = &number_class;
    2085                 :     939056 :   number->token = token_stream_get (stream);
    2086                 :     939056 :   token_stream_next (stream);
    2087                 :            : 
    2088                 :     939056 :   return (AST *) number;
    2089                 :            : }
    2090                 :            : 
    2091                 :            : typedef struct
    2092                 :            : {
    2093                 :            :   AST ast;
    2094                 :            :   gboolean value;
    2095                 :            : } Boolean;
    2096                 :            : 
    2097                 :            : static gchar *
    2098                 :       9974 : boolean_get_pattern (AST     *ast,
    2099                 :            :                      GError **error)
    2100                 :            : {
    2101                 :       9974 :   return g_strdup ("Mb");
    2102                 :            : }
    2103                 :            : 
    2104                 :            : static GVariant *
    2105                 :      20052 : boolean_get_value (AST                 *ast,
    2106                 :            :                    const GVariantType  *type,
    2107                 :            :                    GError             **error)
    2108                 :            : {
    2109                 :      20052 :   Boolean *boolean = (Boolean *) ast;
    2110                 :            : 
    2111         [ +  + ]:      20052 :   if (!g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
    2112                 :          4 :     return ast_type_error (ast, type, error);
    2113                 :            : 
    2114                 :      20048 :   return g_variant_new_boolean (boolean->value);
    2115                 :            : }
    2116                 :            : 
    2117                 :            : static void
    2118                 :      20052 : boolean_free (AST *ast)
    2119                 :            : {
    2120                 :      20052 :   Boolean *boolean = (Boolean *) ast;
    2121                 :            : 
    2122                 :      20052 :   g_slice_free (Boolean, boolean);
    2123                 :      20052 : }
    2124                 :            : 
    2125                 :            : static AST *
    2126                 :      20052 : boolean_new (gboolean value)
    2127                 :            : {
    2128                 :            :   static const ASTClass boolean_class = {
    2129                 :            :     boolean_get_pattern,
    2130                 :            :     maybe_wrapper, boolean_get_value,
    2131                 :            :     boolean_free
    2132                 :            :   };
    2133                 :            :   Boolean *boolean;
    2134                 :            : 
    2135                 :      20052 :   boolean = g_slice_new (Boolean);
    2136                 :      20052 :   boolean->ast.class = &boolean_class;
    2137                 :      20052 :   boolean->value = value;
    2138                 :            : 
    2139                 :      20052 :   return (AST *) boolean;
    2140                 :            : }
    2141                 :            : 
    2142                 :            : typedef struct
    2143                 :            : {
    2144                 :            :   AST ast;
    2145                 :            : 
    2146                 :            :   GVariant *value;
    2147                 :            : } Positional;
    2148                 :            : 
    2149                 :            : static gchar *
    2150                 :        356 : positional_get_pattern (AST     *ast,
    2151                 :            :                         GError **error)
    2152                 :            : {
    2153                 :        356 :   Positional *positional = (Positional *) ast;
    2154                 :            : 
    2155                 :        712 :   return g_strdup (g_variant_get_type_string (positional->value));
    2156                 :            : }
    2157                 :            : 
    2158                 :            : static GVariant *
    2159                 :        372 : positional_get_value (AST                 *ast,
    2160                 :            :                       const GVariantType  *type,
    2161                 :            :                       GError             **error)
    2162                 :            : {
    2163                 :        372 :   Positional *positional = (Positional *) ast;
    2164                 :            :   GVariant *value;
    2165                 :            : 
    2166                 :        372 :   g_assert (positional->value != NULL);
    2167                 :            : 
    2168         [ -  + ]:        372 :   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                 :        372 :   g_assert (positional->value != NULL);
    2177                 :        372 :   value = positional->value;
    2178                 :        372 :   positional->value = NULL;
    2179                 :            : 
    2180                 :        372 :   return value;
    2181                 :            : }
    2182                 :            : 
    2183                 :            : static void
    2184                 :        372 : positional_free (AST *ast)
    2185                 :            : {
    2186                 :        372 :   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                 :        372 :   g_slice_free (Positional, positional);
    2192                 :        372 : }
    2193                 :            : 
    2194                 :            : static AST *
    2195                 :        372 : positional_parse (TokenStream  *stream,
    2196                 :            :                   va_list      *app,
    2197                 :            :                   GError      **error)
    2198                 :            : {
    2199                 :            :   static const ASTClass positional_class = {
    2200                 :            :     positional_get_pattern,
    2201                 :            :     positional_get_value, NULL,
    2202                 :            :     positional_free
    2203                 :            :   };
    2204                 :            :   Positional *positional;
    2205                 :            :   const gchar *endptr;
    2206                 :            :   gchar *token;
    2207                 :            : 
    2208                 :        372 :   token = token_stream_get (stream);
    2209                 :        372 :   g_assert (token[0] == '%');
    2210                 :            : 
    2211                 :        372 :   positional = g_slice_new (Positional);
    2212                 :        372 :   positional->ast.class = &positional_class;
    2213                 :        372 :   positional->value = g_variant_new_va (token + 1, &endptr, app);
    2214                 :            : 
    2215   [ +  -  -  + ]:        372 :   if (*endptr || positional->value == NULL)
    2216                 :            :     {
    2217                 :          0 :       token_stream_set_error (stream, error, TRUE,
    2218                 :            :                               G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING,
    2219                 :            :                               "invalid GVariant format string");
    2220                 :            :       /* memory management doesn't matter in case of programmer error. */
    2221                 :          0 :       return NULL;
    2222                 :            :     }
    2223                 :            : 
    2224                 :        372 :   token_stream_next (stream);
    2225                 :        372 :   g_free (token);
    2226                 :            : 
    2227                 :        372 :   return (AST *) positional;
    2228                 :            : }
    2229                 :            : 
    2230                 :            : typedef struct
    2231                 :            : {
    2232                 :            :   AST ast;
    2233                 :            : 
    2234                 :            :   GVariantType *type;
    2235                 :            :   AST *child;
    2236                 :            : } TypeDecl;
    2237                 :            : 
    2238                 :            : static gchar *
    2239                 :       2700 : typedecl_get_pattern (AST     *ast,
    2240                 :            :                       GError **error)
    2241                 :            : {
    2242                 :       2700 :   TypeDecl *decl = (TypeDecl *) ast;
    2243                 :            : 
    2244                 :       2700 :   return g_variant_type_dup_string (decl->type);
    2245                 :            : }
    2246                 :            : 
    2247                 :            : static GVariant *
    2248                 :       2696 : typedecl_get_value (AST                 *ast,
    2249                 :            :                     const GVariantType  *type,
    2250                 :            :                     GError             **error)
    2251                 :            : {
    2252                 :       2696 :   TypeDecl *decl = (TypeDecl *) ast;
    2253                 :            : 
    2254                 :       2696 :   return ast_get_value (decl->child, type, error);
    2255                 :            : }
    2256                 :            : 
    2257                 :            : static void
    2258                 :       2700 : typedecl_free (AST *ast)
    2259                 :            : {
    2260                 :       2700 :   TypeDecl *decl = (TypeDecl *) ast;
    2261                 :            : 
    2262                 :       2700 :   ast_free (decl->child);
    2263                 :       2700 :   g_variant_type_free (decl->type);
    2264                 :       2700 :   g_slice_free (TypeDecl, decl);
    2265                 :       2700 : }
    2266                 :            : 
    2267                 :            : static AST *
    2268                 :       2712 : typedecl_parse (TokenStream  *stream,
    2269                 :            :                 guint         max_depth,
    2270                 :            :                 va_list      *app,
    2271                 :            :                 GError      **error)
    2272                 :            : {
    2273                 :            :   static const ASTClass typedecl_class = {
    2274                 :            :     typedecl_get_pattern,
    2275                 :            :     typedecl_get_value, NULL,
    2276                 :            :     typedecl_free
    2277                 :            :   };
    2278                 :            :   GVariantType *type;
    2279                 :            :   TypeDecl *decl;
    2280                 :            :   AST *child;
    2281                 :            : 
    2282         [ +  + ]:       2712 :   if (token_stream_peek (stream, '@'))
    2283                 :            :     {
    2284                 :            :       gchar *token;
    2285                 :            : 
    2286                 :        440 :       token = token_stream_get (stream);
    2287                 :            : 
    2288         [ +  + ]:        440 :       if (!g_variant_type_string_is_valid (token + 1))
    2289                 :            :         {
    2290                 :          2 :           token_stream_set_error (stream, error, TRUE,
    2291                 :            :                                   G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING,
    2292                 :            :                                   "invalid type declaration");
    2293                 :          2 :           g_free (token);
    2294                 :            : 
    2295                 :          2 :           return NULL;
    2296                 :            :         }
    2297                 :            : 
    2298         [ +  + ]:        438 :       if (g_variant_type_string_get_depth_ (token + 1) > max_depth)
    2299                 :            :         {
    2300                 :          1 :           token_stream_set_error (stream, error, TRUE,
    2301                 :            :                                   G_VARIANT_PARSE_ERROR_RECURSION,
    2302                 :            :                                   "type declaration recurses too deeply");
    2303                 :          1 :           g_free (token);
    2304                 :            : 
    2305                 :          1 :           return NULL;
    2306                 :            :         }
    2307                 :            : 
    2308                 :        437 :       type = g_variant_type_new (token + 1);
    2309                 :            : 
    2310         [ +  + ]:        437 :       if (!g_variant_type_is_definite (type))
    2311                 :            :         {
    2312                 :          2 :           token_stream_set_error (stream, error, TRUE,
    2313                 :            :                                   G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED,
    2314                 :            :                                   "type declarations must be definite");
    2315                 :          2 :           g_variant_type_free (type);
    2316                 :          2 :           g_free (token);
    2317                 :            : 
    2318                 :          2 :           return NULL;
    2319                 :            :         }
    2320                 :            : 
    2321                 :        435 :       token_stream_next (stream);
    2322                 :        435 :       g_free (token);
    2323                 :            :     }
    2324                 :            :   else
    2325                 :            :     {
    2326         [ +  + ]:       2272 :       if (token_stream_consume (stream, "boolean"))
    2327                 :          2 :         type = g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
    2328                 :            : 
    2329         [ +  + ]:       2270 :       else if (token_stream_consume (stream, "byte"))
    2330                 :        269 :         type = g_variant_type_copy (G_VARIANT_TYPE_BYTE);
    2331                 :            : 
    2332         [ +  + ]:       2001 :       else if (token_stream_consume (stream, "int16"))
    2333                 :        272 :         type = g_variant_type_copy (G_VARIANT_TYPE_INT16);
    2334                 :            : 
    2335         [ +  + ]:       1729 :       else if (token_stream_consume (stream, "uint16"))
    2336                 :        270 :         type = g_variant_type_copy (G_VARIANT_TYPE_UINT16);
    2337                 :            : 
    2338         [ +  + ]:       1459 :       else if (token_stream_consume (stream, "int32"))
    2339                 :          5 :         type = g_variant_type_copy (G_VARIANT_TYPE_INT32);
    2340                 :            : 
    2341         [ +  + ]:       1454 :       else if (token_stream_consume (stream, "handle"))
    2342                 :        229 :         type = g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
    2343                 :            : 
    2344         [ +  + ]:       1225 :       else if (token_stream_consume (stream, "uint32"))
    2345                 :        236 :         type = g_variant_type_copy (G_VARIANT_TYPE_UINT32);
    2346                 :            : 
    2347         [ +  + ]:        989 :       else if (token_stream_consume (stream, "int64"))
    2348                 :        240 :         type = g_variant_type_copy (G_VARIANT_TYPE_INT64);
    2349                 :            : 
    2350         [ +  + ]:        749 :       else if (token_stream_consume (stream, "uint64"))
    2351                 :        238 :         type = g_variant_type_copy (G_VARIANT_TYPE_UINT64);
    2352                 :            : 
    2353         [ +  + ]:        511 :       else if (token_stream_consume (stream, "double"))
    2354                 :          2 :         type = g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
    2355                 :            : 
    2356         [ +  + ]:        509 :       else if (token_stream_consume (stream, "string"))
    2357                 :          2 :         type = g_variant_type_copy (G_VARIANT_TYPE_STRING);
    2358                 :            : 
    2359         [ +  + ]:        507 :       else if (token_stream_consume (stream, "objectpath"))
    2360                 :        253 :         type = g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
    2361                 :            : 
    2362         [ +  + ]:        254 :       else if (token_stream_consume (stream, "signature"))
    2363                 :        249 :         type = g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
    2364                 :            : 
    2365                 :            :       else
    2366                 :            :         {
    2367                 :          5 :           token_stream_set_error (stream, error, TRUE,
    2368                 :            :                                   G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
    2369                 :            :                                   "unknown keyword");
    2370                 :          5 :           return NULL;
    2371                 :            :         }
    2372                 :            :     }
    2373                 :            : 
    2374         [ +  + ]:       2702 :   if ((child = parse (stream, max_depth - 1, app, error)) == NULL)
    2375                 :            :     {
    2376                 :          2 :       g_variant_type_free (type);
    2377                 :          2 :       return NULL;
    2378                 :            :     }
    2379                 :            : 
    2380                 :       2700 :   decl = g_slice_new (TypeDecl);
    2381                 :       2700 :   decl->ast.class = &typedecl_class;
    2382                 :       2700 :   decl->type = type;
    2383                 :       2700 :   decl->child = child;
    2384                 :            : 
    2385                 :       2700 :   return (AST *) decl;
    2386                 :            : }
    2387                 :            : 
    2388                 :            : static AST *
    2389                 :    1016243 : parse (TokenStream  *stream,
    2390                 :            :        guint         max_depth,
    2391                 :            :        va_list      *app,
    2392                 :            :        GError      **error)
    2393                 :            : {
    2394                 :            :   SourceRef source_ref;
    2395                 :            :   AST *result;
    2396                 :            : 
    2397         [ +  + ]:    1016243 :   if (max_depth == 0)
    2398                 :            :     {
    2399                 :          1 :       token_stream_set_error (stream, error, FALSE,
    2400                 :            :                               G_VARIANT_PARSE_ERROR_RECURSION,
    2401                 :            :                               "variant nested too deeply");
    2402                 :          1 :       return NULL;
    2403                 :            :     }
    2404                 :            : 
    2405                 :    1016242 :   token_stream_prepare (stream);
    2406                 :    1016242 :   token_stream_start_ref (stream, &source_ref);
    2407                 :            : 
    2408         [ +  + ]:    1016242 :   if (token_stream_peek (stream, '['))
    2409                 :      15635 :     result = array_parse (stream, max_depth, app, error);
    2410                 :            : 
    2411         [ +  + ]:    1000607 :   else if (token_stream_peek (stream, '('))
    2412                 :       4288 :     result = tuple_parse (stream, max_depth, app, error);
    2413                 :            : 
    2414         [ +  + ]:     996319 :   else if (token_stream_peek (stream, '<'))
    2415                 :       2258 :     result = variant_parse (stream, max_depth, app, error);
    2416                 :            : 
    2417         [ +  + ]:     994061 :   else if (token_stream_peek (stream, '{'))
    2418                 :       1354 :     result = dictionary_parse (stream, max_depth, app, error);
    2419                 :            : 
    2420   [ +  +  +  + ]:     992707 :   else if (app && token_stream_peek (stream, '%'))
    2421                 :        372 :     result = positional_parse (stream, app, error);
    2422                 :            : 
    2423         [ +  + ]:     992335 :   else if (token_stream_consume (stream, "true"))
    2424                 :       9856 :     result = boolean_new (TRUE);
    2425                 :            : 
    2426         [ +  + ]:     982479 :   else if (token_stream_consume (stream, "false"))
    2427                 :      10196 :     result = boolean_new (FALSE);
    2428                 :            : 
    2429   [ +  +  +  + ]:    1005513 :   else if (token_stream_is_numeric (stream) ||
    2430         [ +  + ]:      66458 :            token_stream_peek_string (stream, "inf") ||
    2431                 :      33228 :            token_stream_peek_string (stream, "nan"))
    2432                 :     939056 :     result = number_parse (stream, app, error);
    2433                 :            : 
    2434   [ +  +  +  + ]:      65729 :   else if (token_stream_peek (stream, 'n') ||
    2435                 :      32502 :            token_stream_peek (stream, 'j'))
    2436                 :        741 :     result = maybe_parse (stream, max_depth, app, error);
    2437                 :            : 
    2438   [ +  +  +  + ]:      64532 :   else if (token_stream_peek (stream, '@') ||
    2439                 :      32046 :            token_stream_is_keyword (stream))
    2440                 :       2712 :     result = typedecl_parse (stream, max_depth, app, error);
    2441                 :            : 
    2442   [ +  +  +  + ]:      29839 :   else if (token_stream_peek (stream, '\'') ||
    2443                 :         65 :            token_stream_peek (stream, '"'))
    2444                 :      29730 :     result = string_parse (stream, app, error);
    2445                 :            : 
    2446   [ +  +  +  + ]:         71 :   else if (token_stream_peek2 (stream, 'b', '\'') ||
    2447                 :         27 :            token_stream_peek2 (stream, 'b', '"'))
    2448                 :         27 :     result = bytestring_parse (stream, app, error);
    2449                 :            : 
    2450                 :            :   else
    2451                 :            :     {
    2452                 :         17 :       token_stream_set_error (stream, error, FALSE,
    2453                 :            :                               G_VARIANT_PARSE_ERROR_VALUE_EXPECTED,
    2454                 :            :                               "expected value");
    2455                 :         17 :       return NULL;
    2456                 :            :     }
    2457                 :            : 
    2458         [ +  + ]:    1016225 :   if (result != NULL)
    2459                 :            :     {
    2460                 :    1015962 :       token_stream_end_ref (stream, &source_ref);
    2461                 :    1015962 :       result->source_ref = source_ref;
    2462                 :            :     }
    2463                 :            : 
    2464                 :    1016225 :   return result;
    2465                 :            : }
    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                 :        719 : g_variant_parse (const GVariantType  *type,
    2516                 :            :                  const gchar         *text,
    2517                 :            :                  const gchar         *limit,
    2518                 :            :                  const gchar        **endptr,
    2519                 :            :                  GError             **error)
    2520                 :            : {
    2521                 :        719 :   TokenStream stream = { 0, };
    2522                 :        719 :   GVariant *result = NULL;
    2523                 :            :   AST *ast;
    2524                 :            : 
    2525                 :        719 :   g_return_val_if_fail (text != NULL, NULL);
    2526                 :        719 :   g_return_val_if_fail (text == limit || text != NULL, NULL);
    2527                 :            : 
    2528                 :        719 :   stream.start = text;
    2529                 :        719 :   stream.stream = text;
    2530                 :        719 :   stream.end = limit;
    2531                 :            : 
    2532         [ +  + ]:        719 :   if ((ast = parse (&stream, G_VARIANT_MAX_RECURSION_DEPTH, NULL, error)))
    2533                 :            :     {
    2534         [ +  + ]:        594 :       if (type == NULL)
    2535                 :        283 :         result = ast_resolve (ast, error);
    2536                 :            :       else
    2537                 :        311 :         result = ast_get_value (ast, type, error);
    2538                 :            : 
    2539         [ +  + ]:        594 :       if (result != NULL)
    2540                 :            :         {
    2541                 :        456 :           g_variant_ref_sink (result);
    2542                 :            : 
    2543         [ +  + ]:        456 :           if (endptr == NULL)
    2544                 :            :             {
    2545         [ +  + ]:        464 :               while (stream.stream != limit &&
    2546         [ +  + ]:        459 :                      g_ascii_isspace (*stream.stream))
    2547                 :          9 :                 stream.stream++;
    2548                 :            : 
    2549   [ +  +  +  + ]:        455 :               if (stream.stream != limit && *stream.stream != '\0')
    2550                 :            :                 {
    2551                 :          4 :                   SourceRef ref = { stream.stream - text,
    2552                 :          4 :                                     stream.stream - text };
    2553                 :            : 
    2554                 :          4 :                   parser_set_error (error, &ref, NULL,
    2555                 :            :                                     G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END,
    2556                 :            :                                     "expected end of input");
    2557                 :          4 :                   g_variant_unref (result);
    2558                 :            : 
    2559                 :          4 :                   result = NULL;
    2560                 :            :                 }
    2561                 :            :             }
    2562                 :            :           else
    2563                 :          1 :             *endptr = stream.stream;
    2564                 :            :         }
    2565                 :            : 
    2566                 :        594 :       ast_free (ast);
    2567                 :            :     }
    2568                 :            : 
    2569                 :        719 :   return result;
    2570                 :            : }
    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-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                 :        530 : g_variant_new_parsed_va (const gchar *format,
    2603                 :            :                          va_list     *app)
    2604                 :            : {
    2605                 :        530 :   TokenStream stream = { 0, };
    2606                 :        530 :   GVariant *result = NULL;
    2607                 :        530 :   GError *error = NULL;
    2608                 :            :   AST *ast;
    2609                 :            : 
    2610                 :        530 :   g_return_val_if_fail (format != NULL, NULL);
    2611                 :        530 :   g_return_val_if_fail (app != NULL, NULL);
    2612                 :            : 
    2613                 :        530 :   stream.start = format;
    2614                 :        530 :   stream.stream = format;
    2615                 :        530 :   stream.end = NULL;
    2616                 :            : 
    2617         [ +  - ]:        530 :   if ((ast = parse (&stream, G_VARIANT_MAX_RECURSION_DEPTH, app, &error)))
    2618                 :            :     {
    2619                 :        530 :       result = ast_resolve (ast, &error);
    2620                 :        530 :       ast_free (ast);
    2621                 :            :     }
    2622                 :            : 
    2623         [ -  + ]:        530 :   if (error != NULL)
    2624                 :          0 :     g_error ("g_variant_new_parsed: %s", error->message);
    2625                 :            : 
    2626         [ -  + ]:        530 :   if (*stream.stream)
    2627                 :          0 :     g_error ("g_variant_new_parsed: trailing text after value");
    2628                 :            : 
    2629                 :        530 :   g_clear_error (&error);
    2630                 :            : 
    2631                 :        530 :   return result;
    2632                 :            : }
    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-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                 :        525 : g_variant_new_parsed (const gchar *format,
    2676                 :            :                       ...)
    2677                 :            : {
    2678                 :            :   GVariant *result;
    2679                 :            :   va_list ap;
    2680                 :            : 
    2681                 :        525 :   va_start (ap, format);
    2682                 :        525 :   result = g_variant_new_parsed_va (format, &ap);
    2683                 :        525 :   va_end (ap);
    2684                 :            : 
    2685                 :        525 :   return result;
    2686                 :            : }
    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-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                 :          5 : g_variant_builder_add_parsed (GVariantBuilder *builder,
    2725                 :            :                               const gchar     *format,
    2726                 :            :                               ...)
    2727                 :            : {
    2728                 :            :   va_list ap;
    2729                 :            : 
    2730                 :          5 :   va_start (ap, format);
    2731                 :          5 :   g_variant_builder_add_value (builder, g_variant_new_parsed_va (format, &ap));
    2732                 :          5 :   va_end (ap);
    2733                 :          5 : }
    2734                 :            : 
    2735                 :            : static gboolean
    2736                 :         12 : parse_num (const gchar *num,
    2737                 :            :            const gchar *limit,
    2738                 :            :            guint       *result)
    2739                 :            : {
    2740                 :            :   gchar *endptr;
    2741                 :            :   gint64 bignum;
    2742                 :            : 
    2743                 :         12 :   bignum = g_ascii_strtoll (num, &endptr, 10);
    2744                 :            : 
    2745         [ -  + ]:         12 :   if (endptr != limit)
    2746                 :          0 :     return FALSE;
    2747                 :            : 
    2748   [ +  -  -  + ]:         12 :   if (bignum < 0 || bignum > G_MAXINT)
    2749                 :          0 :     return FALSE;
    2750                 :            : 
    2751                 :         12 :   *result = (guint) bignum;
    2752                 :            : 
    2753                 :         12 :   return TRUE;
    2754                 :            : }
    2755                 :            : 
    2756                 :            : static void
    2757                 :          1 : add_last_line (GString     *err,
    2758                 :            :                const gchar *str)
    2759                 :            : {
    2760                 :            :   const gchar *last_nl;
    2761                 :            :   gchar *chomped;
    2762                 :            :   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                 :          1 :   chomped = g_strchomp (g_strdup (str));
    2772                 :          1 :   last_nl = strrchr (chomped, '\n');
    2773         [ +  - ]:          1 :   if (last_nl == NULL)
    2774                 :          1 :     last_nl = chomped;
    2775                 :            :   else
    2776                 :          0 :     last_nl++;
    2777                 :            : 
    2778                 :            :   /* Print the last line like so:
    2779                 :            :    *
    2780                 :            :    *   [1, 2, 3,
    2781                 :            :    *            ^
    2782                 :            :    */
    2783         [ +  - ]:          1 :   g_string_append (err, "  ");
    2784         [ +  - ]:          1 :   if (last_nl[0])
    2785                 :            :     g_string_append (err, last_nl);
    2786                 :            :   else
    2787         [ #  # ]:          0 :     g_string_append (err, "(empty input)");
    2788         [ +  - ]:          1 :   g_string_append (err, "\n  ");
    2789         [ +  + ]:          3 :   for (i = 0; last_nl[i]; i++)
    2790                 :            :     g_string_append_c (err, ' ');
    2791         [ +  - ]:          1 :   g_string_append (err, "^\n");
    2792                 :          1 :   g_free (chomped);
    2793                 :          1 : }
    2794                 :            : 
    2795                 :            : static void
    2796                 :          5 : 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                 :            : {
    2803   [ +  -  -  - ]:          5 :   while (str < end1 || str < end2)
    2804                 :            :     {
    2805                 :            :       const gchar *nl;
    2806                 :            : 
    2807                 :          5 :       nl = str + strcspn (str, "\n");
    2808                 :            : 
    2809   [ +  -  -  +  :          5 :       if ((start1 < nl && str < end1) || (start2 < nl && str < end2))
             -  -  -  - ]
    2810                 :            :         {
    2811                 :            :           const gchar *s;
    2812                 :            : 
    2813                 :            :           /* We're going to print this line */
    2814         [ +  - ]:          5 :           g_string_append (err, "  ");
    2815         [ -  + ]:          5 :           g_string_append_len (err, str, nl - str);
    2816         [ +  - ]:          5 :           g_string_append (err, "\n  ");
    2817                 :            : 
    2818                 :            :           /* And add underlines... */
    2819         [ +  + ]:         68 :           for (s = str; s < nl; s++)
    2820                 :            :             {
    2821   [ +  +  +  +  :         63 :               if ((start1 <= s && s < end1) || (start2 <= s && s < end2))
             +  +  +  + ]
    2822                 :         30 :                 g_string_append_c (err, '^');
    2823                 :            :               else
    2824                 :            :                 g_string_append_c (err, ' ');
    2825                 :            :             }
    2826                 :            :           g_string_append_c (err, '\n');
    2827                 :            :         }
    2828                 :            : 
    2829         [ +  - ]:          5 :       if (!*nl)
    2830                 :          5 :         break;
    2831                 :            : 
    2832                 :          0 :       str = nl + 1;
    2833                 :            :     }
    2834                 :          5 : }
    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                 :          6 : g_variant_parse_error_print_context (GError      *error,
    2877                 :            :                                      const gchar *source_str)
    2878                 :            : {
    2879                 :            :   const gchar *colon, *dash, *comma;
    2880                 :          6 :   gboolean success = FALSE;
    2881                 :            :   GString *err;
    2882                 :            : 
    2883                 :          6 :   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                 :          6 :   colon = strchr (error->message, ':');
    2896                 :          6 :   dash = strchr (error->message, '-');
    2897                 :          6 :   comma = strchr (error->message, ',');
    2898                 :            : 
    2899         [ -  + ]:          6 :   if (!colon)
    2900                 :          0 :     return NULL;
    2901                 :            : 
    2902                 :          6 :   err = g_string_new (colon + 1);
    2903         [ +  - ]:          6 :   g_string_append (err, ":\n");
    2904                 :            : 
    2905   [ +  +  +  + ]:          6 :   if (dash == NULL || colon < dash)
    2906                 :          2 :     {
    2907                 :            :       guint point;
    2908                 :            : 
    2909                 :            :       /* we have a single point */
    2910         [ -  + ]:          2 :       if (!parse_num (error->message, colon, &point))
    2911                 :          0 :         goto out;
    2912                 :            : 
    2913         [ +  + ]:          2 :       if (point >= strlen (source_str))
    2914                 :            :         /* the error is at the end of the input */
    2915                 :          1 :         add_last_line (err, source_str);
    2916                 :            :       else
    2917                 :            :         /* otherwise just treat it as an error at a thin range */
    2918                 :          1 :         add_lines_from_range (err, source_str, source_str + point, source_str + point + 1, NULL, NULL);
    2919                 :            :     }
    2920                 :            :   else
    2921                 :            :     {
    2922                 :            :       /* We have one or two ranges... */
    2923   [ +  +  +  - ]:          4 :       if (comma && comma < colon)
    2924                 :          1 :         {
    2925                 :            :           guint start1, end1, start2, end2;
    2926                 :            :           const gchar *dash2;
    2927                 :            : 
    2928                 :            :           /* Two ranges */
    2929                 :          1 :           dash2 = strchr (comma, '-');
    2930                 :            : 
    2931   [ +  -  +  -  :          2 :           if (!parse_num (error->message, dash, &start1) || !parse_num (dash + 1, comma, &end1) ||
                   +  - ]
    2932         [ -  + ]:          2 :               !parse_num (comma + 1, dash2, &start2) || !parse_num (dash2 + 1, colon, &end2))
    2933                 :          0 :             goto out;
    2934                 :            : 
    2935                 :          1 :           add_lines_from_range (err, source_str,
    2936                 :            :                                 source_str + start1, source_str + end1,
    2937                 :            :                                 source_str + start2, source_str + end2);
    2938                 :            :         }
    2939                 :            :       else
    2940                 :            :         {
    2941                 :            :           guint start, end;
    2942                 :            : 
    2943                 :            :           /* One range */
    2944   [ +  -  -  + ]:          3 :           if (!parse_num (error->message, dash, &start) || !parse_num (dash + 1, colon, &end))
    2945                 :          0 :             goto out;
    2946                 :            : 
    2947                 :          3 :           add_lines_from_range (err, source_str, source_str + start, source_str + end, NULL, NULL);
    2948                 :            :         }
    2949                 :            :     }
    2950                 :            : 
    2951                 :          6 :   success = TRUE;
    2952                 :            : 
    2953                 :          6 : out:
    2954                 :          6 :   return g_string_free (err, !success);
    2955                 :            : }

Generated by: LCOV version 1.14