| |
1 /* |
| |
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
| |
3 * |
| |
4 * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved. |
| |
5 * |
| |
6 * Redistribution and use in source and binary forms, with or without |
| |
7 * modification, are permitted provided that the following conditions are met: |
| |
8 * |
| |
9 * 1. Redistributions of source code must retain the above copyright |
| |
10 * notice, this list of conditions and the following disclaimer. |
| |
11 * |
| |
12 * 2. Redistributions in binary form must reproduce the above copyright |
| |
13 * notice, this list of conditions and the following disclaimer in the |
| |
14 * documentation and/or other materials provided with the distribution. |
| |
15 * |
| |
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| |
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| |
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| |
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| |
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| |
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| |
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| |
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| |
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| |
26 * POSSIBILITY OF SUCH DAMAGE. |
| |
27 */ |
| |
28 /** |
| |
29 * \file json.h |
| |
30 * \brief Interface for parsing data from JSON files. |
| |
31 * \author Mike Becker |
| |
32 * \author Olaf Wintermann |
| |
33 * \copyright 2-Clause BSD License |
| |
34 */ |
| |
35 |
| |
36 #ifndef UCX_JSON_H |
| |
37 #define UCX_JSON_H |
| |
38 |
| |
39 #include "common.h" |
| |
40 #include "allocator.h" |
| |
41 #include "string.h" |
| |
42 #include "buffer.h" |
| |
43 #include "array_list.h" |
| |
44 |
| |
45 #include <string.h> |
| |
46 |
| |
47 #ifdef __cplusplus |
| |
48 extern "C" { |
| |
49 #endif |
| |
50 |
| |
51 |
| |
52 /** |
| |
53 * The type of the parsed token. |
| |
54 */ |
| |
55 enum cx_json_token_type { |
| |
56 /** |
| |
57 * No complete token parsed, yet. |
| |
58 */ |
| |
59 CX_JSON_NO_TOKEN, |
| |
60 /** |
| |
61 * The presumed token contains syntactical errors. |
| |
62 */ |
| |
63 CX_JSON_TOKEN_ERROR, |
| |
64 /** |
| |
65 * A "begin of array" '[' token. |
| |
66 */ |
| |
67 CX_JSON_TOKEN_BEGIN_ARRAY, |
| |
68 /** |
| |
69 * A "begin of object" '{' token. |
| |
70 */ |
| |
71 CX_JSON_TOKEN_BEGIN_OBJECT, |
| |
72 /** |
| |
73 * An "end of array" ']' token. |
| |
74 */ |
| |
75 CX_JSON_TOKEN_END_ARRAY, |
| |
76 /** |
| |
77 * An "end of object" '}' token. |
| |
78 */ |
| |
79 CX_JSON_TOKEN_END_OBJECT, |
| |
80 /** |
| |
81 * A colon ':' token separating names and values. |
| |
82 */ |
| |
83 CX_JSON_TOKEN_NAME_SEPARATOR, |
| |
84 /** |
| |
85 * A comma ',' token separating object entries or array elements. |
| |
86 */ |
| |
87 CX_JSON_TOKEN_VALUE_SEPARATOR, |
| |
88 /** |
| |
89 * A string token. |
| |
90 */ |
| |
91 CX_JSON_TOKEN_STRING, |
| |
92 /** |
| |
93 * A number token that can be represented as integer. |
| |
94 */ |
| |
95 CX_JSON_TOKEN_INTEGER, |
| |
96 /** |
| |
97 * A number token that cannot be represented as integer. |
| |
98 */ |
| |
99 CX_JSON_TOKEN_NUMBER, |
| |
100 /** |
| |
101 * A literal token. |
| |
102 */ |
| |
103 CX_JSON_TOKEN_LITERAL, |
| |
104 /** |
| |
105 * A white-space token. |
| |
106 */ |
| |
107 CX_JSON_TOKEN_SPACE |
| |
108 }; |
| |
109 |
| |
110 /** |
| |
111 * The type of some JSON value. |
| |
112 */ |
| |
113 enum cx_json_value_type { |
| |
114 /** |
| |
115 * Reserved. |
| |
116 */ |
| |
117 CX_JSON_NOTHING, // this allows us to always return non-NULL values |
| |
118 /** |
| |
119 * A JSON object. |
| |
120 */ |
| |
121 CX_JSON_OBJECT, |
| |
122 /** |
| |
123 * A JSON array. |
| |
124 */ |
| |
125 CX_JSON_ARRAY, |
| |
126 /** |
| |
127 * A string. |
| |
128 */ |
| |
129 CX_JSON_STRING, |
| |
130 /** |
| |
131 * A number that contains an integer. |
| |
132 */ |
| |
133 CX_JSON_INTEGER, |
| |
134 /** |
| |
135 * A number, not necessarily an integer. |
| |
136 */ |
| |
137 CX_JSON_NUMBER, |
| |
138 /** |
| |
139 * A literal (true, false, null). |
| |
140 */ |
| |
141 CX_JSON_LITERAL |
| |
142 }; |
| |
143 |
| |
144 /** |
| |
145 * JSON literal types. |
| |
146 */ |
| |
147 enum cx_json_literal { |
| |
148 /** |
| |
149 * The \c null literal. |
| |
150 */ |
| |
151 CX_JSON_NULL, |
| |
152 /** |
| |
153 * The \c true literal. |
| |
154 */ |
| |
155 CX_JSON_TRUE, |
| |
156 /** |
| |
157 * The \c false literal. |
| |
158 */ |
| |
159 CX_JSON_FALSE |
| |
160 }; |
| |
161 |
| |
162 /** |
| |
163 * Type alias for the token type enum. |
| |
164 */ |
| |
165 typedef enum cx_json_token_type CxJsonTokenType; |
| |
166 /** |
| |
167 * Type alias for the value type enum. |
| |
168 */ |
| |
169 typedef enum cx_json_value_type CxJsonValueType; |
| |
170 |
| |
171 /** |
| |
172 * Type alias for the JSON parser interface. |
| |
173 */ |
| |
174 typedef struct cx_json_s CxJson; |
| |
175 |
| |
176 /** |
| |
177 * Type alias for the token struct. |
| |
178 */ |
| |
179 typedef struct cx_json_token_s CxJsonToken; |
| |
180 |
| |
181 /** |
| |
182 * Type alias for the JSON value struct. |
| |
183 */ |
| |
184 typedef struct cx_json_value_s CxJsonValue; |
| |
185 |
| |
186 /** |
| |
187 * Type alias for the JSON array struct. |
| |
188 */ |
| |
189 typedef struct cx_json_array_s CxJsonArray; |
| |
190 /** |
| |
191 * Type alias for the JSON object struct. |
| |
192 */ |
| |
193 typedef struct cx_json_object_s CxJsonObject; |
| |
194 /** |
| |
195 * Type alias for a JSON string. |
| |
196 */ |
| |
197 typedef struct cx_mutstr_s CxJsonString; |
| |
198 /** |
| |
199 * Type alias for a number that can be represented as 64-bit signed integer. |
| |
200 */ |
| |
201 typedef int64_t CxJsonInteger; |
| |
202 /** |
| |
203 * Type alias for number that is not an integer. |
| |
204 */ |
| |
205 typedef double CxJsonNumber; |
| |
206 /** |
| |
207 * Type alias for a JSON literal. |
| |
208 */ |
| |
209 typedef enum cx_json_literal CxJsonLiteral; |
| |
210 |
| |
211 /** |
| |
212 * Type alias for a key/value pair in a JSON object. |
| |
213 */ |
| |
214 typedef struct cx_json_obj_value_s CxJsonObjValue; |
| |
215 |
| |
216 /** |
| |
217 * JSON array structure. |
| |
218 */ |
| |
219 struct cx_json_array_s { |
| |
220 /** |
| |
221 * The array data. |
| |
222 */ |
| |
223 CX_ARRAY_DECLARE(CxJsonValue*, array); |
| |
224 }; |
| |
225 |
| |
226 /** |
| |
227 * JSON object structure. |
| |
228 */ |
| |
229 struct cx_json_object_s { |
| |
230 /** |
| |
231 * The key/value entries. |
| |
232 */ |
| |
233 CX_ARRAY_DECLARE(CxJsonObjValue, values); |
| |
234 /** |
| |
235 * The original indices to reconstruct the order in which the members were added. |
| |
236 */ |
| |
237 size_t *indices; |
| |
238 }; |
| |
239 |
| |
240 /** |
| |
241 * Structure for a key/value entry in a JSON object. |
| |
242 */ |
| |
243 struct cx_json_obj_value_s { |
| |
244 /** |
| |
245 * The key (or name in JSON terminology) of the value. |
| |
246 */ |
| |
247 cxmutstr name; |
| |
248 /** |
| |
249 * The value. |
| |
250 */ |
| |
251 CxJsonValue *value; |
| |
252 }; |
| |
253 |
| |
254 /** |
| |
255 * Structure for a JSON value. |
| |
256 */ |
| |
257 struct cx_json_value_s { |
| |
258 /** |
| |
259 * The allocator with which the value was allocated. |
| |
260 * |
| |
261 * Required for recursively deallocating memory of objects and arrays. |
| |
262 */ |
| |
263 const CxAllocator *allocator; |
| |
264 /** |
| |
265 * The type of this value. |
| |
266 * |
| |
267 * Specifies how the \c value union shall be resolved. |
| |
268 */ |
| |
269 CxJsonValueType type; |
| |
270 /** |
| |
271 * The value data. |
| |
272 */ |
| |
273 union { |
| |
274 /** |
| |
275 * The array data if type is #CX_JSON_ARRAY. |
| |
276 */ |
| |
277 CxJsonArray array; |
| |
278 /** |
| |
279 * The object data if type is #CX_JSON_OBJECT. |
| |
280 */ |
| |
281 CxJsonObject object; |
| |
282 /** |
| |
283 * The string data if type is #CX_JSON_STRING. |
| |
284 */ |
| |
285 CxJsonString string; |
| |
286 /** |
| |
287 * The integer if type is #CX_JSON_INTEGER. |
| |
288 */ |
| |
289 CxJsonInteger integer; |
| |
290 /** |
| |
291 * The number if type is #CX_JSON_NUMBER. |
| |
292 */ |
| |
293 CxJsonNumber number; |
| |
294 /** |
| |
295 * The literal type if type is #CX_JSON_LITERAL. |
| |
296 */ |
| |
297 CxJsonLiteral literal; |
| |
298 } value; |
| |
299 }; |
| |
300 |
| |
301 /** |
| |
302 * Internally used structure for a parsed token. |
| |
303 * |
| |
304 * You should never need to use this in your code. |
| |
305 */ |
| |
306 struct cx_json_token_s { |
| |
307 /** |
| |
308 * The token type. |
| |
309 */ |
| |
310 CxJsonTokenType tokentype; |
| |
311 /** |
| |
312 * True, iff the \c content must be passed to cx_strfree(). |
| |
313 */ |
| |
314 bool allocated; |
| |
315 /** |
| |
316 * The token text, if any. |
| |
317 * |
| |
318 * This is not necessarily set when the token type already |
| |
319 * uniquely identifies the content. |
| |
320 */ |
| |
321 cxmutstr content; |
| |
322 }; |
| |
323 |
| |
324 /** |
| |
325 * The JSON parser interface. |
| |
326 */ |
| |
327 struct cx_json_s { |
| |
328 /** |
| |
329 * The allocator used for produced JSON values. |
| |
330 */ |
| |
331 const CxAllocator *allocator; |
| |
332 /** |
| |
333 * The input buffer. |
| |
334 */ |
| |
335 CxBuffer buffer; |
| |
336 |
| |
337 /** |
| |
338 * Used internally. |
| |
339 * |
| |
340 * Remembers the prefix of the last uncompleted token. |
| |
341 */ |
| |
342 CxJsonToken uncompleted; |
| |
343 |
| |
344 /** |
| |
345 * A pointer to an intermediate state of the currently parsed value. |
| |
346 * |
| |
347 * Never access this value manually. |
| |
348 */ |
| |
349 CxJsonValue *parsed; |
| |
350 |
| |
351 /** |
| |
352 * A pointer to an intermediate state of a currently parsed object member. |
| |
353 * |
| |
354 * Never access this value manually. |
| |
355 */ |
| |
356 CxJsonObjValue uncompleted_member; |
| |
357 |
| |
358 /** |
| |
359 * State stack. |
| |
360 */ |
| |
361 CX_ARRAY_DECLARE_SIZED(int, states, unsigned); |
| |
362 |
| |
363 /** |
| |
364 * Value buffer stack. |
| |
365 */ |
| |
366 CX_ARRAY_DECLARE_SIZED(CxJsonValue*, vbuf, unsigned); |
| |
367 |
| |
368 /** |
| |
369 * Internally reserved memory for the state stack. |
| |
370 */ |
| |
371 int states_internal[8]; |
| |
372 |
| |
373 /** |
| |
374 * Internally reserved memory for the value buffer stack. |
| |
375 */ |
| |
376 CxJsonValue* vbuf_internal[8]; |
| |
377 |
| |
378 /** |
| |
379 * Used internally. |
| |
380 */ |
| |
381 bool tokenizer_escape; // TODO: check if it can be replaced with look-behind |
| |
382 }; |
| |
383 |
| |
384 /** |
| |
385 * Status codes for the json interface. |
| |
386 */ |
| |
387 enum cx_json_status { |
| |
388 /** |
| |
389 * Everything is fine. |
| |
390 */ |
| |
391 CX_JSON_NO_ERROR, |
| |
392 /** |
| |
393 * The input buffer does not contain more data. |
| |
394 */ |
| |
395 CX_JSON_NO_DATA, |
| |
396 /** |
| |
397 * The input ends unexpectedly. |
| |
398 * |
| |
399 * Refill the buffer with cxJsonFill() to complete the json data. |
| |
400 */ |
| |
401 CX_JSON_INCOMPLETE_DATA, |
| |
402 /** |
| |
403 * Not used as a status and never returned by any function. |
| |
404 * |
| |
405 * You can use this enumerator to check for all "good" status results |
| |
406 * by checking if the status is less than \c CX_JSON_OK. |
| |
407 * |
| |
408 * A "good" status means, that you can refill data and continue parsing. |
| |
409 */ |
| |
410 CX_JSON_OK, |
| |
411 /** |
| |
412 * The input buffer has never been filled. |
| |
413 */ |
| |
414 CX_JSON_NULL_DATA, |
| |
415 /** |
| |
416 * Allocating memory for the internal buffer failed. |
| |
417 */ |
| |
418 CX_JSON_BUFFER_ALLOC_FAILED, |
| |
419 /** |
| |
420 * Allocating memory for a json value failed. |
| |
421 */ |
| |
422 CX_JSON_VALUE_ALLOC_FAILED, |
| |
423 /** |
| |
424 * A number value is incorrectly formatted. |
| |
425 */ |
| |
426 CX_JSON_FORMAT_ERROR_NUMBER, |
| |
427 /** |
| |
428 * The tokenizer found something unexpected. |
| |
429 */ |
| |
430 CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN |
| |
431 }; |
| |
432 |
| |
433 /** |
| |
434 * Typedef for the json status enum. |
| |
435 */ |
| |
436 typedef enum cx_json_status CxJsonStatus; |
| |
437 |
| |
438 /** |
| |
439 * The JSON writer settings. |
| |
440 */ |
| |
441 struct cx_json_writer_s { |
| |
442 /** |
| |
443 * Set true to enable pretty output. |
| |
444 */ |
| |
445 bool pretty; |
| |
446 /** |
| |
447 * Set false to output the members in the order in which they were added. |
| |
448 */ |
| |
449 bool sort_members; |
| |
450 /** |
| |
451 * The maximum number of fractional digits in a number value. |
| |
452 */ |
| |
453 uint8_t frac_max_digits; |
| |
454 /** |
| |
455 * Set true to use spaces instead of tab characters. |
| |
456 * Indentation is only used in pretty output. |
| |
457 */ |
| |
458 bool indent_space; |
| |
459 /** |
| |
460 * If \c indent_space is true, this is the number of spaces per tab. |
| |
461 * Indentation is only used in pretty output. |
| |
462 */ |
| |
463 uint8_t indent; |
| |
464 }; |
| |
465 |
| |
466 /** |
| |
467 * Typedef for the json writer. |
| |
468 */ |
| |
469 typedef struct cx_json_writer_s CxJsonWriter; |
| |
470 |
| |
471 /** |
| |
472 * Creates a default writer configuration for compact output. |
| |
473 * |
| |
474 * @return new JSON writer settings |
| |
475 */ |
| |
476 cx_attr_nodiscard |
| |
477 CxJsonWriter cxJsonWriterCompact(void); |
| |
478 |
| |
479 /** |
| |
480 * Creates a default writer configuration for pretty output. |
| |
481 * |
| |
482 * @param use_spaces false if you want tabs, true if you want four spaces instead |
| |
483 * @return new JSON writer settings |
| |
484 */ |
| |
485 cx_attr_nodiscard |
| |
486 CxJsonWriter cxJsonWriterPretty(bool use_spaces); |
| |
487 |
| |
488 /** |
| |
489 * Writes a JSON value to a buffer or stream. |
| |
490 * |
| |
491 * This function blocks until all data is written or an error when trying |
| |
492 * to write data occurs. |
| |
493 * The write operation is not atomic in the sense that it might happen |
| |
494 * that the data is only partially written when an error occurs with no |
| |
495 * way to indicate how much data was written. |
| |
496 * To avoid this problem, you can use a CxBuffer as \p target which is |
| |
497 * unlikely to fail a write operation and either use the buffer's flush |
| |
498 * feature to relay the data or use the data in the buffer manually to |
| |
499 * write it to the actual target. |
| |
500 * |
| |
501 * @param target the buffer or stream where to write to |
| |
502 * @param value the value that shall be written |
| |
503 * @param wfunc the write function to use |
| |
504 * @param settings formatting settings (or \c NULL to use a compact default) |
| |
505 * @return zero on success, non-zero when no or not all data could be written |
| |
506 */ |
| |
507 cx_attr_nonnull_arg(1, 2, 3) |
| |
508 int cxJsonWrite( |
| |
509 void* target, |
| |
510 const CxJsonValue* value, |
| |
511 cx_write_func wfunc, |
| |
512 const CxJsonWriter* settings |
| |
513 ); |
| |
514 |
| |
515 /** |
| |
516 * Initializes the json interface. |
| |
517 * |
| |
518 * @param json the json interface |
| |
519 * @param allocator the allocator that shall be used for the produced values |
| |
520 * @see cxJsonDestroy() |
| |
521 */ |
| |
522 cx_attr_nonnull_arg(1) |
| |
523 void cxJsonInit(CxJson *json, const CxAllocator *allocator); |
| |
524 |
| |
525 /** |
| |
526 * Destroys the json interface. |
| |
527 * |
| |
528 * @param json the json interface |
| |
529 * @see cxJsonInit() |
| |
530 */ |
| |
531 cx_attr_nonnull |
| |
532 void cxJsonDestroy(CxJson *json); |
| |
533 |
| |
534 /** |
| |
535 * Destroys and re-initializes the json interface. |
| |
536 * |
| |
537 * You might want to use this, to reset the parser after |
| |
538 * encountering a syntax error. |
| |
539 * |
| |
540 * @param json the json interface |
| |
541 */ |
| |
542 cx_attr_nonnull |
| |
543 static inline void cxJsonReset(CxJson *json) { |
| |
544 const CxAllocator *allocator = json->allocator; |
| |
545 cxJsonDestroy(json); |
| |
546 cxJsonInit(json, allocator); |
| |
547 } |
| |
548 |
| |
549 /** |
| |
550 * Fills the input buffer. |
| |
551 * |
| |
552 * @remark The JSON interface tries to avoid copying the input data. |
| |
553 * When you use this function and cxJsonNext() interleaving, |
| |
554 * no copies are performed. However, you must not free the |
| |
555 * pointer to the data in that case. When you invoke the fill |
| |
556 * function more than once before calling cxJsonNext(), |
| |
557 * the additional data is appended - inevitably leading to |
| |
558 * an allocation of a new buffer and copying the previous contents. |
| |
559 * |
| |
560 * @param json the json interface |
| |
561 * @param buf the source buffer |
| |
562 * @param len the length of the source buffer |
| |
563 * @return zero on success, non-zero on internal allocation error |
| |
564 * @see cxJsonFill() |
| |
565 */ |
| |
566 cx_attr_nonnull |
| |
567 cx_attr_access_r(2, 3) |
| |
568 int cxJsonFilln(CxJson *json, const char *buf, size_t len); |
| |
569 |
| |
570 #ifdef __cplusplus |
| |
571 } // extern "C" |
| |
572 |
| |
573 cx_attr_nonnull |
| |
574 static inline int cxJsonFill( |
| |
575 CxJson *json, |
| |
576 cxstring str |
| |
577 ) { |
| |
578 return cxJsonFilln(json, str.ptr, str.length); |
| |
579 } |
| |
580 |
| |
581 cx_attr_nonnull |
| |
582 static inline int cxJsonFill( |
| |
583 CxJson *json, |
| |
584 cxmutstr str |
| |
585 ) { |
| |
586 return cxJsonFilln(json, str.ptr, str.length); |
| |
587 } |
| |
588 |
| |
589 cx_attr_nonnull |
| |
590 cx_attr_cstr_arg(2) |
| |
591 static inline int cxJsonFill( |
| |
592 CxJson *json, |
| |
593 const char *str |
| |
594 ) { |
| |
595 return cxJsonFilln(json, str, strlen(str)); |
| |
596 } |
| |
597 |
| |
598 extern "C" { |
| |
599 #else // __cplusplus |
| |
600 /** |
| |
601 * Fills the input buffer. |
| |
602 * |
| |
603 * @remark The JSON interface tries to avoid copying the input data. |
| |
604 * When you use this function and cxJsonNext() interleaving, |
| |
605 * no copies are performed. However, you must not free the |
| |
606 * pointer to the data in that case. When you invoke the fill |
| |
607 * function more than once before calling cxJsonNext(), |
| |
608 * the additional data is appended - inevitably leading to |
| |
609 * an allocation of a new buffer and copying the previous contents. |
| |
610 * |
| |
611 * @param json the json interface |
| |
612 * @param buf the source string |
| |
613 * @return zero on success, non-zero on internal allocation error |
| |
614 * @see cxJsonFilln() |
| |
615 */ |
| |
616 #define cxJsonFill(json, str) _Generic((str), \ |
| |
617 cxstring: cx_json_fill_cxstr, \ |
| |
618 cxmutstr: cx_json_fill_mutstr, \ |
| |
619 char*: cx_json_fill_str, \ |
| |
620 const char*: cx_json_fill_str) \ |
| |
621 (json, str) |
| |
622 |
| |
623 /** |
| |
624 * @copydoc cxJsonFill() |
| |
625 */ |
| |
626 cx_attr_nonnull |
| |
627 static inline int cx_json_fill_cxstr( |
| |
628 CxJson *json, |
| |
629 cxstring str |
| |
630 ) { |
| |
631 return cxJsonFilln(json, str.ptr, str.length); |
| |
632 } |
| |
633 |
| |
634 /** |
| |
635 * @copydoc cxJsonFill() |
| |
636 */ |
| |
637 cx_attr_nonnull |
| |
638 static inline int cx_json_fill_mutstr( |
| |
639 CxJson *json, |
| |
640 cxmutstr str |
| |
641 ) { |
| |
642 return cxJsonFilln(json, str.ptr, str.length); |
| |
643 } |
| |
644 |
| |
645 /** |
| |
646 * @copydoc cxJsonFill() |
| |
647 */ |
| |
648 cx_attr_nonnull |
| |
649 cx_attr_cstr_arg(2) |
| |
650 static inline int cx_json_fill_str( |
| |
651 CxJson *json, |
| |
652 const char *str |
| |
653 ) { |
| |
654 return cxJsonFilln(json, str, strlen(str)); |
| |
655 } |
| |
656 #endif |
| |
657 |
| |
658 /** |
| |
659 * Creates a new (empty) JSON object. |
| |
660 * |
| |
661 * @param allocator the allocator to use |
| |
662 * @return the new JSON object or \c NULL if allocation fails |
| |
663 */ |
| |
664 cx_attr_nodiscard |
| |
665 CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator); |
| |
666 |
| |
667 /** |
| |
668 * Creates a new (empty) JSON array. |
| |
669 * |
| |
670 * @param allocator the allocator to use |
| |
671 * @return the new JSON array or \c NULL if allocation fails |
| |
672 */ |
| |
673 cx_attr_nodiscard |
| |
674 CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator); |
| |
675 |
| |
676 /** |
| |
677 * Creates a new JSON number value. |
| |
678 * |
| |
679 * @param allocator the allocator to use |
| |
680 * @param num the numeric value |
| |
681 * @return the new JSON value or \c NULL if allocation fails |
| |
682 * @see cxJsonObjPutNumber() |
| |
683 * @see cxJsonArrAddNumbers() |
| |
684 */ |
| |
685 cx_attr_nodiscard |
| |
686 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num); |
| |
687 |
| |
688 /** |
| |
689 * Creates a new JSON number value based on an integer. |
| |
690 * |
| |
691 * @param allocator the allocator to use |
| |
692 * @param num the numeric value |
| |
693 * @return the new JSON value or \c NULL if allocation fails |
| |
694 * @see cxJsonObjPutInteger() |
| |
695 * @see cxJsonArrAddIntegers() |
| |
696 */ |
| |
697 cx_attr_nodiscard |
| |
698 CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num); |
| |
699 |
| |
700 /** |
| |
701 * Creates a new JSON string. |
| |
702 * |
| |
703 * @param allocator the allocator to use |
| |
704 * @param str the string data |
| |
705 * @return the new JSON value or \c NULL if allocation fails |
| |
706 * @see cxJsonCreateCxString() |
| |
707 * @see cxJsonObjPutString() |
| |
708 * @see cxJsonArrAddStrings() |
| |
709 */ |
| |
710 cx_attr_nodiscard |
| |
711 cx_attr_nonnull_arg(2) |
| |
712 cx_attr_cstr_arg(2) |
| |
713 CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char *str); |
| |
714 |
| |
715 /** |
| |
716 * Creates a new JSON string. |
| |
717 * |
| |
718 * @param allocator the allocator to use |
| |
719 * @param str the string data |
| |
720 * @return the new JSON value or \c NULL if allocation fails |
| |
721 * @see cxJsonCreateString() |
| |
722 * @see cxJsonObjPutCxString() |
| |
723 * @see cxJsonArrAddCxStrings() |
| |
724 */ |
| |
725 cx_attr_nodiscard |
| |
726 CxJsonValue* cxJsonCreateCxString(const CxAllocator* allocator, cxstring str); |
| |
727 |
| |
728 /** |
| |
729 * Creates a new JSON literal. |
| |
730 * |
| |
731 * @param allocator the allocator to use |
| |
732 * @param lit the type of literal |
| |
733 * @return the new JSON value or \c NULL if allocation fails |
| |
734 * @see cxJsonObjPutLiteral() |
| |
735 * @see cxJsonArrAddLiterals() |
| |
736 */ |
| |
737 cx_attr_nodiscard |
| |
738 CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit); |
| |
739 |
| |
740 /** |
| |
741 * Adds number values to a JSON array. |
| |
742 * |
| |
743 * @param arr the JSON array |
| |
744 * @param num the array of values |
| |
745 * @param count the number of elements |
| |
746 * @return zero on success, non-zero on allocation failure |
| |
747 */ |
| |
748 cx_attr_nonnull |
| |
749 cx_attr_access_r(2, 3) |
| |
750 int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count); |
| |
751 |
| |
752 /** |
| |
753 * Adds number values, of which all are integers, to a JSON array. |
| |
754 * |
| |
755 * @param arr the JSON array |
| |
756 * @param num the array of values |
| |
757 * @param count the number of elements |
| |
758 * @return zero on success, non-zero on allocation failure |
| |
759 */ |
| |
760 cx_attr_nonnull |
| |
761 cx_attr_access_r(2, 3) |
| |
762 int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count); |
| |
763 |
| |
764 /** |
| |
765 * Adds strings to a JSON array. |
| |
766 * |
| |
767 * The strings will be copied with the allocator of the array. |
| |
768 * |
| |
769 * @param arr the JSON array |
| |
770 * @param str the array of strings |
| |
771 * @param count the number of elements |
| |
772 * @return zero on success, non-zero on allocation failure |
| |
773 * @see cxJsonArrAddCxStrings() |
| |
774 */ |
| |
775 cx_attr_nonnull |
| |
776 cx_attr_access_r(2, 3) |
| |
777 int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count); |
| |
778 |
| |
779 /** |
| |
780 * Adds strings to a JSON array. |
| |
781 * |
| |
782 * The strings will be copied with the allocator of the array. |
| |
783 * |
| |
784 * @param arr the JSON array |
| |
785 * @param str the array of strings |
| |
786 * @param count the number of elements |
| |
787 * @return zero on success, non-zero on allocation failure |
| |
788 * @see cxJsonArrAddStrings() |
| |
789 */ |
| |
790 cx_attr_nonnull |
| |
791 cx_attr_access_r(2, 3) |
| |
792 int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count); |
| |
793 |
| |
794 /** |
| |
795 * Adds literals to a JSON array. |
| |
796 * |
| |
797 * @param arr the JSON array |
| |
798 * @param lit the array of literal types |
| |
799 * @param count the number of elements |
| |
800 * @return zero on success, non-zero on allocation failure |
| |
801 */ |
| |
802 cx_attr_nonnull |
| |
803 cx_attr_access_r(2, 3) |
| |
804 int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count); |
| |
805 |
| |
806 /** |
| |
807 * Add arbitrary values to a JSON array. |
| |
808 * |
| |
809 * \note In contrast to all other add functions, this function adds the values |
| |
810 * directly to the array instead of copying them. |
| |
811 * |
| |
812 * @param arr the JSON array |
| |
813 * @param val the values |
| |
814 * @param count the number of elements |
| |
815 * @return zero on success, non-zero on allocation failure |
| |
816 */ |
| |
817 cx_attr_nonnull |
| |
818 cx_attr_access_r(2, 3) |
| |
819 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count); |
| |
820 |
| |
821 /** |
| |
822 * Adds or replaces a value within a JSON object. |
| |
823 * |
| |
824 * The value will be directly added and not copied. |
| |
825 * |
| |
826 * \note If a value with the specified \p name already exists, |
| |
827 * it will be (recursively) freed with its own allocator. |
| |
828 * |
| |
829 * @param obj the JSON object |
| |
830 * @param name the name of the value |
| |
831 * @param child the value |
| |
832 * @return zero on success, non-zero on allocation failure |
| |
833 */ |
| |
834 cx_attr_nonnull |
| |
835 int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child); |
| |
836 |
| |
837 /** |
| |
838 * Creates a new JSON object and adds it to an existing object. |
| |
839 * |
| |
840 * @param obj the target JSON object |
| |
841 * @param name the name of the new value |
| |
842 * @return the new value or \c NULL if allocation fails |
| |
843 * @see cxJsonObjPut() |
| |
844 * @see cxJsonCreateObj() |
| |
845 */ |
| |
846 cx_attr_nonnull |
| |
847 CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name); |
| |
848 |
| |
849 /** |
| |
850 * Creates a new JSON array and adds it to an object. |
| |
851 * |
| |
852 * @param obj the target JSON object |
| |
853 * @param name the name of the new value |
| |
854 * @return the new value or \c NULL if allocation fails |
| |
855 * @see cxJsonObjPut() |
| |
856 * @see cxJsonCreateArr() |
| |
857 */ |
| |
858 cx_attr_nonnull |
| |
859 CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name); |
| |
860 |
| |
861 /** |
| |
862 * Creates a new JSON number and adds it to an object. |
| |
863 * |
| |
864 * @param obj the target JSON object |
| |
865 * @param name the name of the new value |
| |
866 * @param num the numeric value |
| |
867 * @return the new value or \c NULL if allocation fails |
| |
868 * @see cxJsonObjPut() |
| |
869 * @see cxJsonCreateNumber() |
| |
870 */ |
| |
871 cx_attr_nonnull |
| |
872 CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, double num); |
| |
873 |
| |
874 /** |
| |
875 * Creates a new JSON number, based on an integer, and adds it to an object. |
| |
876 * |
| |
877 * @param obj the target JSON object |
| |
878 * @param name the name of the new value |
| |
879 * @param num the numeric value |
| |
880 * @return the new value or \c NULL if allocation fails |
| |
881 * @see cxJsonObjPut() |
| |
882 * @see cxJsonCreateInteger() |
| |
883 */ |
| |
884 cx_attr_nonnull |
| |
885 CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int64_t num); |
| |
886 |
| |
887 /** |
| |
888 * Creates a new JSON string and adds it to an object. |
| |
889 * |
| |
890 * The string data is copied. |
| |
891 * |
| |
892 * @param obj the target JSON object |
| |
893 * @param name the name of the new value |
| |
894 * @param str the string data |
| |
895 * @return the new value or \c NULL if allocation fails |
| |
896 * @see cxJsonObjPut() |
| |
897 * @see cxJsonCreateString() |
| |
898 */ |
| |
899 cx_attr_nonnull |
| |
900 cx_attr_cstr_arg(3) |
| |
901 CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str); |
| |
902 |
| |
903 /** |
| |
904 * Creates a new JSON string and adds it to an object. |
| |
905 * |
| |
906 * The string data is copied. |
| |
907 * |
| |
908 * @param obj the target JSON object |
| |
909 * @param name the name of the new value |
| |
910 * @param str the string data |
| |
911 * @return the new value or \c NULL if allocation fails |
| |
912 * @see cxJsonObjPut() |
| |
913 * @see cxJsonCreateCxString() |
| |
914 */ |
| |
915 cx_attr_nonnull |
| |
916 CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxstring str); |
| |
917 |
| |
918 /** |
| |
919 * Creates a new JSON literal and adds it to an object. |
| |
920 * |
| |
921 * @param obj the target JSON object |
| |
922 * @param name the name of the new value |
| |
923 * @param lit the type of literal |
| |
924 * @return the new value or \c NULL if allocation fails |
| |
925 * @see cxJsonObjPut() |
| |
926 * @see cxJsonCreateLiteral() |
| |
927 */ |
| |
928 cx_attr_nonnull |
| |
929 CxJsonValue* cxJsonObjPutLiteral(CxJsonValue* obj, cxstring name, CxJsonLiteral lit); |
| |
930 |
| |
931 /** |
| |
932 * Recursively deallocates the memory of a JSON value. |
| |
933 * |
| |
934 * \remark The type of each deallocated value will be changed |
| |
935 * to #CX_JSON_NOTHING and values of such type will be skipped |
| |
936 * by the de-allocation. That means, this function protects |
| |
937 * you from double-frees when you are accidentally freeing |
| |
938 * a nested value and then the parent value (or vice versa). |
| |
939 * |
| |
940 * @param value the value |
| |
941 */ |
| |
942 void cxJsonValueFree(CxJsonValue *value); |
| |
943 |
| |
944 /** |
| |
945 * Tries to obtain the next JSON value. |
| |
946 * |
| |
947 * |
| |
948 * @param json the json interface |
| |
949 * @param value a pointer where the next value shall be stored |
| |
950 * @return a status code |
| |
951 */ |
| |
952 cx_attr_nonnull |
| |
953 cx_attr_access_w(2) |
| |
954 CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value); |
| |
955 |
| |
956 /** |
| |
957 * Checks if the specified value is a JSON object. |
| |
958 * |
| |
959 * @param value a pointer to the value |
| |
960 * @return true if the value is a JSON object, false otherwise |
| |
961 */ |
| |
962 cx_attr_nonnull |
| |
963 static inline bool cxJsonIsObject(const CxJsonValue *value) { |
| |
964 return value->type == CX_JSON_OBJECT; |
| |
965 } |
| |
966 |
| |
967 /** |
| |
968 * Checks if the specified value is a JSON array. |
| |
969 * |
| |
970 * @param value a pointer to the value |
| |
971 * @return true if the value is a JSON array, false otherwise |
| |
972 */ |
| |
973 cx_attr_nonnull |
| |
974 static inline bool cxJsonIsArray(const CxJsonValue *value) { |
| |
975 return value->type == CX_JSON_ARRAY; |
| |
976 } |
| |
977 |
| |
978 /** |
| |
979 * Checks if the specified value is a string. |
| |
980 * |
| |
981 * @param value a pointer to the value |
| |
982 * @return true if the value is a string, false otherwise |
| |
983 */ |
| |
984 cx_attr_nonnull |
| |
985 static inline bool cxJsonIsString(const CxJsonValue *value) { |
| |
986 return value->type == CX_JSON_STRING; |
| |
987 } |
| |
988 |
| |
989 /** |
| |
990 * Checks if the specified value is a JSON number. |
| |
991 * |
| |
992 * This function will return true for both floating point and |
| |
993 * integer numbers. |
| |
994 * |
| |
995 * @param value a pointer to the value |
| |
996 * @return true if the value is a JSON number, false otherwise |
| |
997 * @see cxJsonIsInteger() |
| |
998 */ |
| |
999 cx_attr_nonnull |
| |
1000 static inline bool cxJsonIsNumber(const CxJsonValue *value) { |
| |
1001 return value->type == CX_JSON_NUMBER || value->type == CX_JSON_INTEGER; |
| |
1002 } |
| |
1003 |
| |
1004 /** |
| |
1005 * Checks if the specified value is an integer number. |
| |
1006 * |
| |
1007 * @param value a pointer to the value |
| |
1008 * @return true if the value is an integer number, false otherwise |
| |
1009 * @see cxJsonIsNumber() |
| |
1010 */ |
| |
1011 cx_attr_nonnull |
| |
1012 static inline bool cxJsonIsInteger(const CxJsonValue *value) { |
| |
1013 return value->type == CX_JSON_INTEGER; |
| |
1014 } |
| |
1015 |
| |
1016 /** |
| |
1017 * Checks if the specified value is a JSON literal. |
| |
1018 * |
| |
1019 * JSON literals are \c true, \c false, and \c null. |
| |
1020 * |
| |
1021 * @param value a pointer to the value |
| |
1022 * @return true if the value is a JSON literal, false otherwise |
| |
1023 * @see cxJsonIsTrue() |
| |
1024 * @see cxJsonIsFalse() |
| |
1025 * @see cxJsonIsNull() |
| |
1026 */ |
| |
1027 cx_attr_nonnull |
| |
1028 static inline bool cxJsonIsLiteral(const CxJsonValue *value) { |
| |
1029 return value->type == CX_JSON_LITERAL; |
| |
1030 } |
| |
1031 |
| |
1032 /** |
| |
1033 * Checks if the specified value is a Boolean literal. |
| |
1034 * |
| |
1035 * @param value a pointer to the value |
| |
1036 * @return true if the value is either \c true or \c false, false otherwise |
| |
1037 * @see cxJsonIsTrue() |
| |
1038 * @see cxJsonIsFalse() |
| |
1039 */ |
| |
1040 cx_attr_nonnull |
| |
1041 static inline bool cxJsonIsBool(const CxJsonValue *value) { |
| |
1042 return cxJsonIsLiteral(value) && value->value.literal != CX_JSON_NULL; |
| |
1043 } |
| |
1044 |
| |
1045 /** |
| |
1046 * Checks if the specified value is \c true. |
| |
1047 * |
| |
1048 * \remark Be advised, that this is not the same as |
| |
1049 * testing \c !cxJsonIsFalse(v). |
| |
1050 * |
| |
1051 * @param value a pointer to the value |
| |
1052 * @return true if the value is \c true, false otherwise |
| |
1053 * @see cxJsonIsBool() |
| |
1054 * @see cxJsonIsFalse() |
| |
1055 */ |
| |
1056 cx_attr_nonnull |
| |
1057 static inline bool cxJsonIsTrue(const CxJsonValue *value) { |
| |
1058 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_TRUE; |
| |
1059 } |
| |
1060 |
| |
1061 /** |
| |
1062 * Checks if the specified value is \c false. |
| |
1063 * |
| |
1064 * \remark Be advised, that this is not the same as |
| |
1065 * testing \c !cxJsonIsTrue(v). |
| |
1066 * |
| |
1067 * @param value a pointer to the value |
| |
1068 * @return true if the value is \c false, false otherwise |
| |
1069 * @see cxJsonIsBool() |
| |
1070 * @see cxJsonIsTrue() |
| |
1071 */ |
| |
1072 cx_attr_nonnull |
| |
1073 static inline bool cxJsonIsFalse(const CxJsonValue *value) { |
| |
1074 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_FALSE; |
| |
1075 } |
| |
1076 |
| |
1077 /** |
| |
1078 * Checks if the specified value is \c null. |
| |
1079 * |
| |
1080 * @param value a pointer to the value |
| |
1081 * @return true if the value is \c null, false otherwise |
| |
1082 * @see cxJsonIsLiteral() |
| |
1083 */ |
| |
1084 cx_attr_nonnull |
| |
1085 static inline bool cxJsonIsNull(const CxJsonValue *value) { |
| |
1086 return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_NULL; |
| |
1087 } |
| |
1088 |
| |
1089 /** |
| |
1090 * Obtains a C string from the given JSON value. |
| |
1091 * |
| |
1092 * If the \p value is not a string, the behavior is undefined. |
| |
1093 * |
| |
1094 * @param value the JSON value |
| |
1095 * @return the value represented as C string |
| |
1096 * @see cxJsonIsString() |
| |
1097 */ |
| |
1098 cx_attr_nonnull |
| |
1099 cx_attr_returns_nonnull |
| |
1100 static inline char *cxJsonAsString(const CxJsonValue *value) { |
| |
1101 return value->value.string.ptr; |
| |
1102 } |
| |
1103 |
| |
1104 /** |
| |
1105 * Obtains a UCX string from the given JSON value. |
| |
1106 * |
| |
1107 * If the \p value is not a string, the behavior is undefined. |
| |
1108 * |
| |
1109 * @param value the JSON value |
| |
1110 * @return the value represented as UCX string |
| |
1111 * @see cxJsonIsString() |
| |
1112 */ |
| |
1113 cx_attr_nonnull |
| |
1114 static inline cxstring cxJsonAsCxString(const CxJsonValue *value) { |
| |
1115 return cx_strcast(value->value.string); |
| |
1116 } |
| |
1117 |
| |
1118 /** |
| |
1119 * Obtains a mutable UCX string from the given JSON value. |
| |
1120 * |
| |
1121 * If the \p value is not a string, the behavior is undefined. |
| |
1122 * |
| |
1123 * @param value the JSON value |
| |
1124 * @return the value represented as mutable UCX string |
| |
1125 * @see cxJsonIsString() |
| |
1126 */ |
| |
1127 cx_attr_nonnull |
| |
1128 static inline cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) { |
| |
1129 return value->value.string; |
| |
1130 } |
| |
1131 |
| |
1132 /** |
| |
1133 * Obtains a double-precision floating point value from the given JSON value. |
| |
1134 * |
| |
1135 * If the \p value is not a JSON number, the behavior is undefined. |
| |
1136 * |
| |
1137 * @param value the JSON value |
| |
1138 * @return the value represented as double |
| |
1139 * @see cxJsonIsNumber() |
| |
1140 */ |
| |
1141 cx_attr_nonnull |
| |
1142 static inline double cxJsonAsDouble(const CxJsonValue *value) { |
| |
1143 if (value->type == CX_JSON_INTEGER) { |
| |
1144 return (double) value->value.integer; |
| |
1145 } else { |
| |
1146 return value->value.number; |
| |
1147 } |
| |
1148 } |
| |
1149 |
| |
1150 /** |
| |
1151 * Obtains a 64-bit signed integer from the given JSON value. |
| |
1152 * |
| |
1153 * If the \p value is not a JSON number, the behavior is undefined. |
| |
1154 * If it is a JSON number, but not an integer, the value will be |
| |
1155 * converted to an integer, possibly losing precision. |
| |
1156 * |
| |
1157 * @param value the JSON value |
| |
1158 * @return the value represented as double |
| |
1159 * @see cxJsonIsNumber() |
| |
1160 * @see cxJsonIsInteger() |
| |
1161 */ |
| |
1162 cx_attr_nonnull |
| |
1163 static inline int64_t cxJsonAsInteger(const CxJsonValue *value) { |
| |
1164 if (value->type == CX_JSON_INTEGER) { |
| |
1165 return value->value.integer; |
| |
1166 } else { |
| |
1167 return (int64_t) value->value.number; |
| |
1168 } |
| |
1169 } |
| |
1170 |
| |
1171 /** |
| |
1172 * Obtains a Boolean value from the given JSON value. |
| |
1173 * |
| |
1174 * If the \p value is not a JSON literal, the behavior is undefined. |
| |
1175 * The \c null literal is interpreted as \c false. |
| |
1176 * |
| |
1177 * @param value the JSON value |
| |
1178 * @return the value represented as double |
| |
1179 * @see cxJsonIsLiteral() |
| |
1180 */ |
| |
1181 cx_attr_nonnull |
| |
1182 static inline bool cxJsonAsBool(const CxJsonValue *value) { |
| |
1183 return value->value.literal == CX_JSON_TRUE; |
| |
1184 } |
| |
1185 |
| |
1186 /** |
| |
1187 * Returns the size of a JSON array. |
| |
1188 * |
| |
1189 * If the \p value is not a JSON array, the behavior is undefined. |
| |
1190 * |
| |
1191 * @param value the JSON value |
| |
1192 * @return the size of the array |
| |
1193 * @see cxJsonIsArray() |
| |
1194 */ |
| |
1195 cx_attr_nonnull |
| |
1196 static inline size_t cxJsonArrSize(const CxJsonValue *value) { |
| |
1197 return value->value.array.array_size; |
| |
1198 } |
| |
1199 |
| |
1200 /** |
| |
1201 * Returns an element from a JSON array. |
| |
1202 * |
| |
1203 * If the \p value is not a JSON array, the behavior is undefined. |
| |
1204 * |
| |
1205 * This function guarantees to return a value. If the index is |
| |
1206 * out of bounds, the returned value will be of type |
| |
1207 * #CX_JSON_NOTHING, but never \c NULL. |
| |
1208 * |
| |
1209 * @param value the JSON value |
| |
1210 * @param index the index in the array |
| |
1211 * @return the value at the specified index |
| |
1212 * @see cxJsonIsArray() |
| |
1213 */ |
| |
1214 cx_attr_nonnull |
| |
1215 cx_attr_returns_nonnull |
| |
1216 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index); |
| |
1217 |
| |
1218 /** |
| |
1219 * Returns an iterator over the JSON array elements. |
| |
1220 * |
| |
1221 * The iterator yields values of type \c CxJsonValue* . |
| |
1222 * |
| |
1223 * If the \p value is not a JSON array, the behavior is undefined. |
| |
1224 * |
| |
1225 * @param value the JSON value |
| |
1226 * @return an iterator over the array elements |
| |
1227 * @see cxJsonIsArray() |
| |
1228 */ |
| |
1229 cx_attr_nonnull |
| |
1230 cx_attr_nodiscard |
| |
1231 CxIterator cxJsonArrIter(const CxJsonValue *value); |
| |
1232 |
| |
1233 /** |
| |
1234 * Returns an iterator over the JSON object members. |
| |
1235 * |
| |
1236 * The iterator yields values of type \c CxJsonObjValue* which |
| |
1237 * contain the name and value of the member. |
| |
1238 * |
| |
1239 * If the \p value is not a JSON object, the behavior is undefined. |
| |
1240 * |
| |
1241 * @param value the JSON value |
| |
1242 * @return an iterator over the object members |
| |
1243 * @see cxJsonIsObject() |
| |
1244 */ |
| |
1245 cx_attr_nonnull |
| |
1246 cx_attr_nodiscard |
| |
1247 CxIterator cxJsonObjIter(const CxJsonValue *value); |
| |
1248 |
| |
1249 /** |
| |
1250 * @copydoc cxJsonObjGet() |
| |
1251 */ |
| |
1252 cx_attr_nonnull |
| |
1253 cx_attr_returns_nonnull |
| |
1254 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name); |
| |
1255 |
| |
1256 #ifdef __cplusplus |
| |
1257 } // extern "C" |
| |
1258 |
| |
1259 CxJsonValue *cxJsonObjGet(const CxJsonValue *value, cxstring name) { |
| |
1260 return cx_json_obj_get_cxstr(value, name); |
| |
1261 } |
| |
1262 |
| |
1263 CxJsonValue *cxJsonObjGet(const CxJsonValue *value, cxmutstr name) { |
| |
1264 return cx_json_obj_get_cxstr(value, cx_strcast(name)); |
| |
1265 } |
| |
1266 |
| |
1267 CxJsonValue *cxJsonObjGet(const CxJsonValue *value, const char *name) { |
| |
1268 return cx_json_obj_get_cxstr(value, cx_str(name)); |
| |
1269 } |
| |
1270 |
| |
1271 extern "C" { |
| |
1272 #else |
| |
1273 /** |
| |
1274 * Returns a value corresponding to a key in a JSON object. |
| |
1275 * |
| |
1276 * If the \p value is not a JSON object, the behavior is undefined. |
| |
1277 * |
| |
1278 * This function guarantees to return a JSON value. If the |
| |
1279 * object does not contain \p name, the returned JSON value |
| |
1280 * will be of type #CX_JSON_NOTHING, but never \c NULL. |
| |
1281 * |
| |
1282 * @param value the JSON object |
| |
1283 * @param name the key to look up |
| |
1284 * @return the value corresponding to the key |
| |
1285 * @see cxJsonIsObject() |
| |
1286 */ |
| |
1287 #define cxJsonObjGet(value, name) _Generic((name), \ |
| |
1288 cxstring: cx_json_obj_get_cxstr, \ |
| |
1289 cxmutstr: cx_json_obj_get_mutstr, \ |
| |
1290 char*: cx_json_obj_get_str, \ |
| |
1291 const char*: cx_json_obj_get_str) \ |
| |
1292 (value, name) |
| |
1293 |
| |
1294 /** |
| |
1295 * @copydoc cxJsonObjGet() |
| |
1296 */ |
| |
1297 cx_attr_nonnull |
| |
1298 cx_attr_returns_nonnull |
| |
1299 static inline CxJsonValue *cx_json_obj_get_mutstr(const CxJsonValue *value, cxmutstr name) { |
| |
1300 return cx_json_obj_get_cxstr(value, cx_strcast(name)); |
| |
1301 } |
| |
1302 |
| |
1303 /** |
| |
1304 * @copydoc cxJsonObjGet() |
| |
1305 */ |
| |
1306 cx_attr_nonnull |
| |
1307 cx_attr_returns_nonnull |
| |
1308 cx_attr_cstr_arg(2) |
| |
1309 static inline CxJsonValue *cx_json_obj_get_str(const CxJsonValue *value, const char *name) { |
| |
1310 return cx_json_obj_get_cxstr(value, cx_str(name)); |
| |
1311 } |
| |
1312 #endif |
| |
1313 |
| |
1314 #ifdef __cplusplus |
| |
1315 } |
| |
1316 #endif |
| |
1317 |
| |
1318 #endif /* UCX_JSON_H */ |
| |
1319 |