/src/tinysparql/subprojects/json-glib-1.10.6/json-glib/json-builder.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* json-generator.c - JSON tree builder |
2 | | * |
3 | | * This file is part of JSON-GLib |
4 | | * |
5 | | * SPDX-FileCopyrightText: 2010 Luca Bruno <lethalman88@gmail.com> |
6 | | * SPDX-FileCopyrightText: 2015 Collabora Ltd. |
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 | | * Luca Bruno <lethalman88@gmail.com> |
24 | | * Philip Withnall <philip.withnall@collabora.co.uk> |
25 | | */ |
26 | | |
27 | | /** |
28 | | * JsonBuilder: |
29 | | * |
30 | | * `JsonBuilder` provides an object for generating a JSON tree. |
31 | | * |
32 | | * The root of the JSON tree can be either a [struct@Json.Object] or a [struct@Json.Array]. |
33 | | * Thus the first call must necessarily be either |
34 | | * [method@Json.Builder.begin_object] or [method@Json.Builder.begin_array]. |
35 | | * |
36 | | * For convenience to language bindings, most `JsonBuilder` method return the |
37 | | * instance, making it easy to chain function calls. |
38 | | * |
39 | | * ## Using `JsonBuilder` |
40 | | * |
41 | | * ```c |
42 | | * g_autoptr(JsonBuilder) builder = json_builder_new (); |
43 | | * |
44 | | * json_builder_begin_object (builder); |
45 | | * |
46 | | * json_builder_set_member_name (builder, "url"); |
47 | | * json_builder_add_string_value (builder, "http://www.gnome.org/img/flash/two-thirty.png"); |
48 | | * |
49 | | * json_builder_set_member_name (builder, "size"); |
50 | | * json_builder_begin_array (builder); |
51 | | * json_builder_add_int_value (builder, 652); |
52 | | * json_builder_add_int_value (builder, 242); |
53 | | * json_builder_end_array (builder); |
54 | | * |
55 | | * json_builder_end_object (builder); |
56 | | * |
57 | | * g_autoptr(JsonNode) root = json_builder_get_root (builder); |
58 | | * |
59 | | * g_autoptr(JsonGenerator) gen = json_generator_new (); |
60 | | * json_generator_set_root (gen, root); |
61 | | * g_autofree char *str = json_generator_to_data (gen, NULL); |
62 | | * |
63 | | * // str now contains the following JSON data |
64 | | * // { "url" : "http://www.gnome.org/img/flash/two-thirty.png", "size" : [ 652, 242 ] } |
65 | | * ``` |
66 | | */ |
67 | | |
68 | | #include "config.h" |
69 | | |
70 | | #include <stdlib.h> |
71 | | #include <string.h> |
72 | | |
73 | | #include "json-types-private.h" |
74 | | |
75 | | #include "json-builder.h" |
76 | | |
77 | | struct _JsonBuilderPrivate |
78 | | { |
79 | | GQueue *stack; |
80 | | JsonNode *root; |
81 | | gboolean immutable; |
82 | | }; |
83 | | |
84 | | enum |
85 | | { |
86 | | PROP_IMMUTABLE = 1, |
87 | | PROP_LAST |
88 | | }; |
89 | | |
90 | | static GParamSpec *builder_props[PROP_LAST] = { NULL, }; |
91 | | |
92 | | typedef enum |
93 | | { |
94 | | JSON_BUILDER_MODE_OBJECT, |
95 | | JSON_BUILDER_MODE_ARRAY, |
96 | | JSON_BUILDER_MODE_MEMBER |
97 | | } JsonBuilderMode; |
98 | | |
99 | | typedef struct |
100 | | { |
101 | | JsonBuilderMode mode; |
102 | | |
103 | | union |
104 | | { |
105 | | JsonObject *object; |
106 | | JsonArray *array; |
107 | | } data; |
108 | | gchar *member_name; |
109 | | } JsonBuilderState; |
110 | | |
111 | | static void |
112 | | json_builder_state_free (JsonBuilderState *state) |
113 | 0 | { |
114 | 0 | if (G_LIKELY (state)) |
115 | 0 | { |
116 | 0 | switch (state->mode) |
117 | 0 | { |
118 | 0 | case JSON_BUILDER_MODE_OBJECT: |
119 | 0 | case JSON_BUILDER_MODE_MEMBER: |
120 | 0 | json_object_unref (state->data.object); |
121 | 0 | g_free (state->member_name); |
122 | 0 | state->data.object = NULL; |
123 | 0 | state->member_name = NULL; |
124 | 0 | break; |
125 | | |
126 | 0 | case JSON_BUILDER_MODE_ARRAY: |
127 | 0 | json_array_unref (state->data.array); |
128 | 0 | state->data.array = NULL; |
129 | 0 | break; |
130 | | |
131 | 0 | default: |
132 | 0 | g_assert_not_reached (); |
133 | 0 | } |
134 | | |
135 | 0 | g_free (state); |
136 | 0 | } |
137 | 0 | } |
138 | | |
139 | | G_DEFINE_TYPE_WITH_PRIVATE (JsonBuilder, json_builder, G_TYPE_OBJECT) |
140 | | |
141 | | static void |
142 | | json_builder_free_all_state (JsonBuilder *builder) |
143 | 0 | { |
144 | 0 | JsonBuilderState *state; |
145 | |
|
146 | 0 | while (!g_queue_is_empty (builder->priv->stack)) |
147 | 0 | { |
148 | 0 | state = g_queue_pop_head (builder->priv->stack); |
149 | 0 | json_builder_state_free (state); |
150 | 0 | } |
151 | |
|
152 | 0 | if (builder->priv->root) |
153 | 0 | { |
154 | 0 | json_node_unref (builder->priv->root); |
155 | 0 | builder->priv->root = NULL; |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | static void |
160 | | json_builder_finalize (GObject *gobject) |
161 | 0 | { |
162 | 0 | JsonBuilderPrivate *priv = json_builder_get_instance_private ((JsonBuilder *) gobject); |
163 | |
|
164 | 0 | json_builder_free_all_state (JSON_BUILDER (gobject)); |
165 | |
|
166 | 0 | g_queue_free (priv->stack); |
167 | 0 | priv->stack = NULL; |
168 | |
|
169 | 0 | G_OBJECT_CLASS (json_builder_parent_class)->finalize (gobject); |
170 | 0 | } |
171 | | |
172 | | static void |
173 | | json_builder_set_property (GObject *gobject, |
174 | | guint prop_id, |
175 | | const GValue *value, |
176 | | GParamSpec *pspec) |
177 | 0 | { |
178 | 0 | JsonBuilderPrivate *priv = JSON_BUILDER (gobject)->priv; |
179 | |
|
180 | 0 | switch (prop_id) |
181 | 0 | { |
182 | 0 | case PROP_IMMUTABLE: |
183 | | /* Construct-only. */ |
184 | 0 | priv->immutable = g_value_get_boolean (value); |
185 | 0 | break; |
186 | 0 | default: |
187 | 0 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
188 | 0 | break; |
189 | 0 | } |
190 | 0 | } |
191 | | |
192 | | static void |
193 | | json_builder_get_property (GObject *gobject, |
194 | | guint prop_id, |
195 | | GValue *value, |
196 | | GParamSpec *pspec) |
197 | 0 | { |
198 | 0 | JsonBuilderPrivate *priv = JSON_BUILDER (gobject)->priv; |
199 | |
|
200 | 0 | switch (prop_id) |
201 | 0 | { |
202 | 0 | case PROP_IMMUTABLE: |
203 | 0 | g_value_set_boolean (value, priv->immutable); |
204 | 0 | break; |
205 | 0 | default: |
206 | 0 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
207 | 0 | break; |
208 | 0 | } |
209 | 0 | } |
210 | | |
211 | | static void |
212 | | json_builder_class_init (JsonBuilderClass *klass) |
213 | 0 | { |
214 | 0 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
215 | | |
216 | | /** |
217 | | * JsonBuilder:immutable: |
218 | | * |
219 | | * Whether the tree should be immutable when created. |
220 | | * |
221 | | * Making the output immutable on creation avoids the expense |
222 | | * of traversing it to make it immutable later. |
223 | | * |
224 | | * Since: 1.2 |
225 | | */ |
226 | 0 | builder_props[PROP_IMMUTABLE] = |
227 | 0 | g_param_spec_boolean ("immutable", |
228 | 0 | "Immutable Output", |
229 | 0 | "Whether the builder output is immutable.", |
230 | 0 | FALSE, |
231 | 0 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); |
232 | |
|
233 | 0 | gobject_class->set_property = json_builder_set_property; |
234 | 0 | gobject_class->get_property = json_builder_get_property; |
235 | 0 | gobject_class->finalize = json_builder_finalize; |
236 | |
|
237 | 0 | g_object_class_install_properties (gobject_class, PROP_LAST, builder_props); |
238 | 0 | } |
239 | | |
240 | | static void |
241 | | json_builder_init (JsonBuilder *builder) |
242 | 0 | { |
243 | 0 | JsonBuilderPrivate *priv = json_builder_get_instance_private (builder); |
244 | |
|
245 | 0 | builder->priv = priv; |
246 | |
|
247 | 0 | priv->stack = g_queue_new (); |
248 | 0 | priv->root = NULL; |
249 | 0 | } |
250 | | |
251 | | static inline JsonBuilderMode |
252 | | json_builder_current_mode (JsonBuilder *builder) |
253 | 0 | { |
254 | 0 | JsonBuilderState *state = g_queue_peek_head (builder->priv->stack); |
255 | 0 | return state->mode; |
256 | 0 | } |
257 | | |
258 | | static inline gboolean |
259 | | json_builder_is_valid_add_mode (JsonBuilder *builder) |
260 | 0 | { |
261 | 0 | JsonBuilderMode mode = json_builder_current_mode (builder); |
262 | 0 | return mode == JSON_BUILDER_MODE_MEMBER || mode == JSON_BUILDER_MODE_ARRAY; |
263 | 0 | } |
264 | | |
265 | | /** |
266 | | * json_builder_new: |
267 | | * |
268 | | * Creates a new `JsonBuilder`. |
269 | | * |
270 | | * You can use this object to generate a JSON tree and obtain the root node. |
271 | | * |
272 | | * Return value: the newly created builder instance |
273 | | */ |
274 | | JsonBuilder * |
275 | | json_builder_new (void) |
276 | 0 | { |
277 | 0 | return g_object_new (JSON_TYPE_BUILDER, NULL); |
278 | 0 | } |
279 | | |
280 | | /** |
281 | | * json_builder_new_immutable: (constructor) |
282 | | * |
283 | | * Creates a new, immutable `JsonBuilder` instance. |
284 | | * |
285 | | * It is equivalent to setting the [property@Json.Builder:immutable] property |
286 | | * set to `TRUE` at construction time. |
287 | | * |
288 | | * Since: 1.2 |
289 | | * Returns: (transfer full): the newly create builder instance |
290 | | */ |
291 | | JsonBuilder * |
292 | | json_builder_new_immutable (void) |
293 | 0 | { |
294 | 0 | return g_object_new (JSON_TYPE_BUILDER, "immutable", TRUE, NULL); |
295 | 0 | } |
296 | | |
297 | | /** |
298 | | * json_builder_get_root: |
299 | | * @builder: a builder |
300 | | * |
301 | | * Returns the root of the currently constructed tree. |
302 | | * |
303 | | * if the build is incomplete (ie: if there are any opened objects, or any |
304 | | * open object members and array elements) then this function will return |
305 | | * `NULL`. |
306 | | * |
307 | | * Return value: (nullable) (transfer full): the root node |
308 | | */ |
309 | | JsonNode * |
310 | | json_builder_get_root (JsonBuilder *builder) |
311 | 0 | { |
312 | 0 | JsonNode *root = NULL; |
313 | |
|
314 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
315 | | |
316 | 0 | if (builder->priv->root) |
317 | 0 | root = json_node_copy (builder->priv->root); |
318 | | |
319 | | /* Sanity check. */ |
320 | 0 | g_assert (!builder->priv->immutable || |
321 | 0 | root == NULL || |
322 | 0 | json_node_is_immutable (root)); |
323 | | |
324 | 0 | return root; |
325 | 0 | } |
326 | | |
327 | | /** |
328 | | * json_builder_reset: |
329 | | * @builder: a builder |
330 | | * |
331 | | * Resets the state of the builder back to its initial state. |
332 | | */ |
333 | | void |
334 | | json_builder_reset (JsonBuilder *builder) |
335 | 0 | { |
336 | 0 | g_return_if_fail (JSON_IS_BUILDER (builder)); |
337 | | |
338 | 0 | json_builder_free_all_state (builder); |
339 | 0 | } |
340 | | |
341 | | /** |
342 | | * json_builder_begin_object: |
343 | | * @builder: a builder |
344 | | * |
345 | | * Opens an object inside the given builder. |
346 | | * |
347 | | * You can add a new member to the object by using [method@Json.Builder.set_member_name], |
348 | | * followed by [method@Json.Builder.add_value]. |
349 | | * |
350 | | * Once you added all members to the object, you must call [method@Json.Builder.end_object] |
351 | | * to close the object. |
352 | | * |
353 | | * If the builder is in an inconsistent state, this function will return `NULL`. |
354 | | * |
355 | | * Return value: (nullable) (transfer none): the builder instance |
356 | | */ |
357 | | JsonBuilder * |
358 | | json_builder_begin_object (JsonBuilder *builder) |
359 | 0 | { |
360 | 0 | JsonObject *object; |
361 | 0 | JsonBuilderState *state; |
362 | 0 | JsonBuilderState *cur_state; |
363 | |
|
364 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
365 | 0 | g_return_val_if_fail (builder->priv->root == NULL, NULL); |
366 | 0 | g_return_val_if_fail (g_queue_is_empty (builder->priv->stack) || json_builder_is_valid_add_mode (builder), NULL); |
367 | | |
368 | 0 | object = json_object_new (); |
369 | 0 | cur_state = g_queue_peek_head (builder->priv->stack); |
370 | 0 | if (cur_state) |
371 | 0 | { |
372 | 0 | switch (cur_state->mode) |
373 | 0 | { |
374 | 0 | case JSON_BUILDER_MODE_ARRAY: |
375 | 0 | json_array_add_object_element (cur_state->data.array, json_object_ref (object)); |
376 | 0 | break; |
377 | | |
378 | 0 | case JSON_BUILDER_MODE_MEMBER: |
379 | 0 | json_object_set_object_member (cur_state->data.object, cur_state->member_name, json_object_ref (object)); |
380 | 0 | g_free (cur_state->member_name); |
381 | 0 | cur_state->member_name = NULL; |
382 | 0 | cur_state->mode = JSON_BUILDER_MODE_OBJECT; |
383 | 0 | break; |
384 | | |
385 | 0 | default: |
386 | 0 | g_assert_not_reached (); |
387 | 0 | } |
388 | 0 | } |
389 | | |
390 | 0 | state = g_new (JsonBuilderState, 1); |
391 | 0 | state->data.object = object; |
392 | 0 | state->member_name = NULL; |
393 | 0 | state->mode = JSON_BUILDER_MODE_OBJECT; |
394 | 0 | g_queue_push_head (builder->priv->stack, state); |
395 | |
|
396 | 0 | return builder; |
397 | 0 | } |
398 | | |
399 | | /** |
400 | | * json_builder_end_object: |
401 | | * @builder: a builder |
402 | | * |
403 | | * Closes the object inside the given builder that was opened by the most |
404 | | * recent call to [method@Json.Builder.begin_object]. |
405 | | * |
406 | | * This function cannot be called after [method@Json.Builder.set_member_name]. |
407 | | * |
408 | | * Return value: (nullable) (transfer none): the builder instance |
409 | | */ |
410 | | JsonBuilder * |
411 | | json_builder_end_object (JsonBuilder *builder) |
412 | 0 | { |
413 | 0 | JsonBuilderState *state; |
414 | |
|
415 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
416 | 0 | g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); |
417 | 0 | g_return_val_if_fail (json_builder_current_mode (builder) == JSON_BUILDER_MODE_OBJECT, NULL); |
418 | | |
419 | 0 | state = g_queue_pop_head (builder->priv->stack); |
420 | |
|
421 | 0 | if (builder->priv->immutable) |
422 | 0 | json_object_seal (state->data.object); |
423 | |
|
424 | 0 | if (g_queue_is_empty (builder->priv->stack)) |
425 | 0 | { |
426 | 0 | builder->priv->root = json_node_new (JSON_NODE_OBJECT); |
427 | 0 | json_node_take_object (builder->priv->root, json_object_ref (state->data.object)); |
428 | |
|
429 | 0 | if (builder->priv->immutable) |
430 | 0 | json_node_seal (builder->priv->root); |
431 | 0 | } |
432 | |
|
433 | 0 | json_builder_state_free (state); |
434 | |
|
435 | 0 | return builder; |
436 | 0 | } |
437 | | |
438 | | /** |
439 | | * json_builder_begin_array: |
440 | | * @builder: a builder |
441 | | * |
442 | | * Opens an array inside the given builder. |
443 | | * |
444 | | * You can add a new element to the array by using [method@Json.Builder.add_value]. |
445 | | * |
446 | | * Once you added all elements to the array, you must call |
447 | | * [method@Json.Builder.end_array] to close the array. |
448 | | * |
449 | | * Return value: (nullable) (transfer none): the builder instance |
450 | | */ |
451 | | JsonBuilder * |
452 | | json_builder_begin_array (JsonBuilder *builder) |
453 | 0 | { |
454 | 0 | JsonArray *array; |
455 | 0 | JsonBuilderState *state; |
456 | 0 | JsonBuilderState *cur_state; |
457 | |
|
458 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
459 | 0 | g_return_val_if_fail (builder->priv->root == NULL, NULL); |
460 | 0 | g_return_val_if_fail (g_queue_is_empty (builder->priv->stack) || json_builder_is_valid_add_mode (builder), NULL); |
461 | | |
462 | 0 | array = json_array_new (); |
463 | 0 | cur_state = g_queue_peek_head (builder->priv->stack); |
464 | 0 | if (cur_state) |
465 | 0 | { |
466 | 0 | switch (cur_state->mode) |
467 | 0 | { |
468 | 0 | case JSON_BUILDER_MODE_ARRAY: |
469 | 0 | json_array_add_array_element (cur_state->data.array, json_array_ref (array)); |
470 | 0 | break; |
471 | | |
472 | 0 | case JSON_BUILDER_MODE_MEMBER: |
473 | 0 | json_object_set_array_member (cur_state->data.object, cur_state->member_name, json_array_ref (array)); |
474 | 0 | g_free (cur_state->member_name); |
475 | 0 | cur_state->member_name = NULL; |
476 | 0 | cur_state->mode = JSON_BUILDER_MODE_OBJECT; |
477 | 0 | break; |
478 | | |
479 | 0 | default: |
480 | 0 | g_assert_not_reached (); |
481 | 0 | } |
482 | 0 | } |
483 | | |
484 | 0 | state = g_new (JsonBuilderState, 1); |
485 | 0 | state->data.array = array; |
486 | 0 | state->mode = JSON_BUILDER_MODE_ARRAY; |
487 | 0 | g_queue_push_head (builder->priv->stack, state); |
488 | |
|
489 | 0 | return builder; |
490 | 0 | } |
491 | | |
492 | | /** |
493 | | * json_builder_end_array: |
494 | | * @builder: a builder |
495 | | * |
496 | | * Closes the array inside the given builder that was opened by the most |
497 | | * recent call to [method@Json.Builder.begin_array]. |
498 | | * |
499 | | * This function cannot be called after [method@Json.Builder.set_member_name]. |
500 | | * |
501 | | * Return value: (nullable) (transfer none): the builder instance |
502 | | */ |
503 | | JsonBuilder * |
504 | | json_builder_end_array (JsonBuilder *builder) |
505 | 0 | { |
506 | 0 | JsonBuilderState *state; |
507 | |
|
508 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
509 | 0 | g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); |
510 | 0 | g_return_val_if_fail (json_builder_current_mode (builder) == JSON_BUILDER_MODE_ARRAY, NULL); |
511 | | |
512 | 0 | state = g_queue_pop_head (builder->priv->stack); |
513 | |
|
514 | 0 | if (builder->priv->immutable) |
515 | 0 | json_array_seal (state->data.array); |
516 | |
|
517 | 0 | if (g_queue_is_empty (builder->priv->stack)) |
518 | 0 | { |
519 | 0 | builder->priv->root = json_node_new (JSON_NODE_ARRAY); |
520 | 0 | json_node_take_array (builder->priv->root, json_array_ref (state->data.array)); |
521 | |
|
522 | 0 | if (builder->priv->immutable) |
523 | 0 | json_node_seal (builder->priv->root); |
524 | 0 | } |
525 | |
|
526 | 0 | json_builder_state_free (state); |
527 | |
|
528 | 0 | return builder; |
529 | 0 | } |
530 | | |
531 | | /** |
532 | | * json_builder_set_member_name: |
533 | | * @builder: a builder |
534 | | * @member_name: the name of the member |
535 | | * |
536 | | * Sets the name of the member in an object. |
537 | | * |
538 | | * This function must be followed by of these functions: |
539 | | * |
540 | | * - [method@Json.Builder.add_value], to add a scalar value to the member |
541 | | * - [method@Json.Builder.begin_object], to add an object to the member |
542 | | * - [method@Json.Builder.begin_array], to add an array to the member |
543 | | * |
544 | | * This function can only be called within an open object. |
545 | | * |
546 | | * Return value: (nullable) (transfer none): the builder instance |
547 | | */ |
548 | | JsonBuilder * |
549 | | json_builder_set_member_name (JsonBuilder *builder, |
550 | | const gchar *member_name) |
551 | 0 | { |
552 | 0 | JsonBuilderState *state; |
553 | |
|
554 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
555 | 0 | g_return_val_if_fail (member_name != NULL, NULL); |
556 | 0 | g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); |
557 | 0 | g_return_val_if_fail (json_builder_current_mode (builder) == JSON_BUILDER_MODE_OBJECT, NULL); |
558 | | |
559 | 0 | state = g_queue_peek_head (builder->priv->stack); |
560 | 0 | state->member_name = g_strdup (member_name); |
561 | 0 | state->mode = JSON_BUILDER_MODE_MEMBER; |
562 | |
|
563 | 0 | return builder; |
564 | 0 | } |
565 | | |
566 | | /** |
567 | | * json_builder_add_value: |
568 | | * @builder: a builder |
569 | | * @node: (transfer full): the value of the member or element |
570 | | * |
571 | | * Adds a value to the currently open object member or array. |
572 | | * |
573 | | * If called after [method@Json.Builder.set_member_name], sets the given node |
574 | | * as the value of the current member in the open object; otherwise, the node |
575 | | * is appended to the elements of the open array. |
576 | | * |
577 | | * The builder will take ownership of the node. |
578 | | * |
579 | | * Return value: (nullable) (transfer none): the builder instance |
580 | | */ |
581 | | JsonBuilder * |
582 | | json_builder_add_value (JsonBuilder *builder, |
583 | | JsonNode *node) |
584 | 0 | { |
585 | 0 | JsonBuilderState *state; |
586 | |
|
587 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
588 | 0 | g_return_val_if_fail (node != NULL, NULL); |
589 | 0 | g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); |
590 | 0 | g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); |
591 | | |
592 | 0 | state = g_queue_peek_head (builder->priv->stack); |
593 | |
|
594 | 0 | if (builder->priv->immutable) |
595 | 0 | json_node_seal (node); |
596 | |
|
597 | 0 | switch (state->mode) |
598 | 0 | { |
599 | 0 | case JSON_BUILDER_MODE_MEMBER: |
600 | 0 | json_object_set_member (state->data.object, state->member_name, node); |
601 | 0 | g_free (state->member_name); |
602 | 0 | state->member_name = NULL; |
603 | 0 | state->mode = JSON_BUILDER_MODE_OBJECT; |
604 | 0 | break; |
605 | | |
606 | 0 | case JSON_BUILDER_MODE_ARRAY: |
607 | 0 | json_array_add_element (state->data.array, node); |
608 | 0 | break; |
609 | | |
610 | 0 | default: |
611 | 0 | g_assert_not_reached (); |
612 | 0 | } |
613 | | |
614 | 0 | return builder; |
615 | 0 | } |
616 | | |
617 | | /** |
618 | | * json_builder_add_int_value: |
619 | | * @builder: a builder |
620 | | * @value: the value of the member or element |
621 | | * |
622 | | * Adds an integer value to the currently open object member or array. |
623 | | * |
624 | | * If called after [method@Json.Builder.set_member_name], sets the given value |
625 | | * as the value of the current member in the open object; otherwise, the value |
626 | | * is appended to the elements of the open array. |
627 | | * |
628 | | * See also: [method@Json.Builder.add_value] |
629 | | * |
630 | | * Return value: (nullable) (transfer none): the builder instance |
631 | | */ |
632 | | JsonBuilder * |
633 | | json_builder_add_int_value (JsonBuilder *builder, |
634 | | gint64 value) |
635 | 0 | { |
636 | 0 | JsonBuilderState *state; |
637 | |
|
638 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
639 | 0 | g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); |
640 | 0 | g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); |
641 | | |
642 | 0 | state = g_queue_peek_head (builder->priv->stack); |
643 | 0 | switch (state->mode) |
644 | 0 | { |
645 | 0 | case JSON_BUILDER_MODE_MEMBER: |
646 | 0 | json_object_set_int_member (state->data.object, state->member_name, value); |
647 | 0 | g_free (state->member_name); |
648 | 0 | state->member_name = NULL; |
649 | 0 | state->mode = JSON_BUILDER_MODE_OBJECT; |
650 | 0 | break; |
651 | | |
652 | 0 | case JSON_BUILDER_MODE_ARRAY: |
653 | 0 | json_array_add_int_element (state->data.array, value); |
654 | 0 | break; |
655 | | |
656 | 0 | default: |
657 | 0 | g_assert_not_reached (); |
658 | 0 | } |
659 | | |
660 | 0 | return builder; |
661 | 0 | } |
662 | | |
663 | | /** |
664 | | * json_builder_add_double_value: |
665 | | * @builder: a builder |
666 | | * @value: the value of the member or element |
667 | | * |
668 | | * Adds a floating point value to the currently open object member or array. |
669 | | * |
670 | | * If called after [method@Json.Builder.set_member_name], sets the given value |
671 | | * as the value of the current member in the open object; otherwise, the value |
672 | | * is appended to the elements of the open array. |
673 | | * |
674 | | * See also: [method@Json.Builder.add_value] |
675 | | * |
676 | | * Return value: (nullable) (transfer none): the builder instance |
677 | | */ |
678 | | JsonBuilder * |
679 | | json_builder_add_double_value (JsonBuilder *builder, |
680 | | gdouble value) |
681 | 0 | { |
682 | 0 | JsonBuilderState *state; |
683 | |
|
684 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
685 | 0 | g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); |
686 | 0 | g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); |
687 | | |
688 | 0 | state = g_queue_peek_head (builder->priv->stack); |
689 | |
|
690 | 0 | switch (state->mode) |
691 | 0 | { |
692 | 0 | case JSON_BUILDER_MODE_MEMBER: |
693 | 0 | json_object_set_double_member (state->data.object, state->member_name, value); |
694 | 0 | g_free (state->member_name); |
695 | 0 | state->member_name = NULL; |
696 | 0 | state->mode = JSON_BUILDER_MODE_OBJECT; |
697 | 0 | break; |
698 | | |
699 | 0 | case JSON_BUILDER_MODE_ARRAY: |
700 | 0 | json_array_add_double_element (state->data.array, value); |
701 | 0 | break; |
702 | | |
703 | 0 | default: |
704 | 0 | g_assert_not_reached (); |
705 | 0 | } |
706 | | |
707 | 0 | return builder; |
708 | 0 | } |
709 | | |
710 | | /** |
711 | | * json_builder_add_boolean_value: |
712 | | * @builder: a builder |
713 | | * @value: the value of the member or element |
714 | | * |
715 | | * Adds a boolean value to the currently open object member or array. |
716 | | * |
717 | | * If called after [method@Json.Builder.set_member_name], sets the given value |
718 | | * as the value of the current member in the open object; otherwise, the value |
719 | | * is appended to the elements of the open array. |
720 | | * |
721 | | * See also: [method@Json.Builder.add_value] |
722 | | * |
723 | | * Return value: (nullable) (transfer none): the builder instance |
724 | | */ |
725 | | JsonBuilder * |
726 | | json_builder_add_boolean_value (JsonBuilder *builder, |
727 | | gboolean value) |
728 | 0 | { |
729 | 0 | JsonBuilderState *state; |
730 | |
|
731 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
732 | 0 | g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); |
733 | 0 | g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); |
734 | | |
735 | 0 | state = g_queue_peek_head (builder->priv->stack); |
736 | |
|
737 | 0 | switch (state->mode) |
738 | 0 | { |
739 | 0 | case JSON_BUILDER_MODE_MEMBER: |
740 | 0 | json_object_set_boolean_member (state->data.object, state->member_name, value); |
741 | 0 | g_free (state->member_name); |
742 | 0 | state->member_name = NULL; |
743 | 0 | state->mode = JSON_BUILDER_MODE_OBJECT; |
744 | 0 | break; |
745 | | |
746 | 0 | case JSON_BUILDER_MODE_ARRAY: |
747 | 0 | json_array_add_boolean_element (state->data.array, value); |
748 | 0 | break; |
749 | | |
750 | 0 | default: |
751 | 0 | g_assert_not_reached (); |
752 | 0 | } |
753 | | |
754 | 0 | return builder; |
755 | 0 | } |
756 | | |
757 | | /** |
758 | | * json_builder_add_string_value: |
759 | | * @builder: a builder |
760 | | * @value: the value of the member or element |
761 | | * |
762 | | * Adds a string value to the currently open object member or array. |
763 | | * |
764 | | * If called after [method@Json.Builder.set_member_name], sets the given value |
765 | | * as the value of the current member in the open object; otherwise, the value |
766 | | * is appended to the elements of the open array. |
767 | | * |
768 | | * See also: [method@Json.Builder.add_value] |
769 | | * |
770 | | * Return value: (nullable) (transfer none): the builder instance |
771 | | */ |
772 | | JsonBuilder * |
773 | | json_builder_add_string_value (JsonBuilder *builder, |
774 | | const gchar *value) |
775 | 0 | { |
776 | 0 | JsonBuilderState *state; |
777 | |
|
778 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
779 | 0 | g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); |
780 | 0 | g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); |
781 | | |
782 | 0 | state = g_queue_peek_head (builder->priv->stack); |
783 | |
|
784 | 0 | switch (state->mode) |
785 | 0 | { |
786 | 0 | case JSON_BUILDER_MODE_MEMBER: |
787 | 0 | json_object_set_string_member (state->data.object, state->member_name, value); |
788 | 0 | g_free (state->member_name); |
789 | 0 | state->member_name = NULL; |
790 | 0 | state->mode = JSON_BUILDER_MODE_OBJECT; |
791 | 0 | break; |
792 | | |
793 | 0 | case JSON_BUILDER_MODE_ARRAY: |
794 | 0 | json_array_add_string_element (state->data.array, value); |
795 | 0 | break; |
796 | | |
797 | 0 | default: |
798 | 0 | g_assert_not_reached (); |
799 | 0 | } |
800 | | |
801 | 0 | return builder; |
802 | 0 | } |
803 | | |
804 | | /** |
805 | | * json_builder_add_null_value: |
806 | | * @builder: a builder |
807 | | * |
808 | | * Adds a null value to the currently open object member or array. |
809 | | * |
810 | | * If called after [method@Json.Builder.set_member_name], sets the given value |
811 | | * as the value of the current member in the open object; otherwise, the value |
812 | | * is appended to the elements of the open array. |
813 | | * |
814 | | * See also: [method@Json.Builder.add_value] |
815 | | * |
816 | | * Return value: (nullable) (transfer none): the builder instance |
817 | | */ |
818 | | JsonBuilder * |
819 | | json_builder_add_null_value (JsonBuilder *builder) |
820 | 0 | { |
821 | 0 | JsonBuilderState *state; |
822 | |
|
823 | 0 | g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); |
824 | 0 | g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); |
825 | 0 | g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); |
826 | | |
827 | 0 | state = g_queue_peek_head (builder->priv->stack); |
828 | |
|
829 | 0 | switch (state->mode) |
830 | 0 | { |
831 | 0 | case JSON_BUILDER_MODE_MEMBER: |
832 | 0 | json_object_set_null_member (state->data.object, state->member_name); |
833 | 0 | g_free (state->member_name); |
834 | 0 | state->member_name = NULL; |
835 | 0 | state->mode = JSON_BUILDER_MODE_OBJECT; |
836 | 0 | break; |
837 | | |
838 | 0 | case JSON_BUILDER_MODE_ARRAY: |
839 | 0 | json_array_add_null_element (state->data.array); |
840 | 0 | break; |
841 | | |
842 | 0 | default: |
843 | 0 | g_assert_not_reached (); |
844 | 0 | } |
845 | | |
846 | 0 | return builder; |
847 | 0 | } |