LCOV - code coverage report
Current view: top level - glib - gvariant-serialiser.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 96.9 % 575 557
Test Date: 2026-01-20 05:15:58 Functions: 98.0 % 51 50
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * Copyright © 2007, 2008 Ryan Lortie
       3                 :             :  * Copyright © 2010 Codethink Limited
       4                 :             :  * Copyright © 2020 William Manley
       5                 :             :  *
       6                 :             :  * SPDX-License-Identifier: LGPL-2.1-or-later
       7                 :             :  *
       8                 :             :  * This library is free software; you can redistribute it and/or
       9                 :             :  * modify it under the terms of the GNU Lesser General Public
      10                 :             :  * License as published by the Free Software Foundation; either
      11                 :             :  * version 2.1 of the License, or (at your option) any later version.
      12                 :             :  *
      13                 :             :  * This library is distributed in the hope that it will be useful,
      14                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16                 :             :  * Lesser General Public License for more details.
      17                 :             :  *
      18                 :             :  * You should have received a copy of the GNU Lesser General Public
      19                 :             :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      20                 :             :  *
      21                 :             :  * Author: Ryan Lortie <desrt@desrt.ca>
      22                 :             :  */
      23                 :             : 
      24                 :             : /* Prologue {{{1 */
      25                 :             : #include "config.h"
      26                 :             : 
      27                 :             : #include "gvariant-serialiser.h"
      28                 :             : 
      29                 :             : #include <glib/gvariant-internal.h>
      30                 :             : #include <glib/gtestutils.h>
      31                 :             : #include <glib/gstrfuncs.h>
      32                 :             : #include <glib/gtypes.h>
      33                 :             : 
      34                 :             : #include <string.h>
      35                 :             : 
      36                 :             : 
      37                 :             : /* GVariantSerialiser
      38                 :             :  *
      39                 :             :  * After this prologue section, this file has roughly 2 parts.
      40                 :             :  *
      41                 :             :  * The first part is split up into sections according to various
      42                 :             :  * container types.  Maybe, Array, Tuple, Variant.  The Maybe and Array
      43                 :             :  * sections are subdivided for element types being fixed or
      44                 :             :  * variable-sized types.
      45                 :             :  *
      46                 :             :  * Each section documents the format of that particular type of
      47                 :             :  * container and implements 5 functions for dealing with it:
      48                 :             :  *
      49                 :             :  *  n_children:
      50                 :             :  *    - determines (according to serialized data) how many child values
      51                 :             :  *      are inside a particular container value.
      52                 :             :  *
      53                 :             :  *  get_child:
      54                 :             :  *    - gets the type of and the serialized data corresponding to a
      55                 :             :  *      given child value within the container value.
      56                 :             :  *
      57                 :             :  *  needed_size:
      58                 :             :  *    - determines how much space would be required to serialize a
      59                 :             :  *      container of this type, containing the given children so that
      60                 :             :  *      buffers can be preallocated before serializing.
      61                 :             :  *
      62                 :             :  *  serialise:
      63                 :             :  *    - write the serialized data for a container of this type,
      64                 :             :  *      containing the given children, to a buffer.
      65                 :             :  *
      66                 :             :  *  is_normal:
      67                 :             :  *    - check the given data to ensure that it is in normal form.  For a
      68                 :             :  *      given set of child values, there is exactly one normal form for
      69                 :             :  *      the serialized data of a container.  Other forms are possible
      70                 :             :  *      while maintaining the same children (for example, by inserting
      71                 :             :  *      something other than zero bytes as padding) but only one form is
      72                 :             :  *      the normal form.
      73                 :             :  *
      74                 :             :  * The second part contains the main entry point for each of the above 5
      75                 :             :  * functions and logic to dispatch it to the handler for the appropriate
      76                 :             :  * container type code.
      77                 :             :  *
      78                 :             :  * The second part also contains a routine to byteswap serialized
      79                 :             :  * values.  This code makes use of the n_children() and get_child()
      80                 :             :  * functions above to do its work so no extra support is needed on a
      81                 :             :  * per-container-type basis.
      82                 :             :  *
      83                 :             :  * There is also additional code for checking for normal form.  All
      84                 :             :  * numeric types are always in normal form since the full range of
      85                 :             :  * values is permitted (eg: 0 to 255 is a valid byte).  Special checks
      86                 :             :  * need to be performed for booleans (only 0 or 1 allowed), strings
      87                 :             :  * (properly nul-terminated) and object paths and signature strings
      88                 :             :  * (meeting the D-Bus specification requirements).  Depth checks need to be
      89                 :             :  * performed for nested types (arrays, tuples, and variants), to avoid massive
      90                 :             :  * recursion which could exhaust our stack when handling untrusted input.
      91                 :             :  */
      92                 :             : 
      93                 :             : /* < private >
      94                 :             :  * GVariantSerialised:
      95                 :             :  * @type_info: the #GVariantTypeInfo of this value
      96                 :             :  * @data: (nullable): the serialized data of this value, or %NULL
      97                 :             :  * @size: the size of this value
      98                 :             :  *
      99                 :             :  * A structure representing a GVariant in serialized form.  This
     100                 :             :  * structure is used with #GVariantSerialisedFiller functions and as the
     101                 :             :  * primary interface to the serializer.  See #GVariantSerialisedFiller
     102                 :             :  * for a description of its use there.
     103                 :             :  *
     104                 :             :  * When used with the serializer API functions, the following invariants
     105                 :             :  * apply to all #GVariantTypeSerialised structures passed to and
     106                 :             :  * returned from the serializer.
     107                 :             :  *
     108                 :             :  * @type_info must be non-%NULL.
     109                 :             :  *
     110                 :             :  * @data must be properly aligned for the type described by @type_info.
     111                 :             :  *
     112                 :             :  * If @type_info describes a fixed-sized type then @size must always be
     113                 :             :  * equal to the fixed size of that type.
     114                 :             :  *
     115                 :             :  * For fixed-sized types (and only fixed-sized types), @data may be
     116                 :             :  * %NULL even if @size is non-zero.  This happens when a framing error
     117                 :             :  * occurs while attempting to extract a fixed-sized value out of a
     118                 :             :  * variable-sized container.  There is no data to return for the
     119                 :             :  * fixed-sized type, yet @size must be non-zero.  The effect of this
     120                 :             :  * combination should be as if @data were a pointer to an
     121                 :             :  * appropriately-sized zero-filled region.
     122                 :             :  *
     123                 :             :  * @depth has no restrictions; the depth of a top-level serialized #GVariant is
     124                 :             :  * zero, and it increases for each level of nested child.
     125                 :             :  *
     126                 :             :  * @checked_offsets_up_to is always ≥ @ordered_offsets_up_to
     127                 :             :  */
     128                 :             : 
     129                 :             : /* < private >
     130                 :             :  * g_variant_serialised_check:
     131                 :             :  * @serialised: a #GVariantSerialised struct
     132                 :             :  *
     133                 :             :  * Checks @serialised for validity according to the invariants described
     134                 :             :  * above.
     135                 :             :  *
     136                 :             :  * Returns: %TRUE if @serialised is valid; %FALSE otherwise
     137                 :             :  */
     138                 :             : gboolean
     139                 :    19188922 : g_variant_serialised_check (GVariantSerialised serialised)
     140                 :             : {
     141                 :             :   gsize fixed_size;
     142                 :             :   guint alignment;
     143                 :             : 
     144                 :    19188922 :   if (serialised.type_info == NULL)
     145                 :           0 :     return FALSE;
     146                 :    19188922 :   g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
     147                 :             : 
     148                 :    19188922 :   if (fixed_size != 0 && serialised.size != fixed_size)
     149                 :          81 :     return FALSE;
     150                 :    19188841 :   else if (fixed_size == 0 &&
     151                 :    14853737 :            !(serialised.size == 0 || serialised.data != NULL))
     152                 :           0 :     return FALSE;
     153                 :             : 
     154                 :    19188841 :   if (serialised.ordered_offsets_up_to > serialised.checked_offsets_up_to)
     155                 :           0 :     return FALSE;
     156                 :             : 
     157                 :             :   /* Depending on the native alignment requirements of the machine, the
     158                 :             :    * compiler will insert either 3 or 7 padding bytes after the char.
     159                 :             :    * This will result in the sizeof() the struct being 12 or 16.
     160                 :             :    * Subtract 9 to get 3 or 7 which is a nice bitmask to apply to get
     161                 :             :    * the alignment bits that we "care about" being zero: in the
     162                 :             :    * 4-aligned case, we care about 2 bits, and in the 8-aligned case, we
     163                 :             :    * care about 3 bits.
     164                 :             :    */
     165                 :    19188841 :   alignment &= sizeof (struct {
     166                 :             :                          char a;
     167                 :             :                          union {
     168                 :             :                            guint64 x;
     169                 :             :                            void *y;
     170                 :             :                            gdouble z;
     171                 :             :                          } b;
     172                 :             :                        }
     173                 :             :                       ) - 9;
     174                 :             : 
     175                 :             :   /* Some OSes (FreeBSD is a known example) have a malloc() that returns
     176                 :             :    * unaligned memory if you request small sizes.  'malloc (1);', for
     177                 :             :    * example, has been seen to return pointers aligned to 6 mod 16.
     178                 :             :    *
     179                 :             :    * Check if this is a small allocation and return without enforcing
     180                 :             :    * the alignment assertion if this is the case.
     181                 :             :    */
     182                 :    35970506 :   return (serialised.size <= alignment ||
     183                 :    16781665 :           (alignment & (gsize) serialised.data) == 0);
     184                 :             : }
     185                 :             : 
     186                 :             : /* < private >
     187                 :             :  * GVariantSerialisedFiller:
     188                 :             :  * @serialised: a #GVariantSerialised instance to fill
     189                 :             :  * @data: data from the children array
     190                 :             :  *
     191                 :             :  * This function is called back from g_variant_serialiser_needed_size()
     192                 :             :  * and g_variant_serialiser_serialise().  It fills in missing details
     193                 :             :  * from a partially-complete #GVariantSerialised.
     194                 :             :  *
     195                 :             :  * The @data parameter passed back to the function is one of the items
     196                 :             :  * that was passed to the serializer in the @children array.  It
     197                 :             :  * represents a single child item of the container that is being
     198                 :             :  * serialized.  The information filled in to @serialised is the
     199                 :             :  * information for this child.
     200                 :             :  *
     201                 :             :  * If the @type_info field of @serialised is %NULL then the callback
     202                 :             :  * function must set it to the type information corresponding to the
     203                 :             :  * type of the child.  No reference should be added.  If it is non-%NULL
     204                 :             :  * then the callback should assert that it is equal to the actual type
     205                 :             :  * of the child.
     206                 :             :  *
     207                 :             :  * If the @size field is zero then the callback must fill it in with the
     208                 :             :  * required amount of space to store the serialized form of the child.
     209                 :             :  * If it is non-zero then the callback should assert that it is equal to
     210                 :             :  * the needed size of the child.
     211                 :             :  *
     212                 :             :  * If @data is non-%NULL then it points to a space that is properly
     213                 :             :  * aligned for and large enough to store the serialized data of the
     214                 :             :  * child.  The callback must store the serialized form of the child at
     215                 :             :  * @data.
     216                 :             :  *
     217                 :             :  * If the child value is another container then the callback will likely
     218                 :             :  * recurse back into the serializer by calling
     219                 :             :  * g_variant_serialiser_needed_size() to determine @size and
     220                 :             :  * g_variant_serialiser_serialise() to write to @data.
     221                 :             :  */
     222                 :             : 
     223                 :             : /* PART 1: Container types {{{1
     224                 :             :  *
     225                 :             :  * This section contains the serializer implementation functions for
     226                 :             :  * each container type.
     227                 :             :  */
     228                 :             : 
     229                 :             : /* Maybe {{{2
     230                 :             :  *
     231                 :             :  * Maybe types are handled depending on if the element type of the maybe
     232                 :             :  * type is a fixed-sized or variable-sized type.  Although all maybe
     233                 :             :  * types themselves are variable-sized types, herein, a maybe value with
     234                 :             :  * a fixed-sized element type is called a "fixed-sized maybe" for
     235                 :             :  * convenience and a maybe value with a variable-sized element type is
     236                 :             :  * called a "variable-sized maybe".
     237                 :             :  */
     238                 :             : 
     239                 :             : /* Fixed-sized Maybe {{{3
     240                 :             :  *
     241                 :             :  * The size of a maybe value with a fixed-sized element type is either 0
     242                 :             :  * or equal to the fixed size of its element type.  The case where the
     243                 :             :  * size of the maybe value is zero corresponds to the "Nothing" case and
     244                 :             :  * the case where the size of the maybe value is equal to the fixed size
     245                 :             :  * of the element type corresponds to the "Just" case; in that case, the
     246                 :             :  * serialized data of the child value forms the entire serialized data
     247                 :             :  * of the maybe value.
     248                 :             :  *
     249                 :             :  * In the event that a fixed-sized maybe value is presented with a size
     250                 :             :  * that is not equal to the fixed size of the element type then the
     251                 :             :  * value must be taken to be "Nothing".
     252                 :             :  */
     253                 :             : 
     254                 :             : static gsize
     255                 :       55229 : gvs_fixed_sized_maybe_n_children (GVariantSerialised value)
     256                 :             : {
     257                 :             :   gsize element_fixed_size;
     258                 :             : 
     259                 :       55229 :   g_variant_type_info_query_element (value.type_info, NULL,
     260                 :             :                                      &element_fixed_size);
     261                 :             : 
     262                 :       55229 :   return (element_fixed_size == value.size) ? 1 : 0;
     263                 :             : }
     264                 :             : 
     265                 :             : static GVariantSerialised
     266                 :       12923 : gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
     267                 :             :                                  gsize              index_)
     268                 :             : {
     269                 :             :   /* the child has the same bounds as the
     270                 :             :    * container, so just update the type.
     271                 :             :    */
     272                 :       12923 :   value.type_info = g_variant_type_info_element (value.type_info);
     273                 :       12923 :   g_variant_type_info_ref (value.type_info);
     274                 :       12923 :   value.depth++;
     275                 :       12923 :   value.ordered_offsets_up_to = 0;
     276                 :       12923 :   value.checked_offsets_up_to = 0;
     277                 :             : 
     278                 :       12923 :   return value;
     279                 :             : }
     280                 :             : 
     281                 :             : static gsize
     282                 :       56818 : gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
     283                 :             :                                    GVariantSerialisedFiller  gvs_filler,
     284                 :             :                                    const gpointer           *children,
     285                 :             :                                    gsize                     n_children)
     286                 :             : {
     287                 :       56818 :   if (n_children)
     288                 :             :     {
     289                 :             :       gsize element_fixed_size;
     290                 :             : 
     291                 :       28121 :       g_variant_type_info_query_element (type_info, NULL,
     292                 :             :                                          &element_fixed_size);
     293                 :             : 
     294                 :       28121 :       return element_fixed_size;
     295                 :             :     }
     296                 :             :   else
     297                 :       28697 :     return 0;
     298                 :             : }
     299                 :             : 
     300                 :             : static void
     301                 :       21677 : gvs_fixed_sized_maybe_serialise (GVariantSerialised        value,
     302                 :             :                                  GVariantSerialisedFiller  gvs_filler,
     303                 :             :                                  const gpointer           *children,
     304                 :             :                                  gsize                     n_children)
     305                 :             : {
     306                 :       21677 :   if (n_children)
     307                 :             :     {
     308                 :       11695 :       GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0, 0 };
     309                 :             : 
     310                 :       11695 :       gvs_filler (&child, children[0]);
     311                 :             :     }
     312                 :       21677 : }
     313                 :             : 
     314                 :             : static gboolean
     315                 :       17657 : gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
     316                 :             : {
     317                 :       17657 :   if (value.size > 0)
     318                 :             :     {
     319                 :             :       gsize element_fixed_size;
     320                 :             : 
     321                 :        8712 :       g_variant_type_info_query_element (value.type_info,
     322                 :             :                                          NULL, &element_fixed_size);
     323                 :             : 
     324                 :        8712 :       if (value.size != element_fixed_size)
     325                 :          16 :         return FALSE;
     326                 :             : 
     327                 :             :       /* proper element size: "Just".  recurse to the child. */
     328                 :        8696 :       value.type_info = g_variant_type_info_element (value.type_info);
     329                 :        8696 :       value.depth++;
     330                 :        8696 :       value.ordered_offsets_up_to = 0;
     331                 :        8696 :       value.checked_offsets_up_to = 0;
     332                 :             : 
     333                 :        8696 :       return g_variant_serialised_is_normal (value);
     334                 :             :     }
     335                 :             : 
     336                 :             :   /* size of 0: "Nothing" */
     337                 :        8945 :   return TRUE;
     338                 :             : }
     339                 :             : 
     340                 :             : /* Variable-sized Maybe
     341                 :             :  *
     342                 :             :  * The size of a maybe value with a variable-sized element type is
     343                 :             :  * either 0 or strictly greater than 0.  The case where the size of the
     344                 :             :  * maybe value is zero corresponds to the "Nothing" case and the case
     345                 :             :  * where the size of the maybe value is greater than zero corresponds to
     346                 :             :  * the "Just" case; in that case, the serialized data of the child value
     347                 :             :  * forms the first part of the serialized data of the maybe value and is
     348                 :             :  * followed by a single zero byte.  This zero byte is always appended,
     349                 :             :  * regardless of any zero bytes that may already be at the end of the
     350                 :             :  * serialized ata of the child value.
     351                 :             :  */
     352                 :             : 
     353                 :             : static gsize
     354                 :       19067 : gvs_variable_sized_maybe_n_children (GVariantSerialised value)
     355                 :             : {
     356                 :       19067 :   return (value.size > 0) ? 1 : 0;
     357                 :             : }
     358                 :             : 
     359                 :             : static GVariantSerialised
     360                 :        7298 : gvs_variable_sized_maybe_get_child (GVariantSerialised value,
     361                 :             :                                     gsize              index_)
     362                 :             : {
     363                 :             :   /* remove the padding byte and update the type. */
     364                 :        7298 :   value.type_info = g_variant_type_info_element (value.type_info);
     365                 :        7298 :   g_variant_type_info_ref (value.type_info);
     366                 :        7298 :   value.size--;
     367                 :             : 
     368                 :             :   /* if it's zero-sized then it may as well be NULL */
     369                 :        7298 :   if (value.size == 0)
     370                 :          78 :     value.data = NULL;
     371                 :             : 
     372                 :        7298 :   value.depth++;
     373                 :        7298 :   value.ordered_offsets_up_to = 0;
     374                 :        7298 :   value.checked_offsets_up_to = 0;
     375                 :             : 
     376                 :        7298 :   return value;
     377                 :             : }
     378                 :             : 
     379                 :             : static gsize
     380                 :       27854 : gvs_variable_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
     381                 :             :                                       GVariantSerialisedFiller  gvs_filler,
     382                 :             :                                       const gpointer           *children,
     383                 :             :                                       gsize                     n_children)
     384                 :             : {
     385                 :       27854 :   if (n_children)
     386                 :             :     {
     387                 :       13911 :       GVariantSerialised child = { 0, };
     388                 :             : 
     389                 :       13911 :       gvs_filler (&child, children[0]);
     390                 :             : 
     391                 :       13911 :       return child.size + 1;
     392                 :             :     }
     393                 :             :   else
     394                 :       13943 :     return 0;
     395                 :             : }
     396                 :             : 
     397                 :             : static void
     398                 :       11452 : gvs_variable_sized_maybe_serialise (GVariantSerialised        value,
     399                 :             :                                     GVariantSerialisedFiller  gvs_filler,
     400                 :             :                                     const gpointer           *children,
     401                 :             :                                     gsize                     n_children)
     402                 :             : {
     403                 :       11452 :   if (n_children)
     404                 :             :     {
     405                 :        6736 :       GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0, 0 };
     406                 :             : 
     407                 :             :       /* write the data for the child.  */
     408                 :        6736 :       gvs_filler (&child, children[0]);
     409                 :        6736 :       value.data[child.size] = '\0';
     410                 :             :     }
     411                 :       11452 : }
     412                 :             : 
     413                 :             : static gboolean
     414                 :        9092 : gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
     415                 :             : {
     416                 :        9092 :   if (value.size == 0)
     417                 :        4511 :     return TRUE;
     418                 :             : 
     419                 :        4581 :   if (value.data[value.size - 1] != '\0')
     420                 :          15 :     return FALSE;
     421                 :             : 
     422                 :        4566 :   value.type_info = g_variant_type_info_element (value.type_info);
     423                 :        4566 :   value.size--;
     424                 :        4566 :   value.depth++;
     425                 :        4566 :   value.ordered_offsets_up_to = 0;
     426                 :        4566 :   value.checked_offsets_up_to = 0;
     427                 :             : 
     428                 :        4566 :   return g_variant_serialised_is_normal (value);
     429                 :             : }
     430                 :             : 
     431                 :             : /* Arrays {{{2
     432                 :             :  *
     433                 :             :  * Just as with maybe types, array types are handled depending on if the
     434                 :             :  * element type of the array type is a fixed-sized or variable-sized
     435                 :             :  * type.  Similar to maybe types, for convenience, an array value with a
     436                 :             :  * fixed-sized element type is called a "fixed-sized array" and an array
     437                 :             :  * value with a variable-sized element type is called a "variable sized
     438                 :             :  * array".
     439                 :             :  */
     440                 :             : 
     441                 :             : /* Fixed-sized Array {{{3
     442                 :             :  *
     443                 :             :  * For fixed sized arrays, the serialized data is simply a concatenation
     444                 :             :  * of the serialized data of each element, in order.  Since fixed-sized
     445                 :             :  * values always have a fixed size that is a multiple of their alignment
     446                 :             :  * requirement no extra padding is required.
     447                 :             :  *
     448                 :             :  * In the event that a fixed-sized array is presented with a size that
     449                 :             :  * is not an integer multiple of the element size then the value of the
     450                 :             :  * array must be taken as being empty.
     451                 :             :  */
     452                 :             : 
     453                 :             : static gsize
     454                 :     3260541 : gvs_fixed_sized_array_n_children (GVariantSerialised value)
     455                 :             : {
     456                 :             :   gsize element_fixed_size;
     457                 :             : 
     458                 :     3260541 :   g_variant_type_info_query_element (value.type_info, NULL,
     459                 :             :                                      &element_fixed_size);
     460                 :             : 
     461                 :     3260541 :   if (value.size % element_fixed_size == 0)
     462                 :     3260527 :     return value.size / element_fixed_size;
     463                 :             : 
     464                 :          14 :   return 0;
     465                 :             : }
     466                 :             : 
     467                 :             : static GVariantSerialised
     468                 :     3208893 : gvs_fixed_sized_array_get_child (GVariantSerialised value,
     469                 :             :                                  gsize              index_)
     470                 :             : {
     471                 :     3208893 :   GVariantSerialised child = { 0, };
     472                 :             : 
     473                 :     3208893 :   child.type_info = g_variant_type_info_element (value.type_info);
     474                 :     3208893 :   g_variant_type_info_query (child.type_info, NULL, &child.size);
     475                 :     3208893 :   child.data = value.data + (child.size * index_);
     476                 :     3208893 :   g_variant_type_info_ref (child.type_info);
     477                 :     3208893 :   child.depth = value.depth + 1;
     478                 :             : 
     479                 :     3208893 :   return child;
     480                 :             : }
     481                 :             : 
     482                 :             : static gsize
     483                 :      129015 : gvs_fixed_sized_array_needed_size (GVariantTypeInfo         *type_info,
     484                 :             :                                    GVariantSerialisedFiller  gvs_filler,
     485                 :             :                                    const gpointer           *children,
     486                 :             :                                    gsize                     n_children)
     487                 :             : {
     488                 :             :   gsize element_fixed_size;
     489                 :             : 
     490                 :      129015 :   g_variant_type_info_query_element (type_info, NULL, &element_fixed_size);
     491                 :             : 
     492                 :      129015 :   return element_fixed_size * n_children;
     493                 :             : }
     494                 :             : 
     495                 :             : static void
     496                 :       45252 : gvs_fixed_sized_array_serialise (GVariantSerialised        value,
     497                 :             :                                  GVariantSerialisedFiller  gvs_filler,
     498                 :             :                                  const gpointer           *children,
     499                 :             :                                  gsize                     n_children)
     500                 :             : {
     501                 :       45252 :   GVariantSerialised child = { 0, };
     502                 :             :   gsize i;
     503                 :             : 
     504                 :       45252 :   child.type_info = g_variant_type_info_element (value.type_info);
     505                 :       45252 :   g_variant_type_info_query (child.type_info, NULL, &child.size);
     506                 :       45252 :   child.data = value.data;
     507                 :       45252 :   child.depth = value.depth + 1;
     508                 :             : 
     509                 :     2851463 :   for (i = 0; i < n_children; i++)
     510                 :             :     {
     511                 :     2806211 :       gvs_filler (&child, children[i]);
     512                 :     2806211 :       child.data += child.size;
     513                 :             :     }
     514                 :       45252 : }
     515                 :             : 
     516                 :             : static gboolean
     517                 :       24382 : gvs_fixed_sized_array_is_normal (GVariantSerialised value)
     518                 :             : {
     519                 :       24382 :   GVariantSerialised child = { 0, };
     520                 :             : 
     521                 :       24382 :   child.type_info = g_variant_type_info_element (value.type_info);
     522                 :       24382 :   g_variant_type_info_query (child.type_info, NULL, &child.size);
     523                 :       24382 :   child.depth = value.depth + 1;
     524                 :             : 
     525                 :       24382 :   if (value.size % child.size != 0)
     526                 :          13 :     return FALSE;
     527                 :             : 
     528                 :       24369 :   for (child.data = value.data;
     529                 :     1562495 :        child.data < value.data + value.size;
     530                 :     1538126 :        child.data += child.size)
     531                 :             :     {
     532                 :     1538144 :       if (!g_variant_serialised_is_normal (child))
     533                 :          18 :         return FALSE;
     534                 :             :     }
     535                 :             : 
     536                 :       24351 :   return TRUE;
     537                 :             : }
     538                 :             : 
     539                 :             : /* Variable-sized Array {{{3
     540                 :             :  *
     541                 :             :  * Variable sized arrays, containing variable-sized elements, must be
     542                 :             :  * able to determine the boundaries between the elements.  The items
     543                 :             :  * cannot simply be concatenated.  Additionally, we are faced with the
     544                 :             :  * fact that non-fixed-sized values do not necessarily have a size that
     545                 :             :  * is a multiple of their alignment requirement, so we may need to
     546                 :             :  * insert zero-filled padding.
     547                 :             :  *
     548                 :             :  * While it is possible to find the start of an item by starting from
     549                 :             :  * the end of the item before it and padding for alignment, it is not
     550                 :             :  * generally possible to do the reverse operation.  For this reason, we
     551                 :             :  * record the end point of each element in the array.
     552                 :             :  *
     553                 :             :  * GVariant works in terms of "offsets".  An offset is a pointer to a
     554                 :             :  * boundary between two bytes.  In 4 bytes of serialized data, there
     555                 :             :  * would be 5 possible offsets: one at the start ('0'), one between each
     556                 :             :  * pair of adjacent bytes ('1', '2', '3') and one at the end ('4').
     557                 :             :  *
     558                 :             :  * The numeric value of an offset is an unsigned integer given relative
     559                 :             :  * to the start of the serialized data of the array.  Offsets are always
     560                 :             :  * stored in little endian byte order and are always only as big as they
     561                 :             :  * need to be.  For example, in 255 bytes of serialized data, there are
     562                 :             :  * 256 offsets.  All possibilities can be stored in an 8 bit unsigned
     563                 :             :  * integer.  In 256 bytes of serialized data, however, there are 257
     564                 :             :  * possible offsets so 16 bit integers must be used.  The size of an
     565                 :             :  * offset is always a power of 2.
     566                 :             :  *
     567                 :             :  * The offsets are stored at the end of the serialized data of the
     568                 :             :  * array.  They are simply concatenated on without any particular
     569                 :             :  * alignment.  The size of the offsets is included in the size of the
     570                 :             :  * serialized data for purposes of determining the size of the offsets.
     571                 :             :  * This presents a possibly ambiguity; in certain cases, a particular
     572                 :             :  * value of array could have two different serialized forms.
     573                 :             :  *
     574                 :             :  * Imagine an array containing a single string of 253 bytes in length
     575                 :             :  * (so, 254 bytes including the nul terminator).  Now the offset must be
     576                 :             :  * written.  If an 8 bit offset is written, it will bring the size of
     577                 :             :  * the array's serialized data to 255 -- which means that the use of an
     578                 :             :  * 8 bit offset was valid.  If a 16 bit offset is used then the total
     579                 :             :  * size of the array will be 256 -- which means that the use of a 16 bit
     580                 :             :  * offset was valid.  Although both of these will be accepted by the
     581                 :             :  * deserializer, only the smaller of the two is considered to be in
     582                 :             :  * normal form and that is the one that the serializer must produce.
     583                 :             :  */
     584                 :             : 
     585                 :             : /* bytes may be NULL if (size == 0). */
     586                 :             : static inline gsize
     587                 :     9918465 : gvs_read_unaligned_le (guchar *bytes,
     588                 :             :                        guint   size)
     589                 :             : {
     590                 :             :   union
     591                 :             :   {
     592                 :             :     guchar bytes[GLIB_SIZEOF_SIZE_T];
     593                 :             :     gsize integer;
     594                 :             :   } tmpvalue;
     595                 :             : 
     596                 :     9918465 :   tmpvalue.integer = 0;
     597                 :     9918465 :   if (bytes != NULL)
     598                 :     9142485 :     memcpy (&tmpvalue.bytes, bytes, size);
     599                 :             : 
     600                 :     9918465 :   return GSIZE_FROM_LE (tmpvalue.integer);
     601                 :             : }
     602                 :             : 
     603                 :             : static inline void
     604                 :      995105 : gvs_write_unaligned_le (guchar *bytes,
     605                 :             :                         gsize   value,
     606                 :             :                         guint   size)
     607                 :             : {
     608                 :             :   union
     609                 :             :   {
     610                 :             :     guchar bytes[GLIB_SIZEOF_SIZE_T];
     611                 :             :     gsize integer;
     612                 :             :   } tmpvalue;
     613                 :             : 
     614                 :      995105 :   tmpvalue.integer = GSIZE_TO_LE (value);
     615                 :      995105 :   memcpy (bytes, &tmpvalue.bytes, size);
     616                 :      995105 : }
     617                 :             : 
     618                 :             : static guint
     619                 :     4537194 : gvs_get_offset_size (gsize size)
     620                 :             : {
     621                 :     4537194 :   if (size > G_MAXUINT32)
     622                 :           0 :     return 8;
     623                 :             : 
     624                 :     4537194 :   else if (size > G_MAXUINT16)
     625                 :     1494760 :     return 4;
     626                 :             : 
     627                 :     3042434 :   else if (size > G_MAXUINT8)
     628                 :     2308150 :     return 2;
     629                 :             : 
     630                 :      734284 :   else if (size > 0)
     631                 :      359221 :     return 1;
     632                 :             : 
     633                 :      375063 :   return 0;
     634                 :             : }
     635                 :             : 
     636                 :             : static gsize
     637                 :     3726068 : gvs_calculate_total_size (gsize body_size,
     638                 :             :                           gsize offsets)
     639                 :             : {
     640                 :     3726068 :   if (body_size + 1 * offsets <= G_MAXUINT8)
     641                 :      114332 :     return body_size + 1 * offsets;
     642                 :             : 
     643                 :     3611736 :   if (body_size + 2 * offsets <= G_MAXUINT16)
     644                 :     2117415 :     return body_size + 2 * offsets;
     645                 :             : 
     646                 :     1494321 :   if (body_size + 4 * offsets <= G_MAXUINT32)
     647                 :     1494321 :     return body_size + 4 * offsets;
     648                 :             : 
     649                 :           0 :   return body_size + 8 * offsets;
     650                 :             : }
     651                 :             : 
     652                 :             : struct Offsets
     653                 :             : {
     654                 :             :   gsize     data_size;
     655                 :             : 
     656                 :             :   guchar   *array;
     657                 :             :   gsize     length;
     658                 :             :   guint     offset_size;
     659                 :             : 
     660                 :             :   gboolean  is_normal;
     661                 :             : };
     662                 :             : 
     663                 :             : static gsize
     664                 :     1922296 : gvs_offsets_get_offset_n (struct Offsets *offsets,
     665                 :             :                           gsize           n)
     666                 :             : {
     667                 :     3844592 :   return gvs_read_unaligned_le (
     668                 :     1922296 :       offsets->array + (offsets->offset_size * n), offsets->offset_size);
     669                 :             : }
     670                 :             : 
     671                 :             : static struct Offsets
     672                 :     3924104 : gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value)
     673                 :             : {
     674                 :     3924104 :   struct Offsets out = { 0, };
     675                 :             :   gsize offsets_array_size;
     676                 :             :   gsize last_end;
     677                 :             : 
     678                 :     3924104 :   if (value.size == 0)
     679                 :             :     {
     680                 :      366400 :       out.is_normal = TRUE;
     681                 :      366400 :       return out;
     682                 :             :     }
     683                 :             : 
     684                 :     3557704 :   out.offset_size = gvs_get_offset_size (value.size);
     685                 :     3557704 :   last_end = gvs_read_unaligned_le (value.data + value.size - out.offset_size,
     686                 :             :                                     out.offset_size);
     687                 :             : 
     688                 :     3557704 :   if (last_end > value.size)
     689                 :          46 :     return out;  /* offsets not normal */
     690                 :             : 
     691                 :     3557658 :   offsets_array_size = value.size - last_end;
     692                 :             : 
     693                 :     3557658 :   if (offsets_array_size % out.offset_size)
     694                 :          47 :     return out;  /* offsets not normal */
     695                 :             : 
     696                 :     3557611 :   out.data_size = last_end;
     697                 :     3557611 :   out.array = value.data + last_end;
     698                 :     3557611 :   out.length = offsets_array_size / out.offset_size;
     699                 :             : 
     700                 :     3557611 :   if (out.length > 0 && gvs_calculate_total_size (last_end, out.length) != value.size)
     701                 :        1251 :     return out;  /* offset size not minimal */
     702                 :             : 
     703                 :     3556360 :   out.is_normal = TRUE;
     704                 :             : 
     705                 :     3556360 :   return out;
     706                 :             : }
     707                 :             : 
     708                 :             : static gsize
     709                 :     2146966 : gvs_variable_sized_array_n_children (GVariantSerialised value)
     710                 :             : {
     711                 :     2146966 :   return gvs_variable_sized_array_get_frame_offsets (value).length;
     712                 :             : }
     713                 :             : 
     714                 :             : /* Find the index of the first out-of-order element in @data, assuming that
     715                 :             :  * @data is an array of elements of given @type, starting at index @start and
     716                 :             :  * containing a further @len-@start elements. */
     717                 :             : #define DEFINE_FIND_UNORDERED(type, le_to_native) \
     718                 :             :   static gsize \
     719                 :             :   find_unordered_##type (const guint8 *data, gsize start, gsize len) \
     720                 :             :   { \
     721                 :             :     gsize off; \
     722                 :             :     type current_le, previous_le, current, previous; \
     723                 :             :     \
     724                 :             :     memcpy (&previous_le, data + start * sizeof (current), sizeof (current)); \
     725                 :             :     previous = le_to_native (previous_le); \
     726                 :             :     for (off = (start + 1) * sizeof (current); off < len * sizeof (current); off += sizeof (current)) \
     727                 :             :       { \
     728                 :             :         memcpy (&current_le, data + off, sizeof (current)); \
     729                 :             :         current = le_to_native (current_le); \
     730                 :             :         if (current < previous) \
     731                 :             :           break; \
     732                 :             :         previous = current; \
     733                 :             :       } \
     734                 :             :     return off / sizeof (current) - 1; \
     735                 :             :   }
     736                 :             : 
     737                 :             : #define NO_CONVERSION(x) (x)
     738                 :      453441 : DEFINE_FIND_UNORDERED (guint8, NO_CONVERSION);
     739                 :    32962680 : DEFINE_FIND_UNORDERED (guint16, GUINT16_FROM_LE);
     740                 :     1577492 : DEFINE_FIND_UNORDERED (guint32, GUINT32_FROM_LE);
     741                 :           0 : DEFINE_FIND_UNORDERED (guint64, GUINT64_FROM_LE);
     742                 :             : 
     743                 :             : static GVariantSerialised
     744                 :     1764781 : gvs_variable_sized_array_get_child (GVariantSerialised value,
     745                 :             :                                     gsize              index_)
     746                 :             : {
     747                 :     1764781 :   GVariantSerialised child = { 0, };
     748                 :             : 
     749                 :     1764781 :   struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
     750                 :             : 
     751                 :             :   gsize start;
     752                 :             :   gsize end;
     753                 :             : 
     754                 :     1764781 :   child.type_info = g_variant_type_info_element (value.type_info);
     755                 :     1764781 :   g_variant_type_info_ref (child.type_info);
     756                 :     1764781 :   child.depth = value.depth + 1;
     757                 :             : 
     758                 :             :   /* If the requested @index_ is beyond the set of indices whose framing offsets
     759                 :             :    * have been checked, check the remaining offsets to see whether they’re
     760                 :             :    * normal (in order, no overlapping array elements).
     761                 :             :    *
     762                 :             :    * Don’t bother checking if the highest known-good offset is lower than the
     763                 :             :    * highest checked offset, as that means there’s an invalid element at that
     764                 :             :    * index, so there’s no need to check further. */
     765                 :     1764781 :   if (offsets.array != NULL &&
     766                 :     1764781 :       index_ > value.checked_offsets_up_to &&
     767                 :     1572848 :       value.ordered_offsets_up_to == value.checked_offsets_up_to)
     768                 :             :     {
     769                 :     1572848 :       switch (offsets.offset_size)
     770                 :             :         {
     771                 :       14631 :         case 1:
     772                 :             :           {
     773                 :       29262 :             value.ordered_offsets_up_to = find_unordered_guint8 (
     774                 :       14631 :                 offsets.array, value.checked_offsets_up_to, index_ + 1);
     775                 :       14631 :             break;
     776                 :             :           }
     777                 :      814018 :         case 2:
     778                 :             :           {
     779                 :     1628036 :             value.ordered_offsets_up_to = find_unordered_guint16 (
     780                 :      814018 :                 offsets.array, value.checked_offsets_up_to, index_ + 1);
     781                 :      814018 :             break;
     782                 :             :           }
     783                 :      744199 :         case 4:
     784                 :             :           {
     785                 :     1488398 :             value.ordered_offsets_up_to = find_unordered_guint32 (
     786                 :      744199 :                 offsets.array, value.checked_offsets_up_to, index_ + 1);
     787                 :      744199 :             break;
     788                 :             :           }
     789                 :           0 :         case 8:
     790                 :             :           {
     791                 :           0 :             value.ordered_offsets_up_to = find_unordered_guint64 (
     792                 :           0 :                 offsets.array, value.checked_offsets_up_to, index_ + 1);
     793                 :           0 :             break;
     794                 :             :           }
     795                 :           0 :         default:
     796                 :             :           /* gvs_get_offset_size() only returns maximum 8 */
     797                 :             :           g_assert_not_reached ();
     798                 :             :         }
     799                 :             : 
     800                 :     1572848 :       value.checked_offsets_up_to = index_;
     801                 :             :     }
     802                 :             : 
     803                 :     1764781 :   if (index_ > value.ordered_offsets_up_to)
     804                 :             :     {
     805                 :             :       /* Offsets are invalid somewhere, so return an empty child. */
     806                 :      794929 :       return child;
     807                 :             :     }
     808                 :             : 
     809                 :      969852 :   if (index_ > 0)
     810                 :             :     {
     811                 :             :       guint alignment;
     812                 :             : 
     813                 :      952444 :       start = gvs_offsets_get_offset_n (&offsets, index_ - 1);
     814                 :             : 
     815                 :      952444 :       g_variant_type_info_query (child.type_info, &alignment, NULL);
     816                 :      952444 :       start += (-start) & alignment;
     817                 :             :     }
     818                 :             :   else
     819                 :       17408 :     start = 0;
     820                 :             : 
     821                 :      969852 :   end = gvs_offsets_get_offset_n (&offsets, index_);
     822                 :             : 
     823                 :      969852 :   if (start < end && end <= value.size && end <= offsets.data_size)
     824                 :             :     {
     825                 :      956465 :       child.data = value.data + start;
     826                 :      956465 :       child.size = end - start;
     827                 :             :     }
     828                 :             : 
     829                 :      969852 :   return child;
     830                 :             : }
     831                 :             : 
     832                 :             : static gsize
     833                 :       39912 : gvs_variable_sized_array_needed_size (GVariantTypeInfo         *type_info,
     834                 :             :                                       GVariantSerialisedFiller  gvs_filler,
     835                 :             :                                       const gpointer           *children,
     836                 :             :                                       gsize                     n_children)
     837                 :             : {
     838                 :             :   guint alignment;
     839                 :             :   gsize offset;
     840                 :             :   gsize i;
     841                 :             : 
     842                 :       39912 :   g_variant_type_info_query (type_info, &alignment, NULL);
     843                 :       39912 :   offset = 0;
     844                 :             : 
     845                 :     2412925 :   for (i = 0; i < n_children; i++)
     846                 :             :     {
     847                 :     2373013 :       GVariantSerialised child = { 0, };
     848                 :             : 
     849                 :     2373013 :       offset += (-offset) & alignment;
     850                 :     2373013 :       gvs_filler (&child, children[i]);
     851                 :     2373013 :       offset += child.size;
     852                 :             :     }
     853                 :             : 
     854                 :       39912 :   return gvs_calculate_total_size (offset, n_children);
     855                 :             : }
     856                 :             : 
     857                 :             : static void
     858                 :       16573 : gvs_variable_sized_array_serialise (GVariantSerialised        value,
     859                 :             :                                     GVariantSerialisedFiller  gvs_filler,
     860                 :             :                                     const gpointer           *children,
     861                 :             :                                     gsize                     n_children)
     862                 :             : {
     863                 :             :   guchar *offset_ptr;
     864                 :             :   gsize offset_size;
     865                 :             :   guint alignment;
     866                 :             :   gsize offset;
     867                 :             :   gsize i;
     868                 :             : 
     869                 :       16573 :   g_variant_type_info_query (value.type_info, &alignment, NULL);
     870                 :       16573 :   offset_size = gvs_get_offset_size (value.size);
     871                 :       16573 :   offset = 0;
     872                 :             : 
     873                 :       16573 :   offset_ptr = value.data + value.size - offset_size * n_children;
     874                 :             : 
     875                 :      914141 :   for (i = 0; i < n_children; i++)
     876                 :             :     {
     877                 :      897568 :       GVariantSerialised child = { 0, };
     878                 :             : 
     879                 :     1249102 :       while (offset & alignment)
     880                 :      351534 :         value.data[offset++] = '\0';
     881                 :             : 
     882                 :      897568 :       child.data = value.data + offset;
     883                 :      897568 :       gvs_filler (&child, children[i]);
     884                 :      897568 :       offset += child.size;
     885                 :             : 
     886                 :      897568 :       gvs_write_unaligned_le (offset_ptr, offset, offset_size);
     887                 :      897568 :       offset_ptr += offset_size;
     888                 :             :     }
     889                 :       16573 : }
     890                 :             : 
     891                 :             : static gboolean
     892                 :       12357 : gvs_variable_sized_array_is_normal (GVariantSerialised value)
     893                 :             : {
     894                 :       12357 :   GVariantSerialised child = { 0, };
     895                 :             :   guint alignment;
     896                 :             :   gsize offset;
     897                 :             :   gsize i;
     898                 :             : 
     899                 :       12357 :   struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
     900                 :             : 
     901                 :       12357 :   if (!offsets.is_normal)
     902                 :          42 :     return FALSE;
     903                 :             : 
     904                 :       12315 :   if (value.size != 0 && offsets.length == 0)
     905                 :           0 :     return FALSE;
     906                 :             : 
     907                 :       12315 :   g_assert (value.size != 0 || offsets.length == 0);
     908                 :             : 
     909                 :       12315 :   child.type_info = g_variant_type_info_element (value.type_info);
     910                 :       12315 :   g_variant_type_info_query (child.type_info, &alignment, NULL);
     911                 :       12315 :   child.depth = value.depth + 1;
     912                 :       12315 :   offset = 0;
     913                 :             : 
     914                 :      768366 :   for (i = 0; i < offsets.length; i++)
     915                 :             :     {
     916                 :             :       gsize this_end;
     917                 :             : 
     918                 :      756209 :       this_end = gvs_read_unaligned_le (offsets.array + offsets.offset_size * i,
     919                 :             :                                         offsets.offset_size);
     920                 :             : 
     921                 :      756209 :       if (this_end < offset || this_end > offsets.data_size)
     922                 :          54 :         return FALSE;
     923                 :             : 
     924                 :      934199 :       while (offset & alignment)
     925                 :             :         {
     926                 :      178050 :           if (!(offset < this_end && value.data[offset] == '\0'))
     927                 :           6 :             return FALSE;
     928                 :      178044 :           offset++;
     929                 :             :         }
     930                 :             : 
     931                 :      756149 :       child.data = value.data + offset;
     932                 :      756149 :       child.size = this_end - offset;
     933                 :             : 
     934                 :      756149 :       if (child.size == 0)
     935                 :       11804 :         child.data = NULL;
     936                 :             : 
     937                 :      756149 :       if (!g_variant_serialised_is_normal (child))
     938                 :          98 :         return FALSE;
     939                 :             : 
     940                 :      756051 :       offset = this_end;
     941                 :             :     }
     942                 :             : 
     943                 :       12157 :   g_assert (offset == offsets.data_size);
     944                 :             : 
     945                 :             :   /* All offsets have now been checked. */
     946                 :       12157 :   value.ordered_offsets_up_to = G_MAXSIZE;
     947                 :       12157 :   value.checked_offsets_up_to = G_MAXSIZE;
     948                 :             : 
     949                 :       12157 :   return TRUE;
     950                 :             : }
     951                 :             : 
     952                 :             : /* Tuples {{{2
     953                 :             :  *
     954                 :             :  * Since tuples can contain a mix of variable- and fixed-sized items,
     955                 :             :  * they are, in terms of serialization, a hybrid of variable-sized and
     956                 :             :  * fixed-sized arrays.
     957                 :             :  *
     958                 :             :  * Offsets are only stored for variable-sized items.  Also, since the
     959                 :             :  * number of items in a tuple is known from its type, we are able to
     960                 :             :  * know exactly how many offsets to expect in the serialized data (and
     961                 :             :  * therefore how much space is taken up by the offset array).  This
     962                 :             :  * means that we know where the end of the serialized data for the last
     963                 :             :  * item is -- we can just subtract the size of the offset array from the
     964                 :             :  * total size of the tuple.  For this reason, the last item in the tuple
     965                 :             :  * doesn't need an offset stored.
     966                 :             :  *
     967                 :             :  * Tuple offsets are stored in reverse.  This design choice allows
     968                 :             :  * iterator-based deserializers to be more efficient.
     969                 :             :  *
     970                 :             :  * Most of the "heavy lifting" here is handled by the GVariantTypeInfo
     971                 :             :  * for the tuple.  See the notes in gvarianttypeinfo.h.
     972                 :             :  */
     973                 :             : 
     974                 :             : /* Note: This doesn’t guarantee that @out_member_end >= @out_member_start; that
     975                 :             :  * condition may not hold true for invalid serialised variants. The caller is
     976                 :             :  * responsible for checking the returned values and handling invalid ones
     977                 :             :  * appropriately. */
     978                 :             : static void
     979                 :     4441145 : gvs_tuple_get_member_bounds (GVariantSerialised  value,
     980                 :             :                              gsize               index_,
     981                 :             :                              gsize               offset_size,
     982                 :             :                              gsize              *out_member_start,
     983                 :             :                              gsize              *out_member_end)
     984                 :             : {
     985                 :             :   const GVariantMemberInfo *member_info;
     986                 :             :   gsize member_start, member_end;
     987                 :             : 
     988                 :     4441145 :   member_info = g_variant_type_info_member_info (value.type_info, index_);
     989                 :             : 
     990                 :     4441145 :   if (member_info->i + 1 &&
     991                 :     2707722 :       offset_size * (member_info->i + 1) <= value.size)
     992                 :     2707699 :     member_start = gvs_read_unaligned_le (value.data + value.size -
     993                 :     2707699 :                                           offset_size * (member_info->i + 1),
     994                 :             :                                           offset_size);
     995                 :             :   else
     996                 :     1733446 :     member_start = 0;
     997                 :             : 
     998                 :     4441145 :   member_start += member_info->a;
     999                 :     4441145 :   member_start &= member_info->b;
    1000                 :     4441145 :   member_start |= member_info->c;
    1001                 :             : 
    1002                 :     4441145 :   if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST &&
    1003                 :      483988 :       offset_size * (member_info->i + 1) <= value.size)
    1004                 :      483965 :     member_end = value.size - offset_size * (member_info->i + 1);
    1005                 :             : 
    1006                 :     3957180 :   else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
    1007                 :             :     {
    1008                 :             :       gsize fixed_size;
    1009                 :             : 
    1010                 :     3042166 :       g_variant_type_info_query (member_info->type_info, NULL, &fixed_size);
    1011                 :     3042166 :       member_end = member_start + fixed_size;
    1012                 :             :     }
    1013                 :             : 
    1014                 :      915014 :   else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET &&
    1015                 :      914991 :            offset_size * (member_info->i + 2) <= value.size)
    1016                 :      914986 :     member_end = gvs_read_unaligned_le (value.data + value.size -
    1017                 :      914986 :                                         offset_size * (member_info->i + 2),
    1018                 :             :                                         offset_size);
    1019                 :             : 
    1020                 :             :   else  /* invalid */
    1021                 :          28 :     member_end = G_MAXSIZE;
    1022                 :             : 
    1023                 :     4441145 :   if (out_member_start != NULL)
    1024                 :     3660610 :     *out_member_start = member_start;
    1025                 :     4441145 :   if (out_member_end != NULL)
    1026                 :     4441145 :     *out_member_end = member_end;
    1027                 :     4441145 : }
    1028                 :             : 
    1029                 :             : static gsize
    1030                 :      967321 : gvs_tuple_n_children (GVariantSerialised value)
    1031                 :             : {
    1032                 :      967321 :   return g_variant_type_info_n_members (value.type_info);
    1033                 :             : }
    1034                 :             : 
    1035                 :             : static GVariantSerialised
    1036                 :      868137 : gvs_tuple_get_child (GVariantSerialised value,
    1037                 :             :                      gsize              index_)
    1038                 :             : {
    1039                 :             :   const GVariantMemberInfo *member_info;
    1040                 :      868137 :   GVariantSerialised child = { 0, };
    1041                 :             :   gsize offset_size;
    1042                 :             :   gsize start, end, last_end;
    1043                 :             : 
    1044                 :      868137 :   member_info = g_variant_type_info_member_info (value.type_info, index_);
    1045                 :      868137 :   child.type_info = g_variant_type_info_ref (member_info->type_info);
    1046                 :      868137 :   child.depth = value.depth + 1;
    1047                 :      868137 :   offset_size = gvs_get_offset_size (value.size);
    1048                 :             : 
    1049                 :             :   /* Ensure the size is set for fixed-sized children, or
    1050                 :             :    * g_variant_serialised_check() will fail, even if we return
    1051                 :             :    * (child.data == NULL) to indicate an error. */
    1052                 :      868137 :   if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
    1053                 :      548632 :     g_variant_type_info_query (child.type_info, NULL, &child.size);
    1054                 :             : 
    1055                 :             :   /* tuples are the only (potentially) fixed-sized containers, so the
    1056                 :             :    * only ones that have to deal with the possibility of having %NULL
    1057                 :             :    * data with a non-zero %size if errors occurred elsewhere.
    1058                 :             :    */
    1059                 :      868137 :   if G_UNLIKELY (value.data == NULL && value.size != 0)
    1060                 :             :     {
    1061                 :             :       /* this can only happen in fixed-sized tuples,
    1062                 :             :        * so the child must also be fixed sized.
    1063                 :             :        */
    1064                 :       23296 :       g_assert (child.size != 0);
    1065                 :       23296 :       child.data = NULL;
    1066                 :             : 
    1067                 :       23296 :       return child;
    1068                 :             :     }
    1069                 :             : 
    1070                 :             :   /* If the requested @index_ is beyond the set of indices whose framing offsets
    1071                 :             :    * have been checked, check the remaining offsets to see whether they’re
    1072                 :             :    * normal (in order, no overlapping tuple elements).
    1073                 :             :    *
    1074                 :             :    * Unlike the checks in gvs_variable_sized_array_get_child(), we have to check
    1075                 :             :    * all the tuple *elements* here, not just all the framing offsets, since
    1076                 :             :    * tuples contain a mix of elements which use framing offsets and ones which
    1077                 :             :    * don’t. None of them are allowed to overlap. */
    1078                 :      844841 :   if (index_ > value.checked_offsets_up_to &&
    1079                 :      613327 :       value.ordered_offsets_up_to == value.checked_offsets_up_to)
    1080                 :             :     {
    1081                 :      613327 :       gsize i, prev_i_end = 0;
    1082                 :             : 
    1083                 :      613327 :       if (value.checked_offsets_up_to > 0)
    1084                 :           0 :         gvs_tuple_get_member_bounds (value, value.checked_offsets_up_to - 1, offset_size, NULL, &prev_i_end);
    1085                 :             : 
    1086                 :     3176615 :       for (i = value.checked_offsets_up_to; i <= index_; i++)
    1087                 :             :         {
    1088                 :             :           gsize i_start, i_end;
    1089                 :             : 
    1090                 :     2880075 :           gvs_tuple_get_member_bounds (value, i, offset_size, &i_start, &i_end);
    1091                 :             : 
    1092                 :     2880075 :           if (i_start > i_end || i_start < prev_i_end || i_end > value.size)
    1093                 :             :             break;
    1094                 :             : 
    1095                 :     2563288 :           prev_i_end = i_end;
    1096                 :             :         }
    1097                 :             : 
    1098                 :      613327 :       value.ordered_offsets_up_to = i - 1;
    1099                 :      613327 :       value.checked_offsets_up_to = index_;
    1100                 :             :     }
    1101                 :             : 
    1102                 :      844841 :   if (index_ > value.ordered_offsets_up_to)
    1103                 :             :     {
    1104                 :             :       /* Offsets are invalid somewhere, so return an empty child. */
    1105                 :       64278 :       return child;
    1106                 :             :     }
    1107                 :             : 
    1108                 :      780563 :   if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
    1109                 :             :     {
    1110                 :      215776 :       if (offset_size * (member_info->i + 2) > value.size)
    1111                 :          16 :         return child;
    1112                 :             :     }
    1113                 :             :   else
    1114                 :             :     {
    1115                 :      564787 :       if (offset_size * (member_info->i + 1) > value.size)
    1116                 :          12 :         return child;
    1117                 :             :     }
    1118                 :             : 
    1119                 :             :   /* The child should not extend into the offset table. */
    1120                 :      780535 :   gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end);
    1121                 :      780535 :   gvs_tuple_get_member_bounds (value, g_variant_type_info_n_members (value.type_info) - 1, offset_size, NULL, &last_end);
    1122                 :             : 
    1123                 :      780535 :   if (start < end && end <= value.size && end <= last_end)
    1124                 :             :     {
    1125                 :      466392 :       child.data = value.data + start;
    1126                 :      466392 :       child.size = end - start;
    1127                 :             :     }
    1128                 :             : 
    1129                 :      780535 :   return child;
    1130                 :             : }
    1131                 :             : 
    1132                 :             : static gsize
    1133                 :      102372 : gvs_tuple_needed_size (GVariantTypeInfo         *type_info,
    1134                 :             :                        GVariantSerialisedFiller  gvs_filler,
    1135                 :             :                        const gpointer           *children,
    1136                 :             :                        gsize                     n_children)
    1137                 :             : {
    1138                 :      102372 :   const GVariantMemberInfo *member_info = NULL;
    1139                 :             :   gsize fixed_size;
    1140                 :             :   gsize offset;
    1141                 :             :   gsize i;
    1142                 :             : 
    1143                 :      102372 :   g_variant_type_info_query (type_info, NULL, &fixed_size);
    1144                 :             : 
    1145                 :      102372 :   if (fixed_size)
    1146                 :        6089 :     return fixed_size;
    1147                 :             : 
    1148                 :       96283 :   offset = 0;
    1149                 :             : 
    1150                 :             :   /* We must go through at least one iteration below. If the tuple had no
    1151                 :             :    * children, it would have a fixed size. */
    1152                 :       96283 :   g_assert (n_children > 0);
    1153                 :             : 
    1154                 :     1012032 :   for (i = 0; i < n_children; i++)
    1155                 :             :     {
    1156                 :             :       guint alignment;
    1157                 :             : 
    1158                 :      915749 :       member_info = g_variant_type_info_member_info (type_info, i);
    1159                 :      915749 :       g_variant_type_info_query (member_info->type_info,
    1160                 :             :                                  &alignment, &fixed_size);
    1161                 :      915749 :       offset += (-offset) & alignment;
    1162                 :             : 
    1163                 :      915749 :       if (fixed_size)
    1164                 :      676980 :         offset += fixed_size;
    1165                 :             :       else
    1166                 :             :         {
    1167                 :      238769 :           GVariantSerialised child = { 0, };
    1168                 :             : 
    1169                 :      238769 :           gvs_filler (&child, children[i]);
    1170                 :      238769 :           offset += child.size;
    1171                 :             :         }
    1172                 :             :     }
    1173                 :             : 
    1174                 :       96283 :   return gvs_calculate_total_size (offset, member_info->i + 1);
    1175                 :             : }
    1176                 :             : 
    1177                 :             : static void
    1178                 :       62028 : gvs_tuple_serialise (GVariantSerialised        value,
    1179                 :             :                      GVariantSerialisedFiller  gvs_filler,
    1180                 :             :                      const gpointer           *children,
    1181                 :             :                      gsize                     n_children)
    1182                 :             : {
    1183                 :             :   gsize offset_size;
    1184                 :             :   gsize offset;
    1185                 :             :   gsize i;
    1186                 :             : 
    1187                 :       62028 :   offset_size = gvs_get_offset_size (value.size);
    1188                 :       62028 :   offset = 0;
    1189                 :             : 
    1190                 :      446624 :   for (i = 0; i < n_children; i++)
    1191                 :             :     {
    1192                 :             :       const GVariantMemberInfo *member_info;
    1193                 :      384596 :       GVariantSerialised child = { 0, };
    1194                 :             :       guint alignment;
    1195                 :             : 
    1196                 :      384596 :       member_info = g_variant_type_info_member_info (value.type_info, i);
    1197                 :      384596 :       g_variant_type_info_query (member_info->type_info, &alignment, NULL);
    1198                 :             : 
    1199                 :      655795 :       while (offset & alignment)
    1200                 :      271199 :         value.data[offset++] = '\0';
    1201                 :             : 
    1202                 :      384596 :       child.data = value.data + offset;
    1203                 :      384596 :       gvs_filler (&child, children[i]);
    1204                 :      384596 :       offset += child.size;
    1205                 :             : 
    1206                 :      384596 :       if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
    1207                 :             :         {
    1208                 :       97537 :           value.size -= offset_size;
    1209                 :       97537 :           gvs_write_unaligned_le (value.data + value.size,
    1210                 :             :                                   offset, offset_size);
    1211                 :             :         }
    1212                 :             :     }
    1213                 :             : 
    1214                 :       80074 :   while (offset < value.size)
    1215                 :       18046 :     value.data[offset++] = '\0';
    1216                 :       62028 : }
    1217                 :             : 
    1218                 :             : static gboolean
    1219                 :       32774 : gvs_tuple_is_normal (GVariantSerialised value)
    1220                 :             : {
    1221                 :             :   guint offset_size;
    1222                 :             :   gsize offset_ptr;
    1223                 :             :   gsize length;
    1224                 :             :   gsize offset;
    1225                 :             :   gsize i;
    1226                 :             :   gsize offset_table_size;
    1227                 :             : 
    1228                 :             :   /* as per the comment in gvs_tuple_get_child() */
    1229                 :       32774 :   if G_UNLIKELY (value.data == NULL && value.size != 0)
    1230                 :          22 :     return FALSE;
    1231                 :             : 
    1232                 :       32752 :   offset_size = gvs_get_offset_size (value.size);
    1233                 :       32752 :   length = g_variant_type_info_n_members (value.type_info);
    1234                 :       32752 :   offset_ptr = value.size;
    1235                 :       32752 :   offset = 0;
    1236                 :             : 
    1237                 :      331659 :   for (i = 0; i < length; i++)
    1238                 :             :     {
    1239                 :             :       const GVariantMemberInfo *member_info;
    1240                 :      299362 :       GVariantSerialised child = { 0, };
    1241                 :             :       gsize fixed_size;
    1242                 :             :       guint alignment;
    1243                 :             :       gsize end;
    1244                 :             : 
    1245                 :      299362 :       member_info = g_variant_type_info_member_info (value.type_info, i);
    1246                 :      299362 :       child.type_info = member_info->type_info;
    1247                 :      299362 :       child.depth = value.depth + 1;
    1248                 :             : 
    1249                 :      299362 :       g_variant_type_info_query (child.type_info, &alignment, &fixed_size);
    1250                 :             : 
    1251                 :      523426 :       while (offset & alignment)
    1252                 :             :         {
    1253                 :      224104 :           if (offset > value.size || value.data[offset] != '\0')
    1254                 :         455 :             return FALSE;
    1255                 :      224064 :           offset++;
    1256                 :             :         }
    1257                 :             : 
    1258                 :      299322 :       child.data = value.data + offset;
    1259                 :             : 
    1260                 :      299322 :       switch (member_info->ending_type)
    1261                 :             :         {
    1262                 :      233779 :         case G_VARIANT_MEMBER_ENDING_FIXED:
    1263                 :      233779 :           end = offset + fixed_size;
    1264                 :      233779 :           break;
    1265                 :             : 
    1266                 :        5966 :         case G_VARIANT_MEMBER_ENDING_LAST:
    1267                 :        5966 :           end = offset_ptr;
    1268                 :        5966 :           break;
    1269                 :             : 
    1270                 :       59577 :         case G_VARIANT_MEMBER_ENDING_OFFSET:
    1271                 :       59577 :           if (offset_ptr < offset_size)
    1272                 :           2 :             return FALSE;
    1273                 :             : 
    1274                 :       59575 :           offset_ptr -= offset_size;
    1275                 :             : 
    1276                 :       59575 :           if (offset_ptr < offset)
    1277                 :           4 :             return FALSE;
    1278                 :             : 
    1279                 :       59571 :           end = gvs_read_unaligned_le (value.data + offset_ptr, offset_size);
    1280                 :       59571 :           break;
    1281                 :             : 
    1282                 :           0 :         default:
    1283                 :             :           g_assert_not_reached ();
    1284                 :             :         }
    1285                 :             : 
    1286                 :      299316 :       if (end < offset || end > offset_ptr)
    1287                 :          63 :         return FALSE;
    1288                 :             : 
    1289                 :      299253 :       child.size = end - offset;
    1290                 :             : 
    1291                 :      299253 :       if (child.size == 0)
    1292                 :        2018 :         child.data = NULL;
    1293                 :             : 
    1294                 :      299253 :       if (!g_variant_serialised_is_normal (child))
    1295                 :         346 :         return FALSE;
    1296                 :             : 
    1297                 :      298907 :       offset = end;
    1298                 :             :     }
    1299                 :             : 
    1300                 :             :   /* All element bounds have been checked above. */
    1301                 :       32297 :   value.ordered_offsets_up_to = G_MAXSIZE;
    1302                 :       32297 :   value.checked_offsets_up_to = G_MAXSIZE;
    1303                 :             : 
    1304                 :             :   {
    1305                 :             :     gsize fixed_size;
    1306                 :             :     guint alignment;
    1307                 :             : 
    1308                 :       32297 :     g_variant_type_info_query (value.type_info, &alignment, &fixed_size);
    1309                 :             : 
    1310                 :       32297 :     if (fixed_size)
    1311                 :             :       {
    1312                 :        9209 :         g_assert (fixed_size == value.size);
    1313                 :        9209 :         g_assert (offset_ptr == value.size);
    1314                 :             : 
    1315                 :        9209 :         if (i == 0)
    1316                 :             :           {
    1317                 :         268 :             if (value.data[offset++] != '\0')
    1318                 :          24 :               return FALSE;
    1319                 :             :           }
    1320                 :             :         else
    1321                 :             :           {
    1322                 :       21591 :             while (offset & alignment)
    1323                 :       12666 :               if (value.data[offset++] != '\0')
    1324                 :          16 :                 return FALSE;
    1325                 :             :           }
    1326                 :             : 
    1327                 :        9185 :         g_assert (offset == value.size);
    1328                 :             :       }
    1329                 :             :   }
    1330                 :             : 
    1331                 :             :   /* @offset_ptr has been counting backwards from the end of the variant, to
    1332                 :             :    * find the beginning of the offset table. @offset has been counting forwards
    1333                 :             :    * from the beginning of the variant to find the end of the data. They should
    1334                 :             :    * have met in the middle. */
    1335                 :       32273 :   if (offset_ptr != offset)
    1336                 :           0 :     return FALSE;
    1337                 :             : 
    1338                 :       32273 :   offset_table_size = value.size - offset_ptr;
    1339                 :       32273 :   if (value.size > 0 &&
    1340                 :       32262 :       gvs_calculate_total_size (offset, offset_table_size / offset_size) != value.size)
    1341                 :           2 :     return FALSE;  /* offset size not minimal */
    1342                 :             : 
    1343                 :       32271 :   return TRUE;
    1344                 :             : }
    1345                 :             : 
    1346                 :             : /* Variants {{{2
    1347                 :             :  *
    1348                 :             :  * Variants are stored by storing the serialized data of the child,
    1349                 :             :  * followed by a '\0' character, followed by the type string of the
    1350                 :             :  * child.
    1351                 :             :  *
    1352                 :             :  * In the case that a value is presented that contains no '\0'
    1353                 :             :  * character, or doesn't have a single well-formed definite type string
    1354                 :             :  * following that character, the variant must be taken as containing the
    1355                 :             :  * unit tuple: ().
    1356                 :             :  */
    1357                 :             : 
    1358                 :             : static inline gsize
    1359                 :      146155 : gvs_variant_n_children (GVariantSerialised value)
    1360                 :             : {
    1361                 :      146155 :   return 1;
    1362                 :             : }
    1363                 :             : 
    1364                 :             : static inline GVariantSerialised
    1365                 :      145774 : gvs_variant_get_child (GVariantSerialised value,
    1366                 :             :                        gsize              index_)
    1367                 :             : {
    1368                 :      145774 :   GVariantSerialised child = { 0, };
    1369                 :             : 
    1370                 :             :   /* NOTE: not O(1) and impossible for it to be... */
    1371                 :      145774 :   if (value.size)
    1372                 :             :     {
    1373                 :             :       /* find '\0' character */
    1374                 :      288656 :       for (child.size = value.size - 1; child.size; child.size--)
    1375                 :      288167 :         if (value.data[child.size] == '\0')
    1376                 :      125970 :           break;
    1377                 :             : 
    1378                 :             :       /* ensure we didn't just hit the start of the string */
    1379                 :      126459 :       if (value.data[child.size] == '\0')
    1380                 :             :         {
    1381                 :      126402 :           const gchar *type_string = (gchar *) &value.data[child.size + 1];
    1382                 :      126402 :           const gchar *limit = (gchar *) &value.data[value.size];
    1383                 :             :           const gchar *end;
    1384                 :             : 
    1385                 :      126402 :           if (g_variant_type_string_scan (type_string, limit, &end) &&
    1386                 :      126141 :               end == limit)
    1387                 :             :             {
    1388                 :      126122 :               const GVariantType *type = (GVariantType *) type_string;
    1389                 :             : 
    1390                 :      126122 :               if (g_variant_type_is_definite (type))
    1391                 :             :                 {
    1392                 :             :                   gsize fixed_size;
    1393                 :             :                   gsize child_type_depth;
    1394                 :             : 
    1395                 :      126120 :                   child.type_info = g_variant_type_info_get (type);
    1396                 :      126120 :                   child.depth = value.depth + 1;
    1397                 :             : 
    1398                 :      126120 :                   if (child.size != 0)
    1399                 :             :                     /* only set to non-%NULL if size > 0 */
    1400                 :      125718 :                     child.data = value.data;
    1401                 :             : 
    1402                 :      126120 :                   g_variant_type_info_query (child.type_info,
    1403                 :             :                                              NULL, &fixed_size);
    1404                 :      126120 :                   child_type_depth = g_variant_type_info_query_depth (child.type_info);
    1405                 :             : 
    1406                 :      126120 :                   if ((!fixed_size || fixed_size == child.size) &&
    1407                 :      126120 :                       value.depth < G_VARIANT_MAX_RECURSION_DEPTH - child_type_depth)
    1408                 :      126118 :                     return child;
    1409                 :             : 
    1410                 :           2 :                   g_variant_type_info_unref (child.type_info);
    1411                 :             :                 }
    1412                 :             :             }
    1413                 :             :         }
    1414                 :             :     }
    1415                 :             : 
    1416                 :       19656 :   child.type_info = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
    1417                 :       19656 :   child.data = NULL;
    1418                 :       19656 :   child.size = 1;
    1419                 :       19656 :   child.depth = value.depth + 1;
    1420                 :             : 
    1421                 :       19656 :   return child;
    1422                 :             : }
    1423                 :             : 
    1424                 :             : static inline gsize
    1425                 :      209574 : gvs_variant_needed_size (GVariantTypeInfo         *type_info,
    1426                 :             :                          GVariantSerialisedFiller  gvs_filler,
    1427                 :             :                          const gpointer           *children,
    1428                 :             :                          gsize                     n_children)
    1429                 :             : {
    1430                 :      209574 :   GVariantSerialised child = { 0, };
    1431                 :             :   const gchar *type_string;
    1432                 :             : 
    1433                 :      209574 :   gvs_filler (&child, children[0]);
    1434                 :      209574 :   type_string = g_variant_type_info_get_type_string (child.type_info);
    1435                 :             : 
    1436                 :      209574 :   return child.size + 1 + strlen (type_string);
    1437                 :             : }
    1438                 :             : 
    1439                 :             : static inline void
    1440                 :       73293 : gvs_variant_serialise (GVariantSerialised        value,
    1441                 :             :                        GVariantSerialisedFiller  gvs_filler,
    1442                 :             :                        const gpointer           *children,
    1443                 :             :                        gsize                     n_children)
    1444                 :             : {
    1445                 :       73293 :   GVariantSerialised child = { 0, };
    1446                 :             :   const gchar *type_string;
    1447                 :             : 
    1448                 :       73293 :   child.data = value.data;
    1449                 :             : 
    1450                 :       73293 :   gvs_filler (&child, children[0]);
    1451                 :       73293 :   type_string = g_variant_type_info_get_type_string (child.type_info);
    1452                 :       73293 :   value.data[child.size] = '\0';
    1453                 :       73293 :   memcpy (value.data + child.size + 1, type_string, strlen (type_string));
    1454                 :       73293 : }
    1455                 :             : 
    1456                 :             : static inline gboolean
    1457                 :       33731 : gvs_variant_is_normal (GVariantSerialised value)
    1458                 :             : {
    1459                 :             :   GVariantSerialised child;
    1460                 :             :   gboolean normal;
    1461                 :             :   gsize child_type_depth;
    1462                 :             : 
    1463                 :       33731 :   child = gvs_variant_get_child (value, 0);
    1464                 :       33731 :   child_type_depth = g_variant_type_info_query_depth (child.type_info);
    1465                 :             : 
    1466                 :      101193 :   normal = (value.depth < G_VARIANT_MAX_RECURSION_DEPTH - child_type_depth) &&
    1467                 :       67303 :            (child.data != NULL || child.size == 0) &&
    1468                 :       33572 :            g_variant_serialised_is_normal (child);
    1469                 :             : 
    1470                 :       33731 :   g_variant_type_info_unref (child.type_info);
    1471                 :             : 
    1472                 :       33731 :   return normal;
    1473                 :             : }
    1474                 :             : 
    1475                 :             : 
    1476                 :             : 
    1477                 :             : /* PART 2: Serializer API {{{1
    1478                 :             :  *
    1479                 :             :  * This is the implementation of the API of the serializer as advertised
    1480                 :             :  * in gvariant-serialiser.h.
    1481                 :             :  */
    1482                 :             : 
    1483                 :             : /* Dispatch Utilities {{{2
    1484                 :             :  *
    1485                 :             :  * These macros allow a given function (for example,
    1486                 :             :  * g_variant_serialiser_serialise) to be dispatched to the appropriate
    1487                 :             :  * type-specific function above (fixed/variable-sized maybe,
    1488                 :             :  * fixed/variable-sized array, tuple or variant).
    1489                 :             :  */
    1490                 :             : #define DISPATCH_FIXED(type_info, before, after) \
    1491                 :             :   {                                                     \
    1492                 :             :     gsize fixed_size;                                   \
    1493                 :             :                                                         \
    1494                 :             :     g_variant_type_info_query_element (type_info, NULL, \
    1495                 :             :                                        &fixed_size);    \
    1496                 :             :                                                         \
    1497                 :             :     if (fixed_size)                                     \
    1498                 :             :       {                                                 \
    1499                 :             :         before ## fixed_sized ## after                  \
    1500                 :             :       }                                                 \
    1501                 :             :     else                                                \
    1502                 :             :       {                                                 \
    1503                 :             :         before ## variable_sized ## after               \
    1504                 :             :       }                                                 \
    1505                 :             :   }
    1506                 :             : 
    1507                 :             : #define DISPATCH_CASES(type_info, before, after) \
    1508                 :             :   switch (g_variant_type_info_get_type_char (type_info))        \
    1509                 :             :     {                                                           \
    1510                 :             :       case G_VARIANT_TYPE_INFO_CHAR_MAYBE:                      \
    1511                 :             :         DISPATCH_FIXED (type_info, before, _maybe ## after)     \
    1512                 :             :                                                                 \
    1513                 :             :       case G_VARIANT_TYPE_INFO_CHAR_ARRAY:                      \
    1514                 :             :         DISPATCH_FIXED (type_info, before, _array ## after)     \
    1515                 :             :                                                                 \
    1516                 :             :       case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:                 \
    1517                 :             :       case G_VARIANT_TYPE_INFO_CHAR_TUPLE:                      \
    1518                 :             :         {                                                       \
    1519                 :             :           before ## tuple ## after                              \
    1520                 :             :         }                                                       \
    1521                 :             :                                                                 \
    1522                 :             :       case G_VARIANT_TYPE_INFO_CHAR_VARIANT:                    \
    1523                 :             :         {                                                       \
    1524                 :             :           before ## variant ## after                            \
    1525                 :             :         }                                                       \
    1526                 :             :     }
    1527                 :             : 
    1528                 :             : /* Serializer entry points {{{2
    1529                 :             :  *
    1530                 :             :  * These are the functions that are called in order for the serializer
    1531                 :             :  * to do its thing.
    1532                 :             :  */
    1533                 :             : 
    1534                 :             : /* < private >
    1535                 :             :  * g_variant_serialised_n_children:
    1536                 :             :  * @serialised: a #GVariantSerialised
    1537                 :             :  *
    1538                 :             :  * For serialized data that represents a container value (maybes,
    1539                 :             :  * tuples, arrays, variants), determine how many child items are inside
    1540                 :             :  * that container.
    1541                 :             :  *
    1542                 :             :  * Returns: the number of children
    1543                 :             :  */
    1544                 :             : gsize
    1545                 :     6595279 : g_variant_serialised_n_children (GVariantSerialised serialised)
    1546                 :             : {
    1547                 :     6595279 :   g_assert (g_variant_serialised_check (serialised));
    1548                 :             : 
    1549                 :     6595279 :   DISPATCH_CASES (serialised.type_info,
    1550                 :             : 
    1551                 :             :                   return gvs_/**/,/**/_n_children (serialised);
    1552                 :             : 
    1553                 :             :                  )
    1554                 :             :   g_assert_not_reached ();
    1555                 :             : }
    1556                 :             : 
    1557                 :             : /* < private >
    1558                 :             :  * g_variant_serialised_get_child:
    1559                 :             :  * @serialised: a #GVariantSerialised
    1560                 :             :  * @index_: the index of the child to fetch
    1561                 :             :  *
    1562                 :             :  * Extracts a child from a serialized data representing a container
    1563                 :             :  * value.
    1564                 :             :  *
    1565                 :             :  * It is an error to call this function with an index out of bounds.
    1566                 :             :  *
    1567                 :             :  * If the result .data == %NULL and .size > 0 then there has been an
    1568                 :             :  * error extracting the requested fixed-sized value.  This number of
    1569                 :             :  * zero bytes needs to be allocated instead.
    1570                 :             :  *
    1571                 :             :  * In the case that .data == %NULL and .size == 0 then a zero-sized
    1572                 :             :  * item of a variable-sized type is being returned.
    1573                 :             :  *
    1574                 :             :  * .data is never non-%NULL if size is 0.
    1575                 :             :  *
    1576                 :             :  * Returns: a #GVariantSerialised for the child
    1577                 :             :  */
    1578                 :             : GVariantSerialised
    1579                 :     5974075 : g_variant_serialised_get_child (GVariantSerialised serialised,
    1580                 :             :                                 gsize              index_)
    1581                 :             : {
    1582                 :             :   GVariantSerialised child;
    1583                 :             : 
    1584                 :     5974075 :   g_assert (g_variant_serialised_check (serialised));
    1585                 :             : 
    1586                 :     5974075 :   if G_LIKELY (index_ < g_variant_serialised_n_children (serialised))
    1587                 :             :     {
    1588                 :     5974075 :       DISPATCH_CASES (serialised.type_info,
    1589                 :             : 
    1590                 :             :                       child = gvs_/**/,/**/_get_child (serialised, index_);
    1591                 :             :                       g_assert (child.size || child.data == NULL);
    1592                 :             :                       g_assert (g_variant_serialised_check (child));
    1593                 :             :                       return child;
    1594                 :             : 
    1595                 :             :                      )
    1596                 :             :       g_assert_not_reached ();
    1597                 :             :     }
    1598                 :             : 
    1599                 :           0 :   g_error ("Attempt to access item %"G_GSIZE_FORMAT
    1600                 :             :            " in a container with only %"G_GSIZE_FORMAT" items",
    1601                 :             :            index_, g_variant_serialised_n_children (serialised));
    1602                 :             : }
    1603                 :             : 
    1604                 :             : /* < private >
    1605                 :             :  * g_variant_serialiser_serialise:
    1606                 :             :  * @serialised: a #GVariantSerialised, properly set up
    1607                 :             :  * @gvs_filler: the filler function
    1608                 :             :  * @children: an array of child items
    1609                 :             :  * @n_children: the size of @children
    1610                 :             :  *
    1611                 :             :  * Writes data in serialized form.
    1612                 :             :  *
    1613                 :             :  * The type_info field of @serialised must be filled in to type info for
    1614                 :             :  * the type that we are serializing.
    1615                 :             :  *
    1616                 :             :  * The size field of @serialised must be filled in with the value
    1617                 :             :  * returned by a previous call to g_variant_serialiser_needed_size().
    1618                 :             :  *
    1619                 :             :  * The data field of @serialised must be a pointer to a properly-aligned
    1620                 :             :  * memory region large enough to serialize into (ie: at least as big as
    1621                 :             :  * the size field).
    1622                 :             :  *
    1623                 :             :  * This function is only responsible for serializing the top-level
    1624                 :             :  * container.  @gvs_filler is called on each child of the container in
    1625                 :             :  * order for all of the data of that child to be filled in.
    1626                 :             :  */
    1627                 :             : void
    1628                 :      230275 : g_variant_serialiser_serialise (GVariantSerialised        serialised,
    1629                 :             :                                 GVariantSerialisedFiller  gvs_filler,
    1630                 :             :                                 const gpointer           *children,
    1631                 :             :                                 gsize                     n_children)
    1632                 :             : {
    1633                 :      230275 :   g_assert (g_variant_serialised_check (serialised));
    1634                 :             : 
    1635                 :      230275 :   DISPATCH_CASES (serialised.type_info,
    1636                 :             : 
    1637                 :             :                   gvs_/**/,/**/_serialise (serialised, gvs_filler,
    1638                 :             :                                            children, n_children);
    1639                 :             :                   return;
    1640                 :             : 
    1641                 :             :                  )
    1642                 :             :   g_assert_not_reached ();
    1643                 :             : }
    1644                 :             : 
    1645                 :             : /* < private >
    1646                 :             :  * g_variant_serialiser_needed_size:
    1647                 :             :  * @type_info: the type to serialize for
    1648                 :             :  * @gvs_filler: the filler function
    1649                 :             :  * @children: an array of child items
    1650                 :             :  * @n_children: the size of @children
    1651                 :             :  *
    1652                 :             :  * Determines how much memory would be needed to serialize this value.
    1653                 :             :  *
    1654                 :             :  * This function is only responsible for performing calculations for the
    1655                 :             :  * top-level container.  @gvs_filler is called on each child of the
    1656                 :             :  * container in order to determine its size.
    1657                 :             :  */
    1658                 :             : gsize
    1659                 :      565545 : g_variant_serialiser_needed_size (GVariantTypeInfo         *type_info,
    1660                 :             :                                   GVariantSerialisedFiller  gvs_filler,
    1661                 :             :                                   const gpointer           *children,
    1662                 :             :                                   gsize                     n_children)
    1663                 :             : {
    1664                 :      565545 :   DISPATCH_CASES (type_info,
    1665                 :             : 
    1666                 :             :                   return gvs_/**/,/**/_needed_size (type_info, gvs_filler,
    1667                 :             :                                                     children, n_children);
    1668                 :             : 
    1669                 :             :                  )
    1670                 :             :   g_assert_not_reached ();
    1671                 :             : }
    1672                 :             : 
    1673                 :             : /* Byteswapping {{{2 */
    1674                 :             : 
    1675                 :             : /* < private >
    1676                 :             :  * g_variant_serialised_byteswap:
    1677                 :             :  * @value: a #GVariantSerialised
    1678                 :             :  *
    1679                 :             :  * Byte-swap serialized data.  The result of this function is only
    1680                 :             :  * well-defined if the data is in normal form.
    1681                 :             :  */
    1682                 :             : void
    1683                 :      345862 : g_variant_serialised_byteswap (GVariantSerialised serialised)
    1684                 :             : {
    1685                 :             :   gsize fixed_size;
    1686                 :             :   guint alignment;
    1687                 :             : 
    1688                 :      345862 :   g_assert (g_variant_serialised_check (serialised));
    1689                 :             : 
    1690                 :      345862 :   if (!serialised.data)
    1691                 :      320274 :     return;
    1692                 :             : 
    1693                 :             :   /* the types we potentially need to byteswap are
    1694                 :             :    * exactly those with alignment requirements.
    1695                 :             :    */
    1696                 :      345387 :   g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
    1697                 :      345387 :   if (!alignment)
    1698                 :       10682 :     return;
    1699                 :             : 
    1700                 :             :   /* if fixed size and alignment are equal then we are down
    1701                 :             :    * to the base integer type and we should swap it.  the
    1702                 :             :    * only exception to this is if we have a tuple with a
    1703                 :             :    * single item, and then swapping it will be OK anyway.
    1704                 :             :    */
    1705                 :      334705 :   if (alignment + 1 == fixed_size)
    1706                 :             :     {
    1707                 :      309117 :       switch (fixed_size)
    1708                 :             :       {
    1709                 :       13193 :         case 2:
    1710                 :             :           {
    1711                 :       13193 :             guint16 *ptr = (guint16 *) serialised.data;
    1712                 :             : 
    1713                 :       13193 :             g_assert_cmpint (serialised.size, ==, 2);
    1714                 :       13193 :             *ptr = GUINT16_SWAP_LE_BE (*ptr);
    1715                 :             :           }
    1716                 :       13193 :           return;
    1717                 :             : 
    1718                 :      286617 :         case 4:
    1719                 :             :           {
    1720                 :      286617 :             guint32 *ptr = (guint32 *) serialised.data;
    1721                 :             : 
    1722                 :      286617 :             g_assert_cmpint (serialised.size, ==, 4);
    1723                 :      286617 :             *ptr = GUINT32_SWAP_LE_BE (*ptr);
    1724                 :             :           }
    1725                 :      286617 :           return;
    1726                 :             : 
    1727                 :        9307 :         case 8:
    1728                 :             :           {
    1729                 :        9307 :             guint64 *ptr = (guint64 *) serialised.data;
    1730                 :             : 
    1731                 :        9307 :             g_assert_cmpint (serialised.size, ==, 8);
    1732                 :        9307 :             *ptr = GUINT64_SWAP_LE_BE (*ptr);
    1733                 :             :           }
    1734                 :        9307 :           return;
    1735                 :             : 
    1736                 :           0 :         default:
    1737                 :             :           g_assert_not_reached ();
    1738                 :             :       }
    1739                 :             :     }
    1740                 :             : 
    1741                 :             :   /* else, we have a container that potentially contains
    1742                 :             :    * some children that need to be byteswapped.
    1743                 :             :    */
    1744                 :             :   else
    1745                 :             :     {
    1746                 :             :       gsize children, i;
    1747                 :             : 
    1748                 :       25588 :       children = g_variant_serialised_n_children (serialised);
    1749                 :      371284 :       for (i = 0; i < children; i++)
    1750                 :             :         {
    1751                 :             :           GVariantSerialised child;
    1752                 :             : 
    1753                 :      345696 :           child = g_variant_serialised_get_child (serialised, i);
    1754                 :      345696 :           g_variant_serialised_byteswap (child);
    1755                 :      345696 :           g_variant_type_info_unref (child.type_info);
    1756                 :             :         }
    1757                 :             :     }
    1758                 :             : }
    1759                 :             : 
    1760                 :             : /* Normal form checking {{{2 */
    1761                 :             : 
    1762                 :             : /* < private >
    1763                 :             :  * g_variant_serialised_is_normal:
    1764                 :             :  * @serialised: a #GVariantSerialised
    1765                 :             :  *
    1766                 :             :  * Determines, recursively if @serialised is in normal form.  There is
    1767                 :             :  * precisely one normal form of serialized data for each possible value.
    1768                 :             :  *
    1769                 :             :  * It is possible that multiple byte sequences form the serialized data
    1770                 :             :  * for a given value if, for example, the padding bytes are filled in
    1771                 :             :  * with something other than zeros, but only one form is the normal
    1772                 :             :  * form.
    1773                 :             :  */
    1774                 :             : gboolean
    1775                 :     2642874 : g_variant_serialised_is_normal (GVariantSerialised serialised)
    1776                 :             : {
    1777                 :     2642874 :   if (serialised.depth >= G_VARIANT_MAX_RECURSION_DEPTH)
    1778                 :           0 :     return FALSE;
    1779                 :             : 
    1780                 :     2642874 :   DISPATCH_CASES (serialised.type_info,
    1781                 :             : 
    1782                 :             :                   return gvs_/**/,/**/_is_normal (serialised);
    1783                 :             : 
    1784                 :             :                  )
    1785                 :             : 
    1786                 :     2512881 :   if (serialised.data == NULL)
    1787                 :          82 :     return FALSE;
    1788                 :             : 
    1789                 :             :   /* some hard-coded terminal cases */
    1790                 :     2512799 :   switch (g_variant_type_info_get_type_char (serialised.type_info))
    1791                 :             :     {
    1792                 :       48951 :     case 'b': /* boolean */
    1793                 :       48951 :       return serialised.data[0] < 2;
    1794                 :             : 
    1795                 :      160244 :     case 's': /* string */
    1796                 :      160244 :       return g_variant_serialiser_is_string (serialised.data,
    1797                 :             :                                              serialised.size);
    1798                 :             : 
    1799                 :       47669 :     case 'o':
    1800                 :       47669 :       return g_variant_serialiser_is_object_path (serialised.data,
    1801                 :             :                                                   serialised.size);
    1802                 :             : 
    1803                 :      507824 :     case 'g':
    1804                 :      507824 :       return g_variant_serialiser_is_signature (serialised.data,
    1805                 :             :                                                 serialised.size);
    1806                 :             : 
    1807                 :     1748111 :     default:
    1808                 :             :       /* all of the other types are fixed-sized numerical types for
    1809                 :             :        * which all possible values are valid (including various NaN
    1810                 :             :        * representations for floating point values).
    1811                 :             :        */
    1812                 :     1748111 :       return TRUE;
    1813                 :             :     }
    1814                 :             : }
    1815                 :             : 
    1816                 :             : /* Validity-checking functions {{{2
    1817                 :             :  *
    1818                 :             :  * Checks if strings, object paths and signature strings are valid.
    1819                 :             :  */
    1820                 :             : 
    1821                 :             : /* < private >
    1822                 :             :  * g_variant_serialiser_is_string:
    1823                 :             :  * @data: a possible string
    1824                 :             :  * @size: the size of @data
    1825                 :             :  *
    1826                 :             :  * Ensures that @data is a valid string with a nul terminator at the end
    1827                 :             :  * and no nul bytes embedded.
    1828                 :             :  */
    1829                 :             : gboolean
    1830                 :     1503662 : g_variant_serialiser_is_string (gconstpointer data,
    1831                 :             :                                 gsize         size)
    1832                 :             : {
    1833                 :             :   const gchar *expected_end;
    1834                 :             :   const gchar *end;
    1835                 :             : 
    1836                 :             :   /* Strings must end with a nul terminator. */
    1837                 :     1503662 :   if (size == 0)
    1838                 :      100214 :     return FALSE;
    1839                 :             : 
    1840                 :     1403448 :   expected_end = ((gchar *) data) + size - 1;
    1841                 :             : 
    1842                 :     1403448 :   if (*expected_end != '\0')
    1843                 :          40 :     return FALSE;
    1844                 :             : 
    1845                 :     1403408 :   g_utf8_validate_len (data, size, &end);
    1846                 :             : 
    1847                 :     1403408 :   return end == expected_end;
    1848                 :             : }
    1849                 :             : 
    1850                 :             : /* < private >
    1851                 :             :  * g_variant_serialiser_is_object_path:
    1852                 :             :  * @data: a possible D-Bus object path
    1853                 :             :  * @size: the size of @data
    1854                 :             :  *
    1855                 :             :  * Performs the checks for being a valid string.
    1856                 :             :  *
    1857                 :             :  * Also, ensures that @data is a valid D-Bus object path, as per the D-Bus
    1858                 :             :  * specification.
    1859                 :             :  */
    1860                 :             : gboolean
    1861                 :      488771 : g_variant_serialiser_is_object_path (gconstpointer data,
    1862                 :             :                                      gsize         size)
    1863                 :             : {
    1864                 :      488771 :   const gchar *string = data;
    1865                 :             :   gsize i;
    1866                 :             : 
    1867                 :      488771 :   if (!g_variant_serialiser_is_string (data, size))
    1868                 :       62747 :     return FALSE;
    1869                 :             : 
    1870                 :             :   /* The path must begin with an ASCII '/' (integer 47) character */
    1871                 :      426024 :   if (string[0] != '/')
    1872                 :          18 :     return FALSE;
    1873                 :             : 
    1874                 :    16220873 :   for (i = 1; string[i]; i++)
    1875                 :             :     /* Each element must only contain the ASCII characters
    1876                 :             :      * "[A-Z][a-z][0-9]_"
    1877                 :             :      */
    1878                 :    15794878 :     if (g_ascii_isalnum (string[i]) || string[i] == '_')
    1879                 :             :       ;
    1880                 :             : 
    1881                 :             :     /* must consist of elements separated by slash characters. */
    1882                 :      203738 :     else if (string[i] == '/')
    1883                 :             :       {
    1884                 :             :         /* No element may be the empty string. */
    1885                 :             :         /* Multiple '/' characters cannot occur in sequence. */
    1886                 :      203729 :         if (string[i - 1] == '/')
    1887                 :           2 :           return FALSE;
    1888                 :             :       }
    1889                 :             : 
    1890                 :             :     else
    1891                 :           9 :       return FALSE;
    1892                 :             : 
    1893                 :             :   /* A trailing '/' character is not allowed unless the path is the
    1894                 :             :    * root path (a single '/' character).
    1895                 :             :    */
    1896                 :      425995 :   if (i > 1 && string[i - 1] == '/')
    1897                 :           1 :     return FALSE;
    1898                 :             : 
    1899                 :      425994 :   return TRUE;
    1900                 :             : }
    1901                 :             : 
    1902                 :             : /* < private >
    1903                 :             :  * g_variant_serialiser_is_signature:
    1904                 :             :  * @data: a possible D-Bus signature
    1905                 :             :  * @size: the size of @data
    1906                 :             :  *
    1907                 :             :  * Performs the checks for being a valid string.
    1908                 :             :  *
    1909                 :             :  * Also, ensures that @data is a valid D-Bus type signature, as per the
    1910                 :             :  * D-Bus specification. Note that this means the empty string is valid, as the
    1911                 :             :  * D-Bus specification defines a signature as “zero or more single complete
    1912                 :             :  * types”.
    1913                 :             :  */
    1914                 :             : gboolean
    1915                 :      810729 : g_variant_serialiser_is_signature (gconstpointer data,
    1916                 :             :                                    gsize         size)
    1917                 :             : {
    1918                 :      810729 :   const gchar *string = data;
    1919                 :             :   gsize first_invalid;
    1920                 :             : 
    1921                 :      810729 :   if (!g_variant_serialiser_is_string (data, size))
    1922                 :        7307 :     return FALSE;
    1923                 :             : 
    1924                 :             :   /* make sure no non-definite characters appear */
    1925                 :      803422 :   first_invalid = strspn (string, "ybnqiuxthdvasog(){}");
    1926                 :      803422 :   if (string[first_invalid])
    1927                 :          28 :     return FALSE;
    1928                 :             : 
    1929                 :             :   /* make sure each type string is well-formed */
    1930                 :    56576006 :   while (*string)
    1931                 :    55772616 :     if (!g_variant_type_string_scan (string, NULL, &string))
    1932                 :           4 :       return FALSE;
    1933                 :             : 
    1934                 :      803390 :   return TRUE;
    1935                 :             : }
    1936                 :             : 
    1937                 :             : /* Epilogue {{{1 */
    1938                 :             : /* vim:set foldmethod=marker: */
        

Generated by: LCOV version 2.0-1