Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/toolkit/system/gnome/nsGSettingsService.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "mozilla/ArrayUtils.h"
7
8
#include "nsGSettingsService.h"
9
#include "nsString.h"
10
#include "nsCOMPtr.h"
11
#include "nsMemory.h"
12
#include "prlink.h"
13
#include "nsComponentManagerUtils.h"
14
#include "nsIMutableArray.h"
15
#include "nsISupportsPrimitives.h"
16
17
#include <glib.h>
18
#include <glib-object.h>
19
20
using namespace mozilla;
21
22
typedef struct _GSettings GSettings;
23
typedef struct _GVariantType GVariantType;
24
typedef struct _GVariant GVariant;
25
26
#ifndef G_VARIANT_TYPE_INT32
27
# define G_VARIANT_TYPE_INT32        ((const GVariantType *) "i")
28
# define G_VARIANT_TYPE_BOOLEAN      ((const GVariantType *) "b")
29
# define G_VARIANT_TYPE_STRING       ((const GVariantType *) "s")
30
# define G_VARIANT_TYPE_OBJECT_PATH  ((const GVariantType *) "o")
31
# define G_VARIANT_TYPE_SIGNATURE    ((const GVariantType *) "g")
32
#endif
33
#ifndef G_VARIANT_TYPE_STRING_ARRAY
34
# define G_VARIANT_TYPE_STRING_ARRAY ((const GVariantType *) "as")
35
#endif
36
37
#define GSETTINGS_FUNCTIONS \
38
0
  FUNC(g_settings_new, GSettings *, (const char* schema)) \
39
0
  FUNC(g_settings_list_schemas, const char * const *, (void)) \
40
0
  FUNC(g_settings_list_keys, char **, (GSettings* settings)) \
41
0
  FUNC(g_settings_get_value, GVariant *, (GSettings* settings, const char* key)) \
42
0
  FUNC(g_settings_set_value, gboolean, (GSettings* settings, const char* key, GVariant* value)) \
43
0
  FUNC(g_settings_range_check, gboolean, (GSettings* settings, const char* key, GVariant* value)) \
44
0
  FUNC(g_variant_get_int32, gint32, (GVariant* variant)) \
45
0
  FUNC(g_variant_get_boolean, gboolean, (GVariant* variant)) \
46
0
  FUNC(g_variant_get_string, const char *, (GVariant* value, gsize* length)) \
47
0
  FUNC(g_variant_get_strv, const char **, (GVariant* value, gsize* length)) \
48
0
  FUNC(g_variant_is_of_type, gboolean, (GVariant* value, const GVariantType* type)) \
49
0
  FUNC(g_variant_new_int32, GVariant *, (gint32 value)) \
50
0
  FUNC(g_variant_new_boolean, GVariant *, (gboolean value)) \
51
0
  FUNC(g_variant_new_string, GVariant *, (const char* string)) \
52
0
  FUNC(g_variant_unref, void, (GVariant* value))
