/src/tinysparql/subprojects/json-glib-1.10.6/json-glib/json-generator.c
Line | Count | Source |
1 | | /* json-generator.c - JSON streams generator |
2 | | * |
3 | | * This file is part of JSON-GLib |
4 | | * |
5 | | * SPDX-FileCopyrightText: 2007 OpenedHand Ltd. |
6 | | * SPDX-FileCopyrightText: 2009 Intel Corp. |
7 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
8 | | * |
9 | | * This library is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public |
11 | | * License as published by the Free Software Foundation; either |
12 | | * version 2.1 of the License, or (at your option) any later version. |
13 | | * |
14 | | * This library is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | | * Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public |
20 | | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
21 | | * |
22 | | * Author: |
23 | | * Emmanuele Bassi <ebassi@linux.intel.com> |
24 | | */ |
25 | | |
26 | | /** |
27 | | * JsonGenerator: |
28 | | * |
29 | | * `JsonGenerator` provides an object for generating a JSON data stream |
30 | | * from a tree of [struct@Json.Node] instances, and put it into a buffer |
31 | | * or a file. |
32 | | */ |
33 | | |
34 | | #include "config.h" |
35 | | |
36 | | #include <stdlib.h> |
37 | | #include <string.h> |
38 | | |
39 | | #include "json-types-private.h" |
40 | | |
41 | | #include "json-generator.h" |
42 | | |
43 | | struct _JsonGeneratorPrivate |
44 | | { |
45 | | JsonNode *root; |
46 | | |
47 | | guint indent; |
48 | | gunichar indent_char; |
49 | | |
50 | | guint pretty : 1; |
51 | | }; |
52 | | |
53 | | enum |
54 | | { |
55 | | PROP_0, |
56 | | |
57 | | PROP_PRETTY, |
58 | | PROP_INDENT, |
59 | | PROP_ROOT, |
60 | | PROP_INDENT_CHAR, |
61 | | |
62 | | PROP_LAST |
63 | | }; |
64 | | |
65 | | static void dump_value (GString *buffer, |
66 | | JsonNode *node); |
67 | | static void dump_array (JsonGenerator *generator, |
68 | | GString *buffer, |
69 | | gint level, |
70 | | JsonArray *array); |
71 | | static void dump_object (JsonGenerator *generator, |
72 | | GString *buffer, |
73 | | gint level, |
74 | | JsonObject *object); |
75 | | |
76 | | static GParamSpec *generator_props[PROP_LAST] = { NULL, }; |
77 | | |
78 | 0 | G_DEFINE_TYPE_WITH_PRIVATE (JsonGenerator, json_generator, G_TYPE_OBJECT) |
79 | 0 |
|
80 | 0 | static void |
81 | 0 | json_strescape (GString *output, |
82 | 0 | const gchar *str) |
83 | 0 | { |
84 | 0 | const gchar *p; |
85 | 0 | const gchar *end; |
86 | 0 | gsize len; |
87 | |
|
88 | 0 | len = strlen (str); |
89 | 0 | end = str + len; |
90 | |
|
91 | 0 | for (p = str; p < end; p++) |
92 | 0 | { |
93 | 0 | if (*p == '\\' || *p == '"') |
94 | 0 | { |
95 | 0 | g_string_append_c (output, '\\'); |
96 | 0 | g_string_append_c (output, *p); |
97 | 0 | } |
98 | 0 | else if ((*p > 0 && *p < 0x1f) || *p == 0x7f) |
99 | 0 | { |
100 | 0 | switch (*p) |
101 | 0 | { |
102 | 0 | case '\b': |
103 | 0 | g_string_append (output, "\\b"); |
104 | 0 | break; |
105 | 0 | case '\f': |
106 | 0 | g_string_append (output, "\\f"); |
107 | 0 | break; |
108 | 0 | case '\n': |
109 | 0 | g_string_append (output, "\\n"); |
110 | 0 | break; |
111 | 0 | case '\r': |
112 | 0 | g_string_append (output, "\\r"); |
113 | 0 | break; |
114 | 0 | case '\t': |
115 | 0 | g_string_append (output, "\\t"); |
116 | 0 | break; |
117 | 0 | default: |
118 | 0 | g_string_append_printf (output, "\\u00%02x", (guint)*p); |
119 | 0 | break; |
120 | 0 | } |
121 | 0 | } |
122 | 0 | else |
123 | 0 | { |
124 | 0 | g_string_append_c (output, *p); |
125 | 0 | } |
126 | 0 | } |
127 | 0 | } |
128 | | |
129 | | static void |
130 | | json_generator_finalize (GObject *gobject) |
131 | 0 | { |
132 | 0 | JsonGeneratorPrivate *priv; |
133 | |
|
134 | 0 | priv = json_generator_get_instance_private ((JsonGenerator *) gobject); |
135 | 0 | if (priv->root != NULL) |
136 | 0 | json_node_unref (priv->root); |
137 | |
|
138 | 0 | G_OBJECT_CLASS (json_generator_parent_class)->finalize (gobject); |
139 | 0 | } |
140 | | |
141 | | static void |
142 | | json_generator_set_property (GObject *gobject, |
143 | | guint prop_id, |
144 | | const GValue *value, |
145 | | GParamSpec *pspec) |
146 | 0 | { |
147 | 0 | JsonGenerator *generator = JSON_GENERATOR (gobject); |
148 | |
|
149 | 0 | switch (prop_id) |
150 | 0 | { |
151 | 0 | case PROP_PRETTY: |
152 | 0 | json_generator_set_pretty (generator, g_value_get_boolean (value)); |
153 | 0 | break; |
154 | | |
155 | 0 | case PROP_INDENT: |
156 | 0 | json_generator_set_indent (generator, g_value_get_uint (value)); |
157 | 0 | break; |
158 | | |
159 | 0 | case PROP_INDENT_CHAR: |
160 | 0 | json_generator_set_indent_char (generator, g_value_get_uint (value)); |
161 | 0 | break; |
162 | | |
163 | 0 | case PROP_ROOT: |
164 | 0 | json_generator_set_root (generator, g_value_get_boxed (value)); |
165 | 0 | break; |
166 | | |
167 | 0 | default: |
168 | 0 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
169 | 0 | break; |
170 | 0 | } |
171 | 0 | } |
172 | | |
173 | | static void |
174 | | json_generator_get_property (GObject *gobject, |
175 | | guint prop_id, |
176 | | GValue *value, |
177 | | GParamSpec *pspec) |
178 | 0 | { |
179 | 0 | JsonGeneratorPrivate *priv = JSON_GENERATOR (gobject)->priv; |
180 | |
|
181 | 0 | switch (prop_id) |
182 | 0 | { |
183 | 0 | case PROP_PRETTY: |
184 | 0 | g_value_set_boolean (value, priv->pretty); |
185 | 0 | break; |
186 | 0 | case PROP_INDENT: |
187 | 0 | g_value_set_uint (value, priv->indent); |
188 | 0 | break; |
189 | 0 | case PROP_INDENT_CHAR: |
190 | 0 | g_value_set_uint (value, priv->indent_char); |
191 | 0 | break; |
192 | 0 | case PROP_ROOT: |
193 | 0 | g_value_set_boxed (value, priv->root); |
194 | 0 | break; |
195 | 0 | default: |
196 | 0 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
197 | 0 | break; |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | | static void |
202 | | json_generator_class_init (JsonGeneratorClass *klass) |
203 | 0 | { |
204 | 0 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
205 | | |
206 | | /** |
207 | | * JsonGenerator:pretty: (attributes org.gtk.Property.get=json_generator_get_pretty org.gtk.Property.set=json_generator_set_pretty) |
208 | | * |
209 | | * Whether the output should be "pretty-printed", with indentation and |
210 | | * newlines. |
211 | | * |
212 | | * The indentation level can be controlled by using the |
213 | | * [property@Json.Generator:indent] property. |
214 | | */ |
215 | 0 | generator_props[PROP_PRETTY] = |
216 | 0 | g_param_spec_boolean ("pretty", |
217 | 0 | "Pretty", |
218 | 0 | "Pretty-print the output", |
219 | 0 | FALSE, |
220 | 0 | G_PARAM_READWRITE); |
221 | | |
222 | | /** |
223 | | * JsonGenerator:indent: (attributes org.gtk.Property.get=json_generator_get_indent org.gtk.Property.set=json_generator_set_indent) |
224 | | * |
225 | | * Number of spaces to be used to indent when pretty printing. |
226 | | */ |
227 | 0 | generator_props[PROP_INDENT] = |
228 | 0 | g_param_spec_uint ("indent", |
229 | 0 | "Indent", |
230 | 0 | "Number of indentation spaces", |
231 | 0 | 0, G_MAXUINT, |
232 | 0 | 2, |
233 | 0 | G_PARAM_READWRITE); |
234 | | |
235 | | /** |
236 | | * JsonGenerator:root: (attributes org.gtk.Property.get=json_generator_get_root org.gtk.Property.set=json_generator_set_root) |
237 | | * |
238 | | * The root node to be used when constructing a JSON data |
239 | | * stream. |
240 | | * |
241 | | * Since: 0.4 |
242 | | */ |
243 | 0 | generator_props[PROP_ROOT] = |
244 | 0 | g_param_spec_boxed ("root", |
245 | 0 | "Root", |
246 | 0 | "Root of the JSON data tree", |
247 | 0 | JSON_TYPE_NODE, |
248 | 0 | G_PARAM_READWRITE); |
249 | | |
250 | | /** |
251 | | * JsonGenerator:indent-char: (attributes org.gtk.Property.get=json_generator_get_indent_char org.gtk.Property.set=json_generator_set_indent_char) |
252 | | * |
253 | | * The character that should be used when indenting in pretty print. |
254 | | * |
255 | | * Since: 0.6 |
256 | | */ |
257 | 0 | generator_props[PROP_INDENT_CHAR] = |
258 | 0 | g_param_spec_unichar ("indent-char", |
259 | 0 | "Indent Char", |
260 | 0 | "Character that should be used when indenting", |
261 | 0 | ' ', |
262 | 0 | G_PARAM_READWRITE); |
263 | |
|
264 | 0 | gobject_class->set_property = json_generator_set_property; |
265 | 0 | gobject_class->get_property = json_generator_get_property; |
266 | 0 | gobject_class->finalize = json_generator_finalize; |
267 | 0 | g_object_class_install_properties (gobject_class, PROP_LAST, generator_props); |
268 | 0 | } |
269 | | |
270 | | static void |
271 | | json_generator_init (JsonGenerator *generator) |
272 | 0 | { |
273 | 0 | JsonGeneratorPrivate *priv = json_generator_get_instance_private (generator); |
274 | |
|
275 | 0 | generator->priv = priv; |
276 | |
|
277 | 0 | priv->pretty = FALSE; |
278 | 0 | priv->indent = 2; |
279 | 0 | priv->indent_char = ' '; |
280 | 0 | } |
281 | | |
282 | | static void |
283 | | dump_node (JsonGenerator *generator, |
284 | | GString *buffer, |
285 | | gint level, |
286 | | const gchar *name, |
287 | | JsonNode *node) |
288 | 0 | { |
289 | 0 | JsonGeneratorPrivate *priv = generator->priv; |
290 | 0 | gboolean pretty = priv->pretty; |
291 | 0 | guint indent = priv->indent; |
292 | |
|
293 | 0 | if (pretty) |
294 | 0 | { |
295 | 0 | guint i; |
296 | |
|
297 | 0 | for (i = 0; i < (level * indent); i++) |
298 | 0 | g_string_append_c (buffer, priv->indent_char); |
299 | 0 | } |
300 | |
|
301 | 0 | if (name) |
302 | 0 | { |
303 | 0 | g_string_append_c (buffer, '"'); |
304 | 0 | json_strescape (buffer, name); |
305 | 0 | g_string_append_c (buffer, '"'); |
306 | |
|
307 | 0 | if (pretty) |
308 | 0 | g_string_append (buffer, " : "); |
309 | 0 | else |
310 | 0 | g_string_append_c (buffer, ':'); |
311 | 0 | } |
312 | |
|
313 | 0 | switch (JSON_NODE_TYPE (node)) |
314 | 0 | { |
315 | 0 | case JSON_NODE_NULL: |
316 | 0 | g_string_append (buffer, "null"); |
317 | 0 | break; |
318 | | |
319 | 0 | case JSON_NODE_VALUE: |
320 | 0 | dump_value (buffer, node); |
321 | 0 | break; |
322 | | |
323 | 0 | case JSON_NODE_ARRAY: |
324 | 0 | dump_array (generator, buffer, level, |
325 | 0 | json_node_get_array (node)); |
326 | 0 | break; |
327 | | |
328 | 0 | case JSON_NODE_OBJECT: |
329 | 0 | dump_object (generator, buffer, level, |
330 | 0 | json_node_get_object (node)); |
331 | 0 | break; |
332 | 0 | } |
333 | 0 | } |
334 | | |
335 | | static void |
336 | | dump_value (GString *buffer, |
337 | | JsonNode *node) |
338 | 0 | { |
339 | 0 | const JsonValue *value; |
340 | |
|
341 | 0 | value = node->data.value; |
342 | |
|
343 | 0 | switch (value->type) |
344 | 0 | { |
345 | 0 | case JSON_VALUE_INT: |
346 | 0 | g_string_append_printf (buffer, "%" G_GINT64_FORMAT, json_value_get_int (value)); |
347 | 0 | break; |
348 | | |
349 | 0 | case JSON_VALUE_STRING: |
350 | 0 | { |
351 | 0 | g_string_append_c (buffer, '"'); |
352 | 0 | json_strescape (buffer, json_value_get_string (value)); |
353 | 0 | g_string_append_c (buffer, '"'); |
354 | 0 | } |
355 | 0 | break; |
356 | | |
357 | 0 | case JSON_VALUE_DOUBLE: |
358 | 0 | { |
359 | 0 | gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; |
360 | |
|
361 | 0 | g_string_append (buffer, |
362 | 0 | g_ascii_dtostr (buf, sizeof (buf), |
363 | 0 | json_value_get_double (value))); |
364 | | /* ensure doubles don't become ints */ |
365 | | /* also make sure not to append .0 that results in invalid exponential notation |
366 | | * since the numbers should be decimal, a hex 'e' or "E" can not be mistaken |
367 | | */ |
368 | 0 | if (g_strstr_len (buf, G_ASCII_DTOSTR_BUF_SIZE, ".") == NULL && |
369 | 0 | g_strstr_len (buf, G_ASCII_DTOSTR_BUF_SIZE, "e") == NULL && |
370 | 0 | g_strstr_len (buf, G_ASCII_DTOSTR_BUF_SIZE, "E") == NULL) |
371 | 0 | { |
372 | 0 | g_string_append (buffer, ".0"); |
373 | 0 | } |
374 | 0 | } |
375 | 0 | break; |
376 | | |
377 | 0 | case JSON_VALUE_BOOLEAN: |
378 | 0 | g_string_append (buffer, json_value_get_boolean (value) ? "true" : "false"); |
379 | 0 | break; |
380 | | |
381 | 0 | case JSON_VALUE_NULL: |
382 | 0 | g_string_append (buffer, "null"); |
383 | 0 | break; |
384 | | |
385 | 0 | default: |
386 | 0 | break; |
387 | 0 | } |
388 | 0 | } |
389 | | |
390 | | static void |
391 | | dump_array (JsonGenerator *generator, |
392 | | GString *buffer, |
393 | | gint level, |
394 | | JsonArray *array) |
395 | 0 | { |
396 | 0 | JsonGeneratorPrivate *priv = generator->priv; |
397 | 0 | guint array_len = json_array_get_length (array); |
398 | 0 | guint i; |
399 | 0 | gboolean pretty = priv->pretty; |
400 | 0 | guint indent = priv->indent; |
401 | |
|
402 | 0 | g_string_append_c (buffer, '['); |
403 | |
|
404 | 0 | if (array_len == 0) |
405 | 0 | goto out; |
406 | | |
407 | 0 | for (i = 0; i < array_len; i++) |
408 | 0 | { |
409 | 0 | JsonNode *cur = json_array_get_element (array, i); |
410 | |
|
411 | 0 | if (i == 0 && pretty) |
412 | 0 | g_string_append_c (buffer, '\n'); |
413 | |
|
414 | 0 | dump_node (generator, buffer, level + 1, NULL, cur); |
415 | |
|
416 | 0 | if ((i + 1) != array_len) |
417 | 0 | g_string_append_c (buffer, ','); |
418 | |
|
419 | 0 | if (pretty) |
420 | 0 | g_string_append_c (buffer, '\n'); |
421 | 0 | } |
422 | |
|
423 | 0 | if (pretty) |
424 | 0 | { |
425 | 0 | for (i = 0; i < (level * indent); i++) |
426 | 0 | g_string_append_c (buffer, priv->indent_char); |
427 | 0 | } |
428 | |
|
429 | 0 | out: |
430 | 0 | g_string_append_c (buffer, ']'); |
431 | 0 | } |
432 | | |
433 | | static void |
434 | | dump_object (JsonGenerator *generator, |
435 | | GString *buffer, |
436 | | gint level, |
437 | | JsonObject *object) |
438 | 0 | { |
439 | 0 | JsonGeneratorPrivate *priv = generator->priv; |
440 | 0 | GQueue *members; |
441 | 0 | GList *l; |
442 | 0 | gboolean pretty = priv->pretty; |
443 | 0 | guint indent = priv->indent; |
444 | 0 | guint i; |
445 | |
|
446 | 0 | g_string_append_c (buffer, '{'); |
447 | |
|
448 | 0 | members = json_object_get_members_internal (object); |
449 | |
|
450 | 0 | for (l = members->head; l != NULL; l = l->next) |
451 | 0 | { |
452 | 0 | const gchar *member_name = l->data; |
453 | 0 | JsonNode *cur = json_object_get_member (object, member_name); |
454 | |
|
455 | 0 | if (l->prev == NULL && pretty) |
456 | 0 | g_string_append_c (buffer, '\n'); |
457 | |
|
458 | 0 | dump_node (generator, buffer, level + 1, member_name, cur); |
459 | |
|
460 | 0 | if (l->next != NULL) |
461 | 0 | g_string_append_c (buffer, ','); |
462 | |
|
463 | 0 | if (pretty) |
464 | 0 | g_string_append_c (buffer, '\n'); |
465 | 0 | } |
466 | |
|
467 | 0 | if (pretty) |
468 | 0 | { |
469 | 0 | for (i = 0; i < (level * indent); i++) |
470 | 0 | g_string_append_c (buffer, priv->indent_char); |
471 | 0 | } |
472 | |
|
473 | 0 | g_string_append_c (buffer, '}'); |
474 | 0 | } |
475 | | |
476 | | /** |
477 | | * json_generator_new: |
478 | | * |
479 | | * Creates a new `JsonGenerator`. |
480 | | * |
481 | | * You can use this object to generate a JSON data stream starting from a |
482 | | * data object model composed by [struct@Json.Node]s. |
483 | | * |
484 | | * Return value: the newly created generator instance |
485 | | */ |
486 | | JsonGenerator * |
487 | | json_generator_new (void) |
488 | 0 | { |
489 | 0 | return g_object_new (JSON_TYPE_GENERATOR, NULL); |
490 | 0 | } |
491 | | |
492 | | /** |
493 | | * json_generator_to_gstring: |
494 | | * @generator: a generator |
495 | | * @string: a string buffer |
496 | | * |
497 | | * Generates a JSON data stream and appends it to the string buffer. |
498 | | * |
499 | | * Return value: (transfer none): the passed string, updated with |
500 | | * the generated JSON data |
501 | | * |
502 | | * Since: 1.4 |
503 | | */ |
504 | | GString * |
505 | | json_generator_to_gstring (JsonGenerator *generator, |
506 | | GString *string) |
507 | 0 | { |
508 | 0 | JsonNode *root; |
509 | |
|
510 | 0 | g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL); |
511 | 0 | g_return_val_if_fail (string != NULL, NULL); |
512 | | |
513 | 0 | root = generator->priv->root; |
514 | 0 | if (root != NULL) |
515 | 0 | dump_node (generator, string, 0, NULL, root); |
516 | |
|
517 | 0 | return string; |
518 | 0 | } |
519 | | |
520 | | /** |
521 | | * json_generator_to_data: |
522 | | * @generator: a generator |
523 | | * @length: (out) (optional): return location for the length of the returned |
524 | | * buffer |
525 | | * |
526 | | * Generates a JSON data stream from @generator and returns it as a |
527 | | * buffer. |
528 | | * |
529 | | * Return value: (transfer full): a newly allocated string holding a JSON data stream |
530 | | */ |
531 | | gchar * |
532 | | json_generator_to_data (JsonGenerator *generator, |
533 | | gsize *length) |
534 | 0 | { |
535 | 0 | GString *string; |
536 | |
|
537 | 0 | g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL); |
538 | | |
539 | 0 | string = g_string_new (""); |
540 | 0 | json_generator_to_gstring (generator, string); |
541 | |
|
542 | 0 | if (length) |
543 | 0 | *length = string->len; |
544 | |
|
545 | 0 | return g_string_free (string, FALSE); |
546 | 0 | } |
547 | | |
548 | | /** |
549 | | * json_generator_to_file: |
550 | | * @generator: a generator |
551 | | * @filename: (type filename): the path to the target file |
552 | | * @error: return location for a #GError, or %NULL |
553 | | * |
554 | | * Creates a JSON data stream and puts it inside `filename`, overwriting |
555 | | * the file's current contents. |
556 | | * |
557 | | * This operation is atomic, in the sense that the data is written to a |
558 | | * temporary file which is then renamed to the given `filename`. |
559 | | * |
560 | | * Return value: %TRUE if saving was successful. |
561 | | */ |
562 | | gboolean |
563 | | json_generator_to_file (JsonGenerator *generator, |
564 | | const gchar *filename, |
565 | | GError **error) |
566 | 0 | { |
567 | 0 | gchar *buffer; |
568 | 0 | gsize len; |
569 | 0 | gboolean retval; |
570 | |
|
571 | 0 | g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE); |
572 | 0 | g_return_val_if_fail (filename != NULL, FALSE); |
573 | | |
574 | 0 | buffer = json_generator_to_data (generator, &len); |
575 | 0 | retval = g_file_set_contents (filename, buffer, len, error); |
576 | 0 | g_free (buffer); |
577 | |
|
578 | 0 | return retval; |
579 | 0 | } |
580 | | |
581 | | /** |
582 | | * json_generator_to_stream: |
583 | | * @generator: a generator |
584 | | * @stream: the output stream used to write the JSON data |
585 | | * @cancellable: (nullable): a `GCancellable` |
586 | | * @error: return location for a #GError, or %NULL |
587 | | * |
588 | | * Outputs JSON data and writes it (synchronously) to the given stream. |
589 | | * |
590 | | * Return value: whether the write operation was successful |
591 | | * |
592 | | * Since: 0.12 |
593 | | */ |
594 | | gboolean |
595 | | json_generator_to_stream (JsonGenerator *generator, |
596 | | GOutputStream *stream, |
597 | | GCancellable *cancellable, |
598 | | GError **error) |
599 | 0 | { |
600 | 0 | gboolean retval; |
601 | 0 | gchar *buffer; |
602 | 0 | gsize len; |
603 | |
|
604 | 0 | g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE); |
605 | 0 | g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE); |
606 | | |
607 | 0 | if (g_cancellable_set_error_if_cancelled (cancellable, error)) |
608 | 0 | return FALSE; |
609 | | |
610 | 0 | buffer = json_generator_to_data (generator, &len); |
611 | 0 | retval = g_output_stream_write (stream, buffer, len, cancellable, error); |
612 | 0 | g_free (buffer); |
613 | |
|
614 | 0 | return retval; |
615 | 0 | } |
616 | | |
617 | | /** |
618 | | * json_generator_set_root: (attributes org.gtk.Method.set_property=root) |
619 | | * @generator: a generator |
620 | | * @node: the root node |
621 | | * |
622 | | * Sets the root of the JSON data stream to be serialized by |
623 | | * the given generator. |
624 | | * |
625 | | * The passed `node` is copied by the generator object, so it can be |
626 | | * safely freed after calling this function. |
627 | | */ |
628 | | void |
629 | | json_generator_set_root (JsonGenerator *generator, |
630 | | JsonNode *node) |
631 | 0 | { |
632 | 0 | g_return_if_fail (JSON_IS_GENERATOR (generator)); |
633 | | |
634 | 0 | if (generator->priv->root == node) |
635 | 0 | return; |
636 | | |
637 | 0 | if (generator->priv->root != NULL) |
638 | 0 | { |
639 | 0 | json_node_unref (generator->priv->root); |
640 | 0 | generator->priv->root = NULL; |
641 | 0 | } |
642 | |
|
643 | 0 | if (node != NULL) |
644 | 0 | generator->priv->root = json_node_copy (node); |
645 | |
|
646 | 0 | g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_ROOT]); |
647 | 0 | } |
648 | | |
649 | | /** |
650 | | * json_generator_take_root: |
651 | | * @generator: a generator |
652 | | * @node: (transfer full) (nullable): the root node |
653 | | * |
654 | | * Sets the root of the JSON data stream to be serialized by |
655 | | * the given generator. |
656 | | * |
657 | | * The ownership of the passed `node` is transferred to the generator object. |
658 | | * |
659 | | * Since: 1.10 |
660 | | */ |
661 | | void |
662 | | json_generator_take_root (JsonGenerator *generator, |
663 | | JsonNode *node) |
664 | 0 | { |
665 | 0 | JsonGeneratorPrivate *priv = json_generator_get_instance_private (generator); |
666 | |
|
667 | 0 | g_return_if_fail (JSON_IS_GENERATOR (generator)); |
668 | | |
669 | 0 | if (generator->priv->root == node) |
670 | 0 | return; |
671 | | |
672 | 0 | g_clear_pointer (&priv->root, json_node_unref); |
673 | 0 | if (node != NULL) |
674 | 0 | priv->root = node; |
675 | |
|
676 | 0 | g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_ROOT]); |
677 | 0 | } |
678 | | |
679 | | /** |
680 | | * json_generator_get_root: (attributes org.gtk.Method.get_property=root) |
681 | | * @generator: a generator |
682 | | * |
683 | | * Retrieves a pointer to the root node set using |
684 | | * [method@Json.Generator.set_root]. |
685 | | * |
686 | | * Return value: (nullable) (transfer none): the root node |
687 | | * |
688 | | * Since: 0.14 |
689 | | */ |
690 | | JsonNode * |
691 | | json_generator_get_root (JsonGenerator *generator) |
692 | 0 | { |
693 | 0 | g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL); |
694 | | |
695 | 0 | return generator->priv->root; |
696 | 0 | } |
697 | | |
698 | | /** |
699 | | * json_generator_set_pretty: (attributes org.gtk.Method.set_property=pretty) |
700 | | * @generator: a generator |
701 | | * @is_pretty: whether the generated string should be pretty printed |
702 | | * |
703 | | * Sets whether the generated JSON should be pretty printed. |
704 | | * |
705 | | * Pretty printing will use indentation character specified in the |
706 | | * [property@Json.Generator:indent-char] property and the spacing |
707 | | * specified in the [property@Json.Generator:indent] property. |
708 | | * |
709 | | * Since: 0.14 |
710 | | */ |
711 | | void |
712 | | json_generator_set_pretty (JsonGenerator *generator, |
713 | | gboolean is_pretty) |
714 | 0 | { |
715 | 0 | JsonGeneratorPrivate *priv; |
716 | |
|
717 | 0 | g_return_if_fail (JSON_IS_GENERATOR (generator)); |
718 | | |
719 | 0 | priv = generator->priv; |
720 | |
|
721 | 0 | is_pretty = !!is_pretty; |
722 | |
|
723 | 0 | if (priv->pretty != is_pretty) |
724 | 0 | { |
725 | 0 | priv->pretty = is_pretty; |
726 | |
|
727 | 0 | g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_PRETTY]); |
728 | 0 | } |
729 | 0 | } |
730 | | |
731 | | /** |
732 | | * json_generator_get_pretty: (attributes org.gtk.Method.get_property=pretty) |
733 | | * @generator: a generator |
734 | | * |
735 | | * Retrieves the value set using [method@Json.Generator.set_pretty]. |
736 | | * |
737 | | * Return value: `TRUE` if the generated JSON should be pretty-printed, and |
738 | | * `FALSE` otherwise |
739 | | * |
740 | | * Since: 0.14 |
741 | | */ |
742 | | gboolean |
743 | | json_generator_get_pretty (JsonGenerator *generator) |
744 | 0 | { |
745 | 0 | g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE); |
746 | | |
747 | 0 | return generator->priv->pretty; |
748 | 0 | } |
749 | | |
750 | | /** |
751 | | * json_generator_set_indent: (attributes org.gtk.Method.set_property=indent) |
752 | | * @generator: a generator |
753 | | * @indent_level: the number of repetitions of the indentation character |
754 | | * that should be applied when pretty printing |
755 | | * |
756 | | * Sets the number of repetitions for each indentation level. |
757 | | * |
758 | | * Since: 0.14 |
759 | | */ |
760 | | void |
761 | | json_generator_set_indent (JsonGenerator *generator, |
762 | | guint indent_level) |
763 | 0 | { |
764 | 0 | JsonGeneratorPrivate *priv; |
765 | |
|
766 | 0 | g_return_if_fail (JSON_IS_GENERATOR (generator)); |
767 | | |
768 | 0 | priv = generator->priv; |
769 | |
|
770 | 0 | if (priv->indent != indent_level) |
771 | 0 | { |
772 | 0 | priv->indent = indent_level; |
773 | |
|
774 | 0 | g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT]); |
775 | 0 | } |
776 | 0 | } |
777 | | |
778 | | /** |
779 | | * json_generator_get_indent: (attributes org.gtk.Method.get_property=indent) |
780 | | * @generator: a generator |
781 | | * |
782 | | * Retrieves the value set using [method@Json.Generator.set_indent]. |
783 | | * |
784 | | * Return value: the number of repetitions per indentation level |
785 | | * |
786 | | * Since: 0.14 |
787 | | */ |
788 | | guint |
789 | | json_generator_get_indent (JsonGenerator *generator) |
790 | 0 | { |
791 | 0 | g_return_val_if_fail (JSON_IS_GENERATOR (generator), 0); |
792 | | |
793 | 0 | return generator->priv->indent; |
794 | 0 | } |
795 | | |
796 | | /** |
797 | | * json_generator_set_indent_char: (attributes org.gtk.Method.set_property=indent-char) |
798 | | * @generator: a generator |
799 | | * @indent_char: a Unicode character to be used when indenting |
800 | | * |
801 | | * Sets the character to be used when indenting. |
802 | | * |
803 | | * Since: 0.14 |
804 | | */ |
805 | | void |
806 | | json_generator_set_indent_char (JsonGenerator *generator, |
807 | | gunichar indent_char) |
808 | 0 | { |
809 | 0 | JsonGeneratorPrivate *priv; |
810 | |
|
811 | 0 | g_return_if_fail (JSON_IS_GENERATOR (generator)); |
812 | | |
813 | 0 | priv = generator->priv; |
814 | |
|
815 | 0 | if (priv->indent_char != indent_char) |
816 | 0 | { |
817 | 0 | priv->indent_char = indent_char; |
818 | |
|
819 | 0 | g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT_CHAR]); |
820 | 0 | } |
821 | 0 | } |
822 | | |
823 | | /** |
824 | | * json_generator_get_indent_char: (attributes org.gtk.Method.get_property=indent-char) |
825 | | * @generator: a generator |
826 | | * |
827 | | * Retrieves the value set using [method@Json.Generator.set_indent_char]. |
828 | | * |
829 | | * Return value: the character to be used when indenting |
830 | | * |
831 | | * Since: 0.14 |
832 | | */ |
833 | | gunichar |
834 | | json_generator_get_indent_char (JsonGenerator *generator) |
835 | 0 | { |
836 | 0 | g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE); |
837 | | |
838 | 0 | return generator->priv->indent_char; |
839 | 0 | } |