summaryrefslogtreecommitdiff
path: root/src/libotutil/ot-variant-utils.c
blob: f6a4e43cd02d9b7c7d8d235e7ca71c5db48cd939 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
 * Copyright (C) 2011 Colin Walters <walters@verbum.org>
 *
 * SPDX-License-Identifier: LGPL-2.0+
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <https://www.gnu.org/licenses/>.
 *
 * Author: Colin Walters <walters@verbum.org>
 */

#include "config.h"

#include <gio/gio.h>
#include <gio/gfiledescriptorbased.h>

#include <string.h>

#include "otutil.h"

/* Create a new GVariant empty GVariant of type a{sv} */
GVariant *
ot_gvariant_new_empty_string_dict (void)
{
  g_auto(GVariantBuilder) builder = OT_VARIANT_BUILDER_INITIALIZER;
  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
  return g_variant_builder_end (&builder);
}


/* Create a new GVariant of type ay from the raw @data pointer */
GVariant *
ot_gvariant_new_bytearray (const guchar   *data,
                           gsize           len)
{
  gpointer data_copy = g_memdup (data, len);
  GVariant *ret = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data_copy,
                                 len, FALSE, g_free, data_copy);
  return ret;
}

/* Convert a GBytes into a GVariant of type ay (byte array) */
GVariant *
ot_gvariant_new_ay_bytes (GBytes *bytes)
{
  gsize size;
  gconstpointer data = g_bytes_get_data (bytes, &size);
  g_bytes_ref (bytes);
  return g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, size,
                                  TRUE, (GDestroyNotify)g_bytes_unref, bytes);
}

/* Create a GVariant in @out_variant that is backed by
 * the data from @fd, starting at @start.  If the data is
 * large enough, mmap() may be used.  @trusted is used
 * by the GVariant core; see g_variant_new_from_data().
 */
gboolean
ot_variant_read_fd (int                    fd,
                    goffset                start,
                    const GVariantType    *type,
                    gboolean               trusted,
                    GVariant             **out_variant,
                    GError               **error)
{
  g_autoptr(GBytes) bytes = ot_fd_readall_or_mmap (fd, start, error);
  if (!bytes)
    return FALSE;

  *out_variant = g_variant_ref_sink (g_variant_new_from_bytes (type, bytes, trusted));
  return TRUE;
}

/* GVariants are immutable; this function allows generating an open builder
 * for a new variant, inherting the data from @variant.
 */
GVariantBuilder *
ot_util_variant_builder_from_variant (GVariant            *variant,
                                      const GVariantType  *type)
{
  GVariantBuilder *builder = g_variant_builder_new (type);

  if (variant != NULL)
    {
      const int n = g_variant_n_children (variant);
      for (int i = 0; i < n; i++)
        {
          g_autoptr(GVariant) child = g_variant_get_child_value (variant, i);
          g_variant_builder_add_value (builder, child);
        }
    }

  return builder;
}

/**
 * ot_variant_bsearch_str:
 * @array: A GVariant array whose first element must be a string
 * @str: Search for this string
 * @out_pos: Output position
 *
 *
 * Binary search in a GVariant array, which must be of the form 'a(s...)',
 * where '...' may be anything.  The array elements must be sorted.
 *
 * Returns: %TRUE if found, %FALSE otherwise
 */
gboolean
ot_variant_bsearch_str (GVariant   *array,
                        const char *str,
                        int        *out_pos)
{
  const gsize n = g_variant_n_children (array);
  if (n == 0)
    return FALSE;

  gsize imax = n - 1;
  gsize imin = 0;
  gsize imid = -1;
  while (imax >= imin)
    {
      const char *cur;

      imid = (imin + imax) / 2;

      g_autoptr(GVariant) child = g_variant_get_child_value (array, imid);
      g_variant_get_child (child, 0, "&s", &cur, NULL);

      int cmp = strcmp (cur, str);
      if (cmp < 0)
        imin = imid + 1;
      else if (cmp > 0)
        {
          if (imid == 0)
            break;
          imax = imid - 1;
        }
      else
        {
          *out_pos = imid;
          return TRUE;
        }
    }

  *out_pos = imid;
  return FALSE;
}