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