blob: 85368cbe3365947123660d92766613da5e50d2ce [file] [log] [blame]
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001/**
2 * @file json.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Generic JSON format parser for libyang
5 *
6 * Copyright (c) 2020 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#include <assert.h>
16#include <ctype.h>
17#include <errno.h>
Radek Krejci50f0c6b2020-06-18 16:31:48 +020018#include <stdlib.h>
Radek Krejci47fab892020-11-05 17:02:41 +010019#include <string.h>
Radek Krejci50f0c6b2020-06-18 16:31:48 +020020#include <sys/types.h>
21
22#include "common.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020023#include "in_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010024#include "json.h"
aPiecek704f8e92021-08-25 13:35:05 +020025#include "tree_schema_internal.h"
Radek Krejci50f0c6b2020-06-18 16:31:48 +020026
27#define JSON_PUSH_STATUS_RET(CTX, STATUS) \
Michal Vasko59e90fc2021-09-22 12:17:08 +020028 LY_CHECK_RET(ly_set_add(&CTX->status, (void *)(uintptr_t)(STATUS), 1, NULL))
Radek Krejci50f0c6b2020-06-18 16:31:48 +020029
30#define JSON_POP_STATUS_RET(CTX) \
31 assert(CTX->status.count); CTX->status.count--;
32
Michal Vasko22df3f02020-08-24 13:29:22 +020033const char *
Radek Krejci50f0c6b2020-06-18 16:31:48 +020034lyjson_token2str(enum LYJSON_PARSER_STATUS status)
35{
36 switch (status) {
37 case LYJSON_ERROR:
38 return "error";
39 case LYJSON_ROOT:
40 return "document root";
41 case LYJSON_FALSE:
42 return "false";
43 case LYJSON_TRUE:
44 return "true";
45 case LYJSON_NULL:
46 return "null";
47 case LYJSON_OBJECT:
48 return "object";
49 case LYJSON_OBJECT_CLOSED:
50 return "object closed";
51 case LYJSON_OBJECT_EMPTY:
52 return "empty object";
53 case LYJSON_ARRAY:
54 return "array";
55 case LYJSON_ARRAY_CLOSED:
56 return "array closed";
57 case LYJSON_ARRAY_EMPTY:
58 return "empty array";
59 case LYJSON_NUMBER:
60 return "number";
61 case LYJSON_STRING:
62 return "string";
63 case LYJSON_END:
64 return "end of input";
65 }
66
67 return "";
68}
69
70static LY_ERR
71skip_ws(struct lyjson_ctx *jsonctx)
72{
73 /* skip leading whitespaces */
74 while (*jsonctx->in->current != '\0' && is_jsonws(*jsonctx->in->current)) {
Radek Krejcidd713ce2021-01-04 23:12:12 +010075 if (*jsonctx->in->current == '\n') {
76 LY_IN_NEW_LINE(jsonctx->in);
77 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +020078 ly_in_skip(jsonctx->in, 1);
79 }
80 if (*jsonctx->in->current == '\0') {
81 JSON_PUSH_STATUS_RET(jsonctx, LYJSON_END);
82 }
83
84 return LY_SUCCESS;
85}
86
87/*
88 * @brief Set value corresponding to the current context's status
89 */
90static void
Radek Krejci857189e2020-09-01 13:26:36 +020091lyjson_ctx_set_value(struct lyjson_ctx *jsonctx, const char *value, size_t value_len, ly_bool dynamic)
Radek Krejci50f0c6b2020-06-18 16:31:48 +020092{
93 assert(jsonctx);
94
Juraj Vijtiukec285cd2021-01-14 11:41:20 +010095 if (jsonctx->dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +020096 free((char *)jsonctx->value);
Radek Krejci50f0c6b2020-06-18 16:31:48 +020097 }
98 jsonctx->value = value;
99 jsonctx->value_len = value_len;
100 jsonctx->dynamic = dynamic;
101}
102
103static LY_ERR
104lyjson_check_next(struct lyjson_ctx *jsonctx)
105{
106 if (jsonctx->status.count == 1) {
107 /* top level value (JSON-text), ws expected */
Michal Vasko69730152020-10-09 16:30:07 +0200108 if ((*jsonctx->in->current == '\0') || is_jsonws(*jsonctx->in->current)) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200109 return LY_SUCCESS;
110 }
111 } else if (lyjson_ctx_status(jsonctx, 1) == LYJSON_OBJECT) {
112 LY_CHECK_RET(skip_ws(jsonctx));
Michal Vasko69730152020-10-09 16:30:07 +0200113 if ((*jsonctx->in->current == ',') || (*jsonctx->in->current == '}')) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200114 return LY_SUCCESS;
115 }
116 } else if (lyjson_ctx_status(jsonctx, 1) == LYJSON_ARRAY) {
117 LY_CHECK_RET(skip_ws(jsonctx));
Michal Vasko69730152020-10-09 16:30:07 +0200118 if ((*jsonctx->in->current == ',') || (*jsonctx->in->current == ']')) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200119 return LY_SUCCESS;
120 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200121 }
122
Radek Krejcie7010dc2021-03-04 15:54:24 +0100123 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Unexpected character \"%c\" after JSON %s.",
124 *jsonctx->in->current, lyjson_token2str(lyjson_ctx_status(jsonctx, 0)));
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200125 return LY_EVALID;
126}
127
128/**
129 * Input is expected to start after the opening quotation-mark.
130 * When succeeds, input is moved after the closing quotation-mark.
131 */
132static LY_ERR
133lyjson_string_(struct lyjson_ctx *jsonctx)
134{
135#define BUFSIZE 24
136#define BUFSIZE_STEP 128
137
138 const char *in = jsonctx->in->current, *start;
139 char *buf = NULL;
140 size_t offset; /* read offset in input buffer */
141 size_t len; /* length of the output string (write offset in output buffer) */
142 size_t size = 0; /* size of the output buffer */
143 size_t u;
144 uint64_t start_line;
145
146 assert(jsonctx);
147
148 /* init */
149 start = in;
Radek Krejcid54412f2020-12-17 20:25:35 +0100150 start_line = jsonctx->in->line;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200151 offset = len = 0;
152
153 /* parse */
154 while (in[offset]) {
155 if (in[offset] == '\\') {
156 /* escape sequence */
Michal Vasko2be1d762021-03-11 16:53:15 +0100157 const char *slash = &in[offset];
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200158 uint32_t value;
159 uint8_t i = 1;
160
161 if (!buf) {
162 /* prepare output buffer */
163 buf = malloc(BUFSIZE);
164 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
165 size = BUFSIZE;
166 }
167
168 /* allocate enough for the offset and next character,
169 * we will need 4 bytes at most since we support only the predefined
170 * (one-char) entities and character references */
171 if (len + offset + 4 >= size) {
Juraj Vijtiukd746a352021-01-15 11:33:33 +0100172 size_t increment;
Radek Krejcidf549132021-01-21 10:32:32 +0100173 for (increment = BUFSIZE_STEP; len + offset + 4 >= size + increment; increment += BUFSIZE_STEP) {}
Juraj Vijtiukd746a352021-01-15 11:33:33 +0100174 buf = ly_realloc(buf, size + increment);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200175 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
176 size += BUFSIZE_STEP;
177 }
178
179 if (offset) {
180 /* store what we have so far */
181 memcpy(&buf[len], in, offset);
182 len += offset;
183 in += offset;
184 offset = 0;
185 }
186
187 switch (in[++offset]) {
188 case '"':
189 /* quotation mark */
190 value = 0x22;
191 break;
192 case '\\':
193 /* reverse solidus */
194 value = 0x5c;
195 break;
196 case '/':
197 /* solidus */
198 value = 0x2f;
199 break;
200 case 'b':
201 /* backspace */
202 value = 0x08;
203 break;
204 case 'f':
205 /* form feed */
206 value = 0x0c;
207 break;
208 case 'n':
209 /* line feed */
210 value = 0x0a;
211 break;
212 case 'r':
213 /* carriage return */
214 value = 0x0d;
215 break;
216 case 't':
217 /* tab */
218 value = 0x09;
219 break;
220 case 'u':
221 /* Basic Multilingual Plane character \uXXXX */
222 offset++;
223 for (value = i = 0; i < 4; i++) {
Juraj Vijtiuk2b94e4b2020-11-16 23:52:07 +0100224 if (!in[offset + i]) {
Michal Vasko2be1d762021-03-11 16:53:15 +0100225 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid basic multilingual plane character \"%s\".", slash);
Juraj Vijtiuk2b94e4b2020-11-16 23:52:07 +0100226 goto error;
227 } else if (isdigit(in[offset + i])) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200228 u = (in[offset + i] - '0');
229 } else if (in[offset + i] > 'F') {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100230 u = LY_BASE_DEC + (in[offset + i] - 'a');
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200231 } else {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100232 u = LY_BASE_DEC + (in[offset + i] - 'A');
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200233 }
Radek Krejcif13b87b2020-12-01 22:02:17 +0100234 value = (LY_BASE_HEX * value) + u;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200235 }
236 break;
237 default:
238 /* invalid escape sequence */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100239 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character escape sequence \\%c.", in[offset]);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200240 goto error;
241
242 }
243
244 offset += i; /* add read escaped characters */
245 LY_CHECK_ERR_GOTO(ly_pututf8(&buf[len], value, &u),
Radek Krejci2efc45b2020-12-22 16:25:44 +0100246 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character reference \"%.*s\" (0x%08x).",
Michal Vasko2be1d762021-03-11 16:53:15 +0100247 (int)(&in[offset] - slash), slash, value),
Michal Vasko69730152020-10-09 16:30:07 +0200248 error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200249 len += u; /* update number of bytes in buffer */
250 in += offset; /* move the input by the processed bytes stored in the buffer ... */
251 offset = 0; /* ... and reset the offset index for future moving data into buffer */
252
253 } else if (in[offset] == '"') {
254 /* end of string */
255 if (buf) {
256 /* realloc exact size string */
257 buf = ly_realloc(buf, len + offset + 1);
258 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
259 size = len + offset + 1;
Michal Vasko08e9b112021-06-11 15:41:17 +0200260 if (offset) {
261 memcpy(&buf[len], in, offset);
262 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200263
264 /* set terminating NULL byte */
265 buf[len + offset] = '\0';
266 }
267 len += offset;
268 ++offset;
269 in += offset;
270 goto success;
271 } else {
272 /* get it as UTF-8 character for check */
273 const char *c = &in[offset];
274 uint32_t code = 0;
275 size_t code_len = 0;
276
277 LY_CHECK_ERR_GOTO(ly_getutf8(&c, &code, &code_len),
Radek Krejci2efc45b2020-12-22 16:25:44 +0100278 LOGVAL(jsonctx->ctx, LY_VCODE_INCHAR, in[offset]), error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200279
280 LY_CHECK_ERR_GOTO(!is_jsonstrchar(code),
Radek Krejci2efc45b2020-12-22 16:25:44 +0100281 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character in JSON string \"%.*s\" (0x%08x).",
Radek Krejci422afb12021-03-04 16:38:16 +0100282 (int)(&in[offset] - start + code_len), start, code),
Michal Vasko69730152020-10-09 16:30:07 +0200283 error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200284
285 /* character is ok, continue */
286 offset += code_len;
287 }
288 }
289
290 /* EOF reached before endchar */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100291 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
292 LOGVAL_LINE(jsonctx->ctx, start_line, LYVE_SYNTAX, "Missing quotation-mark at the end of a JSON string.");
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200293
294error:
295 free(buf);
296 return LY_EVALID;
297
298success:
Radek Krejcid54412f2020-12-17 20:25:35 +0100299 jsonctx->in->current = in;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200300 if (buf) {
301 lyjson_ctx_set_value(jsonctx, buf, len, 1);
302 } else {
303 lyjson_ctx_set_value(jsonctx, start, len, 0);
304 }
305
306 return LY_SUCCESS;
307
308#undef BUFSIZE
309#undef BUFSIZE_STEP
310}
311
312/*
313 *
314 * Wrapper around lyjson_string_() adding LYJSON_STRING status into context to allow using lyjson_string_() for parsing object's name.
315 */
316static LY_ERR
317lyjson_string(struct lyjson_ctx *jsonctx)
318{
319 LY_CHECK_RET(lyjson_string_(jsonctx));
320
321 JSON_PUSH_STATUS_RET(jsonctx, LYJSON_STRING);
322 LY_CHECK_RET(lyjson_check_next(jsonctx));
323
324 return LY_SUCCESS;
325}
326
aPieceke87c0a12021-05-13 15:43:26 +0200327/**
aPiecek76034c32021-06-08 15:03:11 +0200328 * @brief Calculate how many @p c characters there are in a row.
329 *
330 * @param[in] str Count from this position.
331 * @param[in] end Position after the last checked character.
332 * @param[in] c Checked character.
333 * @param[in] backwards Set to 1, if to proceed from end-1 to str.
334 * @return Number of characters in a row.
335 */
336static uint32_t
337lyjson_count_in_row(const char *str, const char *end, char c, ly_bool backwards)
338{
339 uint32_t cnt;
340
341 assert(str && end);
342
343 if (str >= end) {
344 return 0;
345 }
346
347 if (!backwards) {
348 for (cnt = 0; (str != end) && (*str == c); ++str, ++cnt) {}
349 } else {
350 --end;
351 --str;
352 for (cnt = 0; (str != end) && (*end == c); --end, ++cnt) {}
353 }
354
355 return cnt;
356}
357
358/**
359 * @brief Check if the number can be shortened to zero.
360 *
aPiecek76034c32021-06-08 15:03:11 +0200361 * @param[in] in Start of input string;
362 * @param[in] end End of input string;
363 * @return 1 if number is zero, otherwise 0.
364 */
365static ly_bool
366lyjson_number_is_zero(const char *in, const char *end)
367{
aPiecek28e101a2021-06-10 09:09:31 +0200368 assert(in < end);
aPiecek76034c32021-06-08 15:03:11 +0200369
370 if ((in[0] == '-') || (in[0] == '+')) {
371 in++;
aPiecek28e101a2021-06-10 09:09:31 +0200372 assert(in < end);
aPiecek76034c32021-06-08 15:03:11 +0200373 }
374 if ((in[0] == '0') && (in[1] == '.')) {
375 in += 2;
aPiecek28e101a2021-06-10 09:09:31 +0200376 if (!(in < end)) {
377 return 1;
378 }
aPiecek76034c32021-06-08 15:03:11 +0200379 }
380
381 return lyjson_count_in_row(in, end, '0', 0) == end - in;
382}
383
384/**
aPieceke87c0a12021-05-13 15:43:26 +0200385 * @brief Allocate buffer for number in string format.
386 *
387 * @param[in] jsonctx JSON context.
388 * @param[in] num_len Required space in bytes for a number.
389 * Terminating null byte is added by default.
390 * @param[out] buffer Output allocated buffer.
391 * @return LY_ERR value.
392 */
393static LY_ERR
aPiecek0ba088e2021-06-15 12:53:17 +0200394lyjson_get_buffer_for_number(const struct ly_ctx *ctx, uint64_t num_len, char **buffer)
aPieceke87c0a12021-05-13 15:43:26 +0200395{
396 *buffer = NULL;
397
aPiecek76034c32021-06-08 15:03:11 +0200398 LY_CHECK_ERR_RET((num_len + 1) > LY_NUMBER_MAXLEN, LOGVAL(ctx, LYVE_SEMANTICS,
aPieceke87c0a12021-05-13 15:43:26 +0200399 "Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit."), LY_EVALID);
400
aPiecek76034c32021-06-08 15:03:11 +0200401 /* allocate buffer for the result (add NULL-byte) */
aPieceke87c0a12021-05-13 15:43:26 +0200402 *buffer = malloc(num_len + 1);
aPiecek76034c32021-06-08 15:03:11 +0200403 LY_CHECK_ERR_RET(!(*buffer), LOGMEM(ctx), LY_EMEM);
404 return LY_SUCCESS;
405}
406
407/**
408 * @brief Copy the 'numeric part' (@p num) except its decimal point
409 * (@p dec_point) and insert the new decimal point (@p dp_position)
410 * only if it is to be placed in the 'numeric part' range (@p num).
411 *
412 * @param[in] num Begin of the 'numeric part'.
413 * @param[in] num_len Length of the 'numeric part'.
414 * @param[in] dec_point Pointer to the old decimal point.
415 * If it has a NULL value, it is ignored.
416 * @param[in] dp_position Position of the new decimal point.
417 * If it has a negative value, it is ignored.
418 * @param[out] dst Memory into which the copied result is written.
419 * @return Number of characters written to the @p dst.
420 */
421static uint32_t
422lyjson_exp_number_copy_num_part(const char *num, uint32_t num_len,
423 char *dec_point, int32_t dp_position, char *dst)
424{
425 int32_t dec_point_idx;
426 int32_t n, d;
427
428 assert(num && dst);
429
430 dec_point_idx = dec_point ? dec_point - num : INT32_MAX;
431 assert((dec_point_idx >= 0) && (dec_point_idx != dp_position));
432
433 for (n = 0, d = 0; (uint32_t)n < num_len; n++) {
434 if (n == dec_point_idx) {
435 continue;
436 } else if (d == dp_position) {
437 dst[d++] = '.';
438 dst[d++] = num[n];
439 } else {
440 dst[d++] = num[n];
441 }
442 }
443
444 return d;
445}
446
447/**
448 * @brief Convert JSON number with exponent into the representation
449 * used by YANG.
450 *
451 * The input numeric string must be syntactically valid. Also, before
452 * calling this function, checks should be performed using the
453 * ::lyjson_number_is_zero().
454 *
455 * @param[in] ctx Context for the error message.
456 * @param[in] in Beginning of the string containing the number.
457 * @param[in] exponent Pointer to the letter E/e.
458 * @param[in] total_len Total size of the input number.
459 * @param[out] res Conversion result.
460 * @param[out] res_len Length of the result.
461 * @return LY_ERR value.
462 */
463static LY_ERR
464lyjson_exp_number(const struct ly_ctx *ctx, const char *in, const char *exponent,
Michal Vaskoc10488f2021-07-23 12:45:20 +0200465 uint64_t total_len, char **res, size_t *res_len)
aPiecek76034c32021-06-08 15:03:11 +0200466{
467
468#define MAYBE_WRITE_MINUS(ARRAY, INDEX, FLAG) \
469 if (FLAG) { \
470 ARRAY[INDEX++] = '-'; \
471 }
472
473/* Length of leading zero followed by the decimal point. */
474#define LEADING_ZERO 1
475
476/* Flags for the ::lyjson_count_in_row() */
477#define FORWARD 0
478#define BACKWARD 1
479
480 /* Buffer where the result is stored. */
481 char *buf;
482 /* Size without space for terminating NULL-byte. */
aPiecek0ba088e2021-06-15 12:53:17 +0200483 uint64_t buf_len;
aPiecek76034c32021-06-08 15:03:11 +0200484 /* Index to buf. */
485 uint32_t i = 0;
486 /* A 'numeric part' doesn't contain a minus sign or an leading zero.
487 * For example, in 0.45, there is the leading zero.
488 */
489 const char *num;
490 /* Length of the 'numeric part' ends before E/e. */
aPiecek0ba088e2021-06-15 12:53:17 +0200491 uint16_t num_len;
aPiecek76034c32021-06-08 15:03:11 +0200492 /* Position of decimal point in the num. */
493 char *dec_point;
494 /* Final position of decimal point in the buf. */
495 int32_t dp_position;
496 /* Exponent as integer. */
Michal Vasko73d77ab2021-07-23 12:45:55 +0200497 long long int e_val;
aPiecek76034c32021-06-08 15:03:11 +0200498 /* Byte for the decimal point. */
499 int8_t dot;
500 /* Required additional byte for the minus sign. */
501 uint8_t minus;
502 /* The number of zeros. */
503 long zeros;
504 /* If the number starts with leading zero followed by the decimal point. */
505 ly_bool leading_zero;
506
507 assert(ctx && in && exponent && res && res_len && (total_len > 2));
508 assert((in < exponent) && ((*exponent == 'e') || (*exponent == 'E')));
509
aPiecek0ba088e2021-06-15 12:53:17 +0200510 if ((exponent - in) > UINT16_MAX) {
511 LOGVAL(ctx, LYVE_SEMANTICS, "JSON number is too long.");
512 return LY_EVALID;
513 }
514
aPiecek76034c32021-06-08 15:03:11 +0200515 /* Convert exponent. */
516 errno = 0;
Michal Vasko73d77ab2021-07-23 12:45:55 +0200517 e_val = strtoll(exponent + 1, NULL, LY_BASE_DEC);
aPieceke4e0d6c2021-07-01 12:02:54 +0200518 if (errno || (e_val > UINT16_MAX) || (e_val < -UINT16_MAX)) {
aPiecek76034c32021-06-08 15:03:11 +0200519 LOGVAL(ctx, LYVE_SEMANTICS,
520 "Exponent out-of-bounds in a JSON Number value (%.*s).",
Michal Vasko54ba8912021-07-23 12:46:23 +0200521 (int)total_len, in);
aPiecek76034c32021-06-08 15:03:11 +0200522 return LY_EVALID;
523 }
524
525 minus = in[0] == '-';
526 if (in[minus] == '0') {
527 assert(in[minus + 1] == '.');
528 leading_zero = 1;
529 /* The leading zero has been found, it will be skipped. */
530 num = &in[minus + 1];
531 } else {
532 leading_zero = 0;
533 /* Set to the first number. */
534 num = &in[minus];
535 }
536 num_len = exponent - num;
537
538 /* Find the location of the decimal points. */
539 dec_point = ly_strnchr(num, '.', num_len);
540 dp_position = dec_point ?
541 dec_point - num + e_val :
542 num_len + e_val;
543
544 /* Remove zeros after the decimal point from the end of
545 * the 'numeric part' because these are useless.
546 * (For example, in 40.001000 these are the last 3).
547 */
548 num_len -= dp_position > 0 ?
549 lyjson_count_in_row(num + dp_position - 1, exponent, '0', BACKWARD) :
550 lyjson_count_in_row(num, exponent, '0', BACKWARD);
551
552 /* Decide what to do with the dot from the 'numeric part'. */
553 if (dec_point && ((int32_t)(num_len - 1) == dp_position)) {
554 /* Decimal point in the last place is useless. */
555 dot = -1;
556 } else if (dec_point) {
557 /* Decimal point is shifted. */
558 dot = 0;
559 } else {
560 /* Additional byte for the decimal point is requred. */
561 dot = 1;
562 }
563
564 /* Final composition of the result. */
565 if (dp_position <= 0) {
566 /* Adding decimal point before the integer with adding additional zero(s). */
567
568 zeros = labs(dp_position);
569 buf_len = minus + LEADING_ZERO + dot + zeros + num_len;
570 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
571 MAYBE_WRITE_MINUS(buf, i, minus);
572 buf[i++] = '0';
573 buf[i++] = '.';
574 memset(buf + i, '0', zeros);
575 i += zeros;
576 dp_position = -1;
577 lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
578 } else if (leading_zero && (dp_position < (ssize_t)num_len)) {
579 /* Insert decimal point between the integer's digits. */
580
581 /* Set a new range of 'numeric part'. Old decimal point is skipped. */
582 num++;
583 num_len--;
584 dp_position--;
585 /* Get the number of useless zeros between the old
586 * and new decimal point. For example, in the number 0.005E1,
587 * there is one useless zero.
588 */
589 zeros = lyjson_count_in_row(num, num + dp_position + 1, '0', FORWARD);
590 /* If the new decimal point will be in the place of the first non-zero subnumber. */
591 if (zeros == (dp_position + 1)) {
592 /* keep one zero as leading zero */
593 zeros--;
594 /* new decimal point will be behind the leading zero */
595 dp_position = 1;
596 dot = 1;
597 } else {
598 dot = 0;
599 }
600 buf_len = minus + dot + (num_len - zeros);
601 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
602 MAYBE_WRITE_MINUS(buf, i, minus);
603 /* Skip useless zeros and copy. */
604 lyjson_exp_number_copy_num_part(num + zeros, num_len - zeros, NULL, dp_position, buf + i);
605 } else if (dp_position < (ssize_t)num_len) {
606 /* Insert decimal point between the integer's digits. */
607
608 buf_len = minus + dot + num_len;
609 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
610 MAYBE_WRITE_MINUS(buf, i, minus);
611 lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
612 } else if (leading_zero) {
613 /* Adding decimal point after the decimal value make the integer result. */
614
615 /* Set a new range of 'numeric part'. Old decimal point is skipped. */
616 num++;
617 num_len--;
618 /* Get the number of useless zeros. */
619 zeros = lyjson_count_in_row(num, num + num_len, '0', FORWARD);
620 buf_len = minus + dp_position - zeros;
621 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
622 MAYBE_WRITE_MINUS(buf, i, minus);
623 /* Skip useless zeros and copy. */
624 i += lyjson_exp_number_copy_num_part(num + zeros, num_len - zeros, NULL, dp_position, buf + i);
625 /* Add multiples of ten behind the 'numeric part'. */
626 memset(buf + i, '0', buf_len - i);
627 } else {
628 /* Adding decimal point after the decimal value make the integer result. */
629
630 buf_len = minus + dp_position;
631 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
632 MAYBE_WRITE_MINUS(buf, i, minus);
633 i += lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
634 /* Add multiples of ten behind the 'numeric part'. */
635 memset(buf + i, '0', buf_len - i);
636 }
637
638 buf[buf_len] = '\0';
639 *res = buf;
640 *res_len = buf_len;
641
642#undef MAYBE_WRITE_MINUS
643#undef LEADING_ZERO
644#undef FORWARD
645#undef BACKWARD
646
aPieceke87c0a12021-05-13 15:43:26 +0200647 return LY_SUCCESS;
648}
649
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200650static LY_ERR
651lyjson_number(struct lyjson_ctx *jsonctx)
652{
aPiecek76034c32021-06-08 15:03:11 +0200653 size_t offset = 0, num_len;
654 const char *in = jsonctx->in->current, *exponent = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200655 uint8_t minus = 0;
aPiecek76034c32021-06-08 15:03:11 +0200656 char *num;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200657
658 if (in[offset] == '-') {
659 ++offset;
660 minus = 1;
661 }
662
663 if (in[offset] == '0') {
664 ++offset;
665 } else if (isdigit(in[offset])) {
666 ++offset;
667 while (isdigit(in[offset])) {
668 ++offset;
669 }
670 } else {
671invalid_character:
672 if (in[offset]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100673 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character in JSON Number value (\"%c\").", in[offset]);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200674 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100675 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200676 }
677 return LY_EVALID;
678 }
679
680 if (in[offset] == '.') {
681 ++offset;
682 if (!isdigit(in[offset])) {
683 goto invalid_character;
684 }
685 while (isdigit(in[offset])) {
686 ++offset;
687 }
688 }
689
690 if ((in[offset] == 'e') || (in[offset] == 'E')) {
aPiecek76034c32021-06-08 15:03:11 +0200691 exponent = &in[offset];
692 ++offset;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200693 if ((in[offset] == '+') || (in[offset] == '-')) {
694 ++offset;
695 }
696 if (!isdigit(in[offset])) {
697 goto invalid_character;
698 }
699 while (isdigit(in[offset])) {
700 ++offset;
701 }
702 }
703
aPiecek76034c32021-06-08 15:03:11 +0200704 if (lyjson_number_is_zero(in, exponent ? exponent : &in[offset])) {
705 lyjson_ctx_set_value(jsonctx, in, minus + 1, 0);
706 } else if (exponent && lyjson_number_is_zero(exponent + 1, &in[offset])) {
707 lyjson_ctx_set_value(jsonctx, in, exponent - in, 0);
708 } else if (exponent) {
709 LY_CHECK_RET(lyjson_exp_number(jsonctx->ctx, in, exponent, offset, &num, &num_len));
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200710 lyjson_ctx_set_value(jsonctx, num, num_len, 1);
711 } else {
aPiecek5b6dd182021-06-10 09:11:58 +0200712 if (offset > LY_NUMBER_MAXLEN) {
713 LOGVAL(jsonctx->ctx, LYVE_SEMANTICS,
714 "Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit.");
715 return LY_EVALID;
716 }
aPiecek76034c32021-06-08 15:03:11 +0200717 lyjson_ctx_set_value(jsonctx, in, offset, 0);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200718 }
719 ly_in_skip(jsonctx->in, offset);
720
721 JSON_PUSH_STATUS_RET(jsonctx, LYJSON_NUMBER);
722 LY_CHECK_RET(lyjson_check_next(jsonctx));
723
724 return LY_SUCCESS;
725}
726
727static LY_ERR
728lyjson_object_name(struct lyjson_ctx *jsonctx)
729{
730 if (*jsonctx->in->current != '"') {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100731 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
Michal Vasko69730152020-10-09 16:30:07 +0200732 jsonctx->in->current, "a JSON object's member");
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200733 return LY_EVALID;
734 }
735 ly_in_skip(jsonctx->in, 1);
736
737 LY_CHECK_RET(lyjson_string_(jsonctx));
738 LY_CHECK_RET(skip_ws(jsonctx));
Michal Vasko08dc70b2020-10-07 13:58:47 +0200739 if (*jsonctx->in->current != ':') {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100740 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
741 "a JSON object's name-separator ':'");
Michal Vasko08dc70b2020-10-07 13:58:47 +0200742 return LY_EVALID;
743 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200744 ly_in_skip(jsonctx->in, 1);
745 LY_CHECK_RET(skip_ws(jsonctx));
746
747 return LY_SUCCESS;
748}
749
750static LY_ERR
751lyjson_object(struct lyjson_ctx *jsonctx)
752{
753 LY_CHECK_RET(skip_ws(jsonctx));
754
755 if (*jsonctx->in->current == '}') {
aPiecek93582ed2021-05-25 14:49:06 +0200756 assert(jsonctx->depth);
757 jsonctx->depth--;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200758 /* empty object */
759 ly_in_skip(jsonctx->in, 1);
760 lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
761 JSON_PUSH_STATUS_RET(jsonctx, LYJSON_OBJECT_EMPTY);
762 return LY_SUCCESS;
763 }
764
765 LY_CHECK_RET(lyjson_object_name(jsonctx));
766
767 /* output data are set by lyjson_string_() */
768 JSON_PUSH_STATUS_RET(jsonctx, LYJSON_OBJECT);
769
770 return LY_SUCCESS;
771}
772
773/*
774 * @brief Process JSON array envelope
775 *
776 *
777 *
778 * @param[in] jsonctx JSON parser context
779 * @return LY_SUCCESS or LY_EMEM
780 */
781static LY_ERR
782lyjson_array(struct lyjson_ctx *jsonctx)
783{
784 LY_CHECK_RET(skip_ws(jsonctx));
785
786 if (*jsonctx->in->current == ']') {
787 /* empty array */
788 ly_in_skip(jsonctx->in, 1);
789 JSON_PUSH_STATUS_RET(jsonctx, LYJSON_ARRAY_EMPTY);
790 } else {
791 JSON_PUSH_STATUS_RET(jsonctx, LYJSON_ARRAY);
792 }
793
794 /* erase previous values, array has no value on its own */
795 lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
796
797 return LY_SUCCESS;
798}
799
800static LY_ERR
801lyjson_value(struct lyjson_ctx *jsonctx)
802{
Michal Vasko69730152020-10-09 16:30:07 +0200803 if (jsonctx->status.count && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200804 return LY_SUCCESS;
805 }
806
Radek Krejcif13b87b2020-12-01 22:02:17 +0100807 if ((*jsonctx->in->current == 'f') && !strncmp(jsonctx->in->current, "false", ly_strlen_const("false"))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200808 /* false */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100809 lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("false"), 0);
810 ly_in_skip(jsonctx->in, ly_strlen_const("false"));
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200811 JSON_PUSH_STATUS_RET(jsonctx, LYJSON_FALSE);
812 LY_CHECK_RET(lyjson_check_next(jsonctx));
813
Radek Krejcif13b87b2020-12-01 22:02:17 +0100814 } else if ((*jsonctx->in->current == 't') && !strncmp(jsonctx->in->current, "true", ly_strlen_const("true"))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200815 /* true */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100816 lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("true"), 0);
817 ly_in_skip(jsonctx->in, ly_strlen_const("true"));
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200818 JSON_PUSH_STATUS_RET(jsonctx, LYJSON_TRUE);
819 LY_CHECK_RET(lyjson_check_next(jsonctx));
820
Radek Krejcif13b87b2020-12-01 22:02:17 +0100821 } else if ((*jsonctx->in->current == 'n') && !strncmp(jsonctx->in->current, "null", ly_strlen_const("null"))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200822 /* none */
Radek Krejci201963a2020-12-03 11:43:40 +0100823 lyjson_ctx_set_value(jsonctx, "", 0, 0);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100824 ly_in_skip(jsonctx->in, ly_strlen_const("null"));
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200825 JSON_PUSH_STATUS_RET(jsonctx, LYJSON_NULL);
826 LY_CHECK_RET(lyjson_check_next(jsonctx));
827
828 } else if (*jsonctx->in->current == '"') {
829 /* string */
830 ly_in_skip(jsonctx->in, 1);
831 LY_CHECK_RET(lyjson_string(jsonctx));
832
833 } else if (*jsonctx->in->current == '[') {
834 /* array */
835 ly_in_skip(jsonctx->in, 1);
836 LY_CHECK_RET(lyjson_array(jsonctx));
837
838 } else if (*jsonctx->in->current == '{') {
aPiecek93582ed2021-05-25 14:49:06 +0200839 jsonctx->depth++;
840 if (jsonctx->depth > LY_MAX_BLOCK_DEPTH) {
841 LOGERR(jsonctx->ctx, LY_EINVAL,
842 "The maximum number of block nestings has been exceeded.");
843 return LY_EINVAL;
844 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200845 /* object */
846 ly_in_skip(jsonctx->in, 1);
847 LY_CHECK_RET(lyjson_object(jsonctx));
848
Michal Vasko69730152020-10-09 16:30:07 +0200849 } else if ((*jsonctx->in->current == '-') || ((*jsonctx->in->current >= '0') && (*jsonctx->in->current <= '9'))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200850 /* number */
851 LY_CHECK_RET(lyjson_number(jsonctx));
852
853 } else {
854 /* unexpected value */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100855 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
Michal Vasko69730152020-10-09 16:30:07 +0200856 jsonctx->in->current, "a JSON value");
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200857 return LY_EVALID;
858 }
859
860 return LY_SUCCESS;
861}
862
863LY_ERR
864lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, struct lyjson_ctx **jsonctx_p)
865{
866 LY_ERR ret = LY_SUCCESS;
867 struct lyjson_ctx *jsonctx;
868
869 assert(ctx);
870 assert(in);
871 assert(jsonctx_p);
872
873 /* new context */
874 jsonctx = calloc(1, sizeof *jsonctx);
875 LY_CHECK_ERR_RET(!jsonctx, LOGMEM(ctx), LY_EMEM);
876 jsonctx->ctx = ctx;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200877 jsonctx->in = in;
878
Radek Krejciddace2c2021-01-08 11:30:56 +0100879 LOG_LOCINIT(NULL, NULL, NULL, in);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100880
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200881 /* parse JSON value, if any */
882 LY_CHECK_GOTO(ret = skip_ws(jsonctx), cleanup);
883 if (lyjson_ctx_status(jsonctx, 0) == LYJSON_END) {
884 /* empty data input */
885 goto cleanup;
886 }
887
888 ret = lyjson_value(jsonctx);
889
Michal Vasko69730152020-10-09 16:30:07 +0200890 if ((jsonctx->status.count > 1) && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100891 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200892 ret = LY_EVALID;
893 }
894
895cleanup:
896 if (ret) {
897 lyjson_ctx_free(jsonctx);
898 } else {
899 *jsonctx_p = jsonctx;
900 }
901 return ret;
902}
903
904void
905lyjson_ctx_backup(struct lyjson_ctx *jsonctx)
906{
907 if (jsonctx->backup.dynamic) {
908 free((char *)jsonctx->backup.value);
909 }
910 jsonctx->backup.status = lyjson_ctx_status(jsonctx, 0);
911 jsonctx->backup.status_count = jsonctx->status.count;
912 jsonctx->backup.value = jsonctx->value;
913 jsonctx->backup.value_len = jsonctx->value_len;
914 jsonctx->backup.input = jsonctx->in->current;
915 jsonctx->backup.dynamic = jsonctx->dynamic;
aPiecek93582ed2021-05-25 14:49:06 +0200916 jsonctx->backup.depth = jsonctx->depth;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200917 jsonctx->dynamic = 0;
918}
919
920void
921lyjson_ctx_restore(struct lyjson_ctx *jsonctx)
922{
923 if (jsonctx->dynamic) {
924 free((char *)jsonctx->value);
925 }
926 jsonctx->status.count = jsonctx->backup.status_count;
Michal Vasko22df3f02020-08-24 13:29:22 +0200927 jsonctx->status.objs[jsonctx->backup.status_count - 1] = (void *)jsonctx->backup.status;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200928 jsonctx->value = jsonctx->backup.value;
929 jsonctx->value_len = jsonctx->backup.value_len;
930 jsonctx->in->current = jsonctx->backup.input;
931 jsonctx->dynamic = jsonctx->backup.dynamic;
aPiecek93582ed2021-05-25 14:49:06 +0200932 jsonctx->depth = jsonctx->backup.depth;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200933 jsonctx->backup.dynamic = 0;
934}
935
936LY_ERR
937lyjson_ctx_next(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status)
938{
939 LY_ERR ret = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +0200940 ly_bool toplevel = 0;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200941 enum LYJSON_PARSER_STATUS prev;
942
943 assert(jsonctx);
944
945 prev = lyjson_ctx_status(jsonctx, 0);
946
Michal Vasko69730152020-10-09 16:30:07 +0200947 if ((prev == LYJSON_OBJECT) || (prev == LYJSON_ARRAY)) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200948 /* get value for the object's member OR the first value in the array */
949 ret = lyjson_value(jsonctx);
950 goto result;
951 } else {
952 /* the previous token is closed and should be completely processed */
953 JSON_POP_STATUS_RET(jsonctx);
954 prev = lyjson_ctx_status(jsonctx, 0);
955 }
956
957 if (!jsonctx->status.count) {
958 /* we are done with the top level value */
959 toplevel = 1;
960 }
961 LY_CHECK_RET(skip_ws(jsonctx));
962 if (toplevel && !jsonctx->status.count) {
963 /* EOF expected, but there are some data after the top level token */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100964 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Expecting end-of-input, but some data follows the top level JSON value.");
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200965 return LY_EVALID;
966 }
967
968 if (toplevel) {
969 /* we are done */
970 return LY_SUCCESS;
971 }
972
973 /* continue with the next token */
974 assert(prev == LYJSON_OBJECT || prev == LYJSON_ARRAY);
975
976 if (*jsonctx->in->current == ',') {
977 /* sibling item in the ... */
978 ly_in_skip(jsonctx->in, 1);
979 LY_CHECK_RET(skip_ws(jsonctx));
980
981 if (prev == LYJSON_OBJECT) {
982 /* ... object - get another object's member */
983 ret = lyjson_object_name(jsonctx);
984 } else { /* LYJSON_ARRAY */
985 /* ... array - get another complete value */
986 ret = lyjson_value(jsonctx);
987 }
Michal Vasko69730152020-10-09 16:30:07 +0200988 } else if (((prev == LYJSON_OBJECT) && (*jsonctx->in->current == '}')) || ((prev == LYJSON_ARRAY) && (*jsonctx->in->current == ']'))) {
aPiecek93582ed2021-05-25 14:49:06 +0200989 if (*jsonctx->in->current == '}') {
990 assert(jsonctx->depth);
991 jsonctx->depth--;
992 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200993 ly_in_skip(jsonctx->in, 1);
994 JSON_POP_STATUS_RET(jsonctx);
995 JSON_PUSH_STATUS_RET(jsonctx, prev + 1);
996 } else {
997 /* unexpected value */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100998 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
999 prev == LYJSON_ARRAY ? "another JSON value in array" : "another JSON object's member");
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001000 return LY_EVALID;
1001 }
1002
1003result:
Michal Vasko69730152020-10-09 16:30:07 +02001004 if ((ret == LY_SUCCESS) && (jsonctx->status.count > 1) && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001005 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001006 ret = LY_EVALID;
1007 }
1008
Michal Vasko69730152020-10-09 16:30:07 +02001009 if ((ret == LY_SUCCESS) && status) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001010 *status = lyjson_ctx_status(jsonctx, 0);
1011 }
1012
1013 return ret;
1014}
1015
1016enum LYJSON_PARSER_STATUS
1017lyjson_ctx_status(struct lyjson_ctx *jsonctx, uint32_t index)
1018{
1019 assert(jsonctx);
1020
1021 if (jsonctx->status.count < index) {
1022 return LYJSON_ERROR;
1023 } else if (jsonctx->status.count == index) {
1024 return LYJSON_ROOT;
1025 } else {
Michal Vasko27915722020-08-31 14:54:42 +02001026 return (enum LYJSON_PARSER_STATUS)(uintptr_t)jsonctx->status.objs[jsonctx->status.count - (index + 1)];
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001027 }
1028}
1029
1030void
1031lyjson_ctx_free(struct lyjson_ctx *jsonctx)
1032{
1033 if (!jsonctx) {
1034 return;
1035 }
1036
Radek Krejciddace2c2021-01-08 11:30:56 +01001037 LOG_LOCBACK(0, 0, 0, 1);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001038
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001039 if (jsonctx->dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +02001040 free((char *)jsonctx->value);
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001041 }
1042 if (jsonctx->backup.dynamic) {
1043 free((char *)jsonctx->backup.value);
1044 }
1045
1046 ly_set_erase(&jsonctx->status, NULL);
1047
1048 free(jsonctx);
1049}