53
54
#define FUNC(name, type, params) \
55
  typedef type (*_##name##_fn) params; \
56
  static _##name##_fn _##name;
57
58
GSETTINGS_FUNCTIONS
59
60
#undef FUNC
61
62
0
#define g_settings_new _g_settings_new
63
0
#define g_settings_list_schemas _g_settings_list_schemas
64
0
#define g_settings_list_keys _g_settings_list_keys
65
0
#define g_settings_get_value _g_settings_get_value
66
0
#define g_settings_set_value _g_settings_set_value
67
0
#define g_settings_range_check _g_settings_range_check
68
0
#define g_variant_get_int32 _g_variant_get_int32
69
0
#define g_variant_get_boolean _g_variant_get_boolean
70
0
#define g_variant_get_string _g_variant_get_string
71
0
#define g_variant_get_strv _g_variant_get_strv
72
0
#define g_variant_is_of_type _g_variant_is_of_type
73
0
#define g_variant_new_int32 _g_variant_new_int32
74
0
#define g_variant_new_boolean _g_variant_new_boolean
75
0
#define g_variant_new_string _g_variant_new_string
76
0
#define g_variant_unref _g_variant_unref
77
78
static PRLibrary *gioLib = nullptr;
79
80
class nsGSettingsCollection final : public nsIGSettingsCollection
81
{
82
public:
83
  NS_DECL_ISUPPORTS
84
  NS_DECL_NSIGSETTINGSCOLLECTION
85
86
  explicit nsGSettingsCollection(GSettings* aSettings) : mSettings(aSettings),
87
0
                                                         mKeys(nullptr) {}
88
private:
89
  ~nsGSettingsCollection();
90
91
  bool KeyExists(const nsACString& aKey);
92
  bool SetValue(const nsACString& aKey,
93
                  GVariant *aValue);
94
95
  GSettings *mSettings;
96
  char **mKeys;
97
};
98
99
nsGSettingsCollection::~nsGSettingsCollection()
100
0
{
101
0
  g_strfreev(mKeys);
102
0
  g_object_unref(mSettings);
103
0
}
104
105
bool
106
nsGSettingsCollection::KeyExists(const nsACString& aKey)
107
0
{
108
0
  if (!mKeys)
109
0
    mKeys = g_settings_list_keys(mSettings);
110
0
111
0
  for (uint32_t i = 0; mKeys[i] != nullptr; i++) {
112
0
    if (aKey.Equals(mKeys[i]))
113
0
      return true;
114
0
  }
115
0
116
0
  return false;
117
0
}
118
119
bool
120
nsGSettingsCollection::SetValue(const nsACString& aKey,
121
                                GVariant *aValue)
122
0
{
123
0
  if (!KeyExists(aKey) ||
124
0
      !g_settings_range_check(mSettings,
125
0
                              PromiseFlatCString(aKey).get(),
126
0
                              aValue)) {
127
0
    g_variant_unref(aValue);
128
0
    return false;
129
0
  }
130
0
131
0
  return g_settings_set_value(mSettings,
132
0
                              PromiseFlatCString(aKey).get(),
133
0
                              aValue);
134
0
}
135
136
NS_IMPL_ISUPPORTS(nsGSettingsCollection, nsIGSettingsCollection)
137
138
NS_IMETHODIMP
139
nsGSettingsCollection::SetString(const nsACString& aKey,
140
                                 const nsACString& aValue)
141
0
{
142
0
  GVariant *value = g_variant_new_string(PromiseFlatCString(aValue).get());
143
0
  if (!value)
144
0
    return NS_ERROR_OUT_OF_MEMORY;
145
0
146
0
  bool res = SetValue(aKey, value);
147
0
148
0
  return res ? NS_OK : NS_ERROR_FAILURE;
149
0
}
150
151
NS_IMETHODIMP
152
nsGSettingsCollection::SetBoolean(const nsACString& aKey,
153
                                  bool aValue)
154
0
{
155
0
  GVariant *value = g_variant_new_boolean(aValue);
156
0
  if (!value)
157
0
    return NS_ERROR_OUT_OF_MEMORY;
158
0
159
0
  bool res = SetValue(aKey, value);
160
0
161
0
  return res ? NS_OK : NS_ERROR_FAILURE;
162
0
}
163
164
NS_IMETHODIMP
165
nsGSettingsCollection::SetInt(const nsACString& aKey,
166
                              int32_t aValue)
167
0
{
168
0
  GVariant *value = g_variant_new_int32(aValue);
169
0
  if (!value)
170
0
    return NS_ERROR_OUT_OF_MEMORY;
171
0
172
0
  bool res = SetValue(aKey, value);
173
0
174
0
  return res ? NS_OK : NS_ERROR_FAILURE;
175
0
}
176
177
NS_IMETHODIMP
178
nsGSettingsCollection::GetString(const nsACString& aKey,
179
                                 nsACString& aResult)
180
0
{
181
0
  if (!KeyExists(aKey))
182
0
    return NS_ERROR_INVALID_ARG;
183
0
184
0
  GVariant *value = g_settings_get_value(mSettings,
185
0
                                         PromiseFlatCString(aKey).get());
186
0
  if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) &&
187
0
      !g_variant_is_of_type(value, G_VARIANT_TYPE_OBJECT_PATH) &&
188
0
      !g_variant_is_of_type(value, G_VARIANT_TYPE_SIGNATURE)) {
189
0
    g_variant_unref(value);
190
0
    return NS_ERROR_FAILURE;
191
0
  }
192
0
193
0
  aResult.Assign(g_variant_get_string(value, nullptr));
194
0
  g_variant_unref(value);
195
0
196
0
  return NS_OK;
197
0
}
198
199
NS_IMETHODIMP
200
nsGSettingsCollection::GetBoolean(const nsACString& aKey,
201
                                  bool* aResult)
202
0
{
203
0
  NS_ENSURE_ARG_POINTER(aResult);
204
0
205
0
  if (!KeyExists(aKey))
206
0
    return NS_ERROR_INVALID_ARG;
207
0
208
0
  GVariant *value = g_settings_get_value(mSettings,
209
0
                                         PromiseFlatCString(aKey).get());
210
0
  if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
211
0
    g_variant_unref(value);
212
0
    return NS_ERROR_FAILURE;
213
0
  }
214
0
215
0
  gboolean res = g_variant_get_boolean(value);
216
0
  *aResult = res ? true : false;
217
0
  g_variant_unref(value);
218
0
219
0
  return NS_OK;
220
0
}
221
222
NS_IMETHODIMP
223
nsGSettingsCollection::GetInt(const nsACString& aKey,
224
                              int32_t* aResult)
225
0
{
226
0
  NS_ENSURE_ARG_POINTER(aResult);
227
0
228
0
  if (!KeyExists(aKey))
229
0
    return NS_ERROR_INVALID_ARG;
230
0
231
0
  GVariant *value = g_settings_get_value(mSettings,
232
0
                                         PromiseFlatCString(aKey).get());
233
0
  if (!g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) {
234
0
    g_variant_unref(value);
235
0
    return NS_ERROR_FAILURE;
236
0
  }
237
0
238
0
  *aResult = g_variant_get_int32(value);
239
0
  g_variant_unref(value);
240
0
241
0
  return NS_OK;
242
0
}
243
244
// These types are local to nsGSettingsService::Init, but ISO C++98 doesn't
245
// allow a template (ArrayLength) to be instantiated based on a local type.
246
// Boo-urns!
247
typedef void (*nsGSettingsFunc)();
248
struct nsGSettingsDynamicFunction {
249
  const char *functionName;
250
  nsGSettingsFunc *function;
251
};
252
253
NS_IMETHODIMP
254
nsGSettingsCollection::GetStringList(const nsACString& aKey, nsIArray** aResult)
255
0
{
256
0
  if (!KeyExists(aKey))
257
0
    return NS_ERROR_INVALID_ARG;
258
0
259
0
  nsCOMPtr<nsIMutableArray> items(do_CreateInstance(NS_ARRAY_CONTRACTID));
260
0
  if (!items) {
261
0
    return NS_ERROR_OUT_OF_MEMORY;
262
0
  }
263
0
264
0
  GVariant *value = g_settings_get_value(mSettings,
265
0
                                         PromiseFlatCString(aKey).get());
266
0
267
0
  if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY)) {
268
0
    g_variant_unref(value);
269
0
    return NS_ERROR_FAILURE;
270
0
  }
271
0
272
0
  const gchar ** gs_strings = g_variant_get_strv(value, nullptr);
273
0
  if (!gs_strings) {
274
0
    // empty array
275
0
    items.forget(aResult);
276
0
    g_variant_unref(value);
277
0
    return NS_OK;
278
0
  }
279
0
280
0
  const gchar** p_gs_strings = gs_strings;
281
0
  while (*p_gs_strings != nullptr)
282
0
  {
283
0
    nsCOMPtr<nsISupportsCString> obj(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
284
0
    if (obj) {
285
0
      obj->SetData(nsDependentCString(*p_gs_strings));
286
0
      items->AppendElement(obj);
287
0
    }
288
0
    p_gs_strings++;
289
0
  }
290
0
  g_free(gs_strings);
291
0
  items.forget(aResult);
292
0
  g_variant_unref(value);
293
0
  return NS_OK;
294
0
}
295
296
nsresult
297
nsGSettingsService::Init()
298
0
{
299
0
#define FUNC(name, type, params) { #name, (nsGSettingsFunc *)&_##name },
300
0
  static const nsGSettingsDynamicFunction kGSettingsSymbols[] = {
301
0
    GSETTINGS_FUNCTIONS
302
0
  };
303
0
#undef FUNC
304
0
305
0
  if (!gioLib) {
306
0
    gioLib = PR_LoadLibrary("libgio-2.0.so.0");
307
0
    if (!gioLib)
308
0
      return NS_ERROR_FAILURE;
309
0
  }
310
0
311
0
  for (auto GSettingsSymbol : kGSettingsSymbols) {
312
0
    *GSettingsSymbol.function =
313
0
      PR_FindFunctionSymbol(gioLib, GSettingsSymbol.functionName);
314
0
    if (!*GSettingsSymbol.function) {
315
0
      return NS_ERROR_FAILURE;
316
0
    }
317
0
  }
318
0
319
0
  return NS_OK;
320
0
}
321
322
NS_IMPL_ISUPPORTS(nsGSettingsService, nsIGSettingsService)
323
324
nsGSettingsService::~nsGSettingsService()
325
0
{
326
0
  if (gioLib) {
327
0
    PR_UnloadLibrary(gioLib);
328
0
    gioLib = nullptr;
329
0
  }
330
0
}
331
332
NS_IMETHODIMP
333
nsGSettingsService::GetCollectionForSchema(const nsACString& schema,
334
                                           nsIGSettingsCollection** collection)
335
0
{
336
0
  NS_ENSURE_ARG_POINTER(collection);
337
0
338
0
  const char * const *schemas = g_settings_list_schemas();
339
0
340
0
  for (uint32_t i = 0; schemas[i] != nullptr; i++) {
341
0
    if (schema.Equals(schemas[i])) {
342
0
      GSettings *settings = g_settings_new(PromiseFlatCString(schema).get());
343
0
      nsGSettingsCollection *mozGSettings = new nsGSettingsCollection(settings);
344
0
      NS_ADDREF(*collection = mozGSettings);
345
0
      return NS_OK;
346
0
    }
347
0
  }
348
0
349
0
  return NS_ERROR_FAILURE;
350
0
}