blob: cbe38e9329a957824ba557fbaf2e46063bc9db07 [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
Michal Vasko22df3f02020-08-24 13:29:22 +020027const char *
Radek Krejci50f0c6b2020-06-18 16:31:48 +020028lyjson_token2str(enum LYJSON_PARSER_STATUS status)
29{
30 switch (status) {
31 case LYJSON_ERROR:
32 return "error";
33 case LYJSON_ROOT:
34 return "document root";
35 case LYJSON_FALSE:
36 return "false";
37 case LYJSON_TRUE:
38 return "true";
39 case LYJSON_NULL:
40 return "null";
41 case LYJSON_OBJECT:
42 return "object";
43 case LYJSON_OBJECT_CLOSED:
44 return "object closed";
45 case LYJSON_OBJECT_EMPTY:
46 return "empty object";
47 case LYJSON_ARRAY:
48 return "array";
49 case LYJSON_ARRAY_CLOSED:
50 return "array closed";
51 case LYJSON_ARRAY_EMPTY:
52 return "empty array";
53 case LYJSON_NUMBER:
54 return "number";
55 case LYJSON_STRING:
56 return "string";
57 case LYJSON_END:
58 return "end of input";
59 }
60
61 return "";
62}
63
64static LY_ERR
65skip_ws(struct lyjson_ctx *jsonctx)
66{
67 /* skip leading whitespaces */
68 while (*jsonctx->in->current != '\0' && is_jsonws(*jsonctx->in->current)) {
Radek Krejcidd713ce2021-01-04 23:12:12 +010069 if (*jsonctx->in->current == '\n') {
70 LY_IN_NEW_LINE(jsonctx->in);
71 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +020072 ly_in_skip(jsonctx->in, 1);
73 }
74 if (*jsonctx->in->current == '\0') {
Michal Vasko61ad1ff2022-02-10 15:48:39 +010075 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_END);
Radek Krejci50f0c6b2020-06-18 16:31:48 +020076 }
77
78 return LY_SUCCESS;
79}
80
81/*
82 * @brief Set value corresponding to the current context's status
83 */
84static void
Radek Krejci857189e2020-09-01 13:26:36 +020085lyjson_ctx_set_value(struct lyjson_ctx *jsonctx, const char *value, size_t value_len, ly_bool dynamic)
Radek Krejci50f0c6b2020-06-18 16:31:48 +020086{
87 assert(jsonctx);
88
Juraj Vijtiukec285cd2021-01-14 11:41:20 +010089 if (jsonctx->dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +020090 free((char *)jsonctx->value);
Radek Krejci50f0c6b2020-06-18 16:31:48 +020091 }
92 jsonctx->value = value;
93 jsonctx->value_len = value_len;
94 jsonctx->dynamic = dynamic;
95}
96
97static LY_ERR
98lyjson_check_next(struct lyjson_ctx *jsonctx)
99{
100 if (jsonctx->status.count == 1) {
101 /* top level value (JSON-text), ws expected */
Michal Vasko69730152020-10-09 16:30:07 +0200102 if ((*jsonctx->in->current == '\0') || is_jsonws(*jsonctx->in->current)) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200103 return LY_SUCCESS;
104 }
105 } else if (lyjson_ctx_status(jsonctx, 1) == LYJSON_OBJECT) {
106 LY_CHECK_RET(skip_ws(jsonctx));
Michal Vasko69730152020-10-09 16:30:07 +0200107 if ((*jsonctx->in->current == ',') || (*jsonctx->in->current == '}')) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200108 return LY_SUCCESS;
109 }
110 } else if (lyjson_ctx_status(jsonctx, 1) == LYJSON_ARRAY) {
111 LY_CHECK_RET(skip_ws(jsonctx));
Michal Vasko69730152020-10-09 16:30:07 +0200112 if ((*jsonctx->in->current == ',') || (*jsonctx->in->current == ']')) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200113 return LY_SUCCESS;
114 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200115 }
116
Radek Krejcie7010dc2021-03-04 15:54:24 +0100117 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Unexpected character \"%c\" after JSON %s.",
118 *jsonctx->in->current, lyjson_token2str(lyjson_ctx_status(jsonctx, 0)));
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200119 return LY_EVALID;
120}
121
122/**
123 * Input is expected to start after the opening quotation-mark.
124 * When succeeds, input is moved after the closing quotation-mark.
125 */
126static LY_ERR
127lyjson_string_(struct lyjson_ctx *jsonctx)
128{
129#define BUFSIZE 24
130#define BUFSIZE_STEP 128
131
132 const char *in = jsonctx->in->current, *start;
133 char *buf = NULL;
134 size_t offset; /* read offset in input buffer */
135 size_t len; /* length of the output string (write offset in output buffer) */
136 size_t size = 0; /* size of the output buffer */
137 size_t u;
138 uint64_t start_line;
139
140 assert(jsonctx);
141
142 /* init */
143 start = in;
Radek Krejcid54412f2020-12-17 20:25:35 +0100144 start_line = jsonctx->in->line;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200145 offset = len = 0;
146
147 /* parse */
148 while (in[offset]) {
149 if (in[offset] == '\\') {
150 /* escape sequence */
Michal Vasko2be1d762021-03-11 16:53:15 +0100151 const char *slash = &in[offset];
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200152 uint32_t value;
153 uint8_t i = 1;
154
155 if (!buf) {
156 /* prepare output buffer */
157 buf = malloc(BUFSIZE);
158 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
159 size = BUFSIZE;
160 }
161
162 /* allocate enough for the offset and next character,
163 * we will need 4 bytes at most since we support only the predefined
164 * (one-char) entities and character references */
165 if (len + offset + 4 >= size) {
Juraj Vijtiukd746a352021-01-15 11:33:33 +0100166 size_t increment;
Radek Krejcidf549132021-01-21 10:32:32 +0100167 for (increment = BUFSIZE_STEP; len + offset + 4 >= size + increment; increment += BUFSIZE_STEP) {}
Juraj Vijtiukd746a352021-01-15 11:33:33 +0100168 buf = ly_realloc(buf, size + increment);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200169 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
170 size += BUFSIZE_STEP;
171 }
172
173 if (offset) {
174 /* store what we have so far */
175 memcpy(&buf[len], in, offset);
176 len += offset;
177 in += offset;
178 offset = 0;
179 }
180
181 switch (in[++offset]) {
182 case '"':
183 /* quotation mark */
184 value = 0x22;
185 break;
186 case '\\':
187 /* reverse solidus */
188 value = 0x5c;
189 break;
190 case '/':
191 /* solidus */
192 value = 0x2f;
193 break;
194 case 'b':
195 /* backspace */
196 value = 0x08;
197 break;
198 case 'f':
199 /* form feed */
200 value = 0x0c;
201 break;
202 case 'n':
203 /* line feed */
204 value = 0x0a;
205 break;
206 case 'r':
207 /* carriage return */
208 value = 0x0d;
209 break;
210 case 't':
211 /* tab */
212 value = 0x09;
213 break;
214 case 'u':
215 /* Basic Multilingual Plane character \uXXXX */
216 offset++;
217 for (value = i = 0; i < 4; i++) {
Juraj Vijtiuk2b94e4b2020-11-16 23:52:07 +0100218 if (!in[offset + i]) {
Michal Vasko2be1d762021-03-11 16:53:15 +0100219 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid basic multilingual plane character \"%s\".", slash);
Juraj Vijtiuk2b94e4b2020-11-16 23:52:07 +0100220 goto error;
221 } else if (isdigit(in[offset + i])) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200222 u = (in[offset + i] - '0');
223 } else if (in[offset + i] > 'F') {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100224 u = LY_BASE_DEC + (in[offset + i] - 'a');
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200225 } else {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100226 u = LY_BASE_DEC + (in[offset + i] - 'A');
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200227 }
Radek Krejcif13b87b2020-12-01 22:02:17 +0100228 value = (LY_BASE_HEX * value) + u;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200229 }
230 break;
231 default:
232 /* invalid escape sequence */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100233 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character escape sequence \\%c.", in[offset]);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200234 goto error;
235
236 }
237
238 offset += i; /* add read escaped characters */
239 LY_CHECK_ERR_GOTO(ly_pututf8(&buf[len], value, &u),
Radek Krejci2efc45b2020-12-22 16:25:44 +0100240 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character reference \"%.*s\" (0x%08x).",
Michal Vasko2be1d762021-03-11 16:53:15 +0100241 (int)(&in[offset] - slash), slash, value),
Michal Vasko69730152020-10-09 16:30:07 +0200242 error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200243 len += u; /* update number of bytes in buffer */
244 in += offset; /* move the input by the processed bytes stored in the buffer ... */
245 offset = 0; /* ... and reset the offset index for future moving data into buffer */
246
247 } else if (in[offset] == '"') {
248 /* end of string */
249 if (buf) {
250 /* realloc exact size string */
251 buf = ly_realloc(buf, len + offset + 1);
252 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
253 size = len + offset + 1;
Michal Vasko08e9b112021-06-11 15:41:17 +0200254 if (offset) {
255 memcpy(&buf[len], in, offset);
256 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200257
258 /* set terminating NULL byte */
259 buf[len + offset] = '\0';
260 }
261 len += offset;
262 ++offset;
263 in += offset;
264 goto success;
265 } else {
266 /* get it as UTF-8 character for check */
267 const char *c = &in[offset];
268 uint32_t code = 0;
269 size_t code_len = 0;
270
271 LY_CHECK_ERR_GOTO(ly_getutf8(&c, &code, &code_len),
Radek Krejci2efc45b2020-12-22 16:25:44 +0100272 LOGVAL(jsonctx->ctx, LY_VCODE_INCHAR, in[offset]), error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200273
274 LY_CHECK_ERR_GOTO(!is_jsonstrchar(code),
Radek Krejci2efc45b2020-12-22 16:25:44 +0100275 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character in JSON string \"%.*s\" (0x%08x).",
Radek Krejci422afb12021-03-04 16:38:16 +0100276 (int)(&in[offset] - start + code_len), start, code),
Michal Vasko69730152020-10-09 16:30:07 +0200277 error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200278
279 /* character is ok, continue */
280 offset += code_len;
281 }
282 }
283
284 /* EOF reached before endchar */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100285 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
286 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 +0200287
288error:
289 free(buf);
290 return LY_EVALID;
291
292success:
Radek Krejcid54412f2020-12-17 20:25:35 +0100293 jsonctx->in->current = in;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200294 if (buf) {
295 lyjson_ctx_set_value(jsonctx, buf, len, 1);
296 } else {
297 lyjson_ctx_set_value(jsonctx, start, len, 0);
298 }
299
300 return LY_SUCCESS;
301
302#undef BUFSIZE
303#undef BUFSIZE_STEP
304}
305
306/*
307 *
308 * Wrapper around lyjson_string_() adding LYJSON_STRING status into context to allow using lyjson_string_() for parsing object's name.
309 */
310static LY_ERR
311lyjson_string(struct lyjson_ctx *jsonctx)
312{
313 LY_CHECK_RET(lyjson_string_(jsonctx));
314
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100315 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_STRING);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200316 LY_CHECK_RET(lyjson_check_next(jsonctx));
317
318 return LY_SUCCESS;
319}
320
aPieceke87c0a12021-05-13 15:43:26 +0200321/**
aPiecek76034c32021-06-08 15:03:11 +0200322 * @brief Calculate how many @p c characters there are in a row.
323 *
324 * @param[in] str Count from this position.
325 * @param[in] end Position after the last checked character.
326 * @param[in] c Checked character.
327 * @param[in] backwards Set to 1, if to proceed from end-1 to str.
328 * @return Number of characters in a row.
329 */
330static uint32_t
331lyjson_count_in_row(const char *str, const char *end, char c, ly_bool backwards)
332{
333 uint32_t cnt;
334
335 assert(str && end);
336
337 if (str >= end) {
338 return 0;
339 }
340
341 if (!backwards) {
342 for (cnt = 0; (str != end) && (*str == c); ++str, ++cnt) {}
343 } else {
344 --end;
345 --str;
346 for (cnt = 0; (str != end) && (*end == c); --end, ++cnt) {}
347 }
348
349 return cnt;
350}
351
352/**
353 * @brief Check if the number can be shortened to zero.
354 *
aPiecek76034c32021-06-08 15:03:11 +0200355 * @param[in] in Start of input string;
356 * @param[in] end End of input string;
357 * @return 1 if number is zero, otherwise 0.
358 */
359static ly_bool
360lyjson_number_is_zero(const char *in, const char *end)
361{
aPiecek28e101a2021-06-10 09:09:31 +0200362 assert(in < end);
aPiecek76034c32021-06-08 15:03:11 +0200363
364 if ((in[0] == '-') || (in[0] == '+')) {
365 in++;
aPiecek28e101a2021-06-10 09:09:31 +0200366 assert(in < end);
aPiecek76034c32021-06-08 15:03:11 +0200367 }
368 if ((in[0] == '0') && (in[1] == '.')) {
369 in += 2;
aPiecek28e101a2021-06-10 09:09:31 +0200370 if (!(in < end)) {
371 return 1;
372 }
aPiecek76034c32021-06-08 15:03:11 +0200373 }
374
375 return lyjson_count_in_row(in, end, '0', 0) == end - in;
376}
377
378/**
aPieceke87c0a12021-05-13 15:43:26 +0200379 * @brief Allocate buffer for number in string format.
380 *
381 * @param[in] jsonctx JSON context.
382 * @param[in] num_len Required space in bytes for a number.
383 * Terminating null byte is added by default.
384 * @param[out] buffer Output allocated buffer.
385 * @return LY_ERR value.
386 */
387static LY_ERR
aPiecek0ba088e2021-06-15 12:53:17 +0200388lyjson_get_buffer_for_number(const struct ly_ctx *ctx, uint64_t num_len, char **buffer)
aPieceke87c0a12021-05-13 15:43:26 +0200389{
390 *buffer = NULL;
391
aPiecek76034c32021-06-08 15:03:11 +0200392 LY_CHECK_ERR_RET((num_len + 1) > LY_NUMBER_MAXLEN, LOGVAL(ctx, LYVE_SEMANTICS,
aPieceke87c0a12021-05-13 15:43:26 +0200393 "Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit."), LY_EVALID);
394
aPiecek76034c32021-06-08 15:03:11 +0200395 /* allocate buffer for the result (add NULL-byte) */
aPieceke87c0a12021-05-13 15:43:26 +0200396 *buffer = malloc(num_len + 1);
aPiecek76034c32021-06-08 15:03:11 +0200397 LY_CHECK_ERR_RET(!(*buffer), LOGMEM(ctx), LY_EMEM);
398 return LY_SUCCESS;
399}
400
401/**
402 * @brief Copy the 'numeric part' (@p num) except its decimal point
403 * (@p dec_point) and insert the new decimal point (@p dp_position)
404 * only if it is to be placed in the 'numeric part' range (@p num).
405 *
406 * @param[in] num Begin of the 'numeric part'.
407 * @param[in] num_len Length of the 'numeric part'.
408 * @param[in] dec_point Pointer to the old decimal point.
409 * If it has a NULL value, it is ignored.
410 * @param[in] dp_position Position of the new decimal point.
411 * If it has a negative value, it is ignored.
412 * @param[out] dst Memory into which the copied result is written.
413 * @return Number of characters written to the @p dst.
414 */
415static uint32_t
416lyjson_exp_number_copy_num_part(const char *num, uint32_t num_len,
417 char *dec_point, int32_t dp_position, char *dst)
418{
419 int32_t dec_point_idx;
420 int32_t n, d;
421
422 assert(num && dst);
423
424 dec_point_idx = dec_point ? dec_point - num : INT32_MAX;
425 assert((dec_point_idx >= 0) && (dec_point_idx != dp_position));
426
427 for (n = 0, d = 0; (uint32_t)n < num_len; n++) {
428 if (n == dec_point_idx) {
429 continue;
430 } else if (d == dp_position) {
431 dst[d++] = '.';
432 dst[d++] = num[n];
433 } else {
434 dst[d++] = num[n];
435 }
436 }
437
438 return d;
439}
440
441/**
442 * @brief Convert JSON number with exponent into the representation
443 * used by YANG.
444 *
445 * The input numeric string must be syntactically valid. Also, before
446 * calling this function, checks should be performed using the
447 * ::lyjson_number_is_zero().
448 *
449 * @param[in] ctx Context for the error message.
450 * @param[in] in Beginning of the string containing the number.
451 * @param[in] exponent Pointer to the letter E/e.
452 * @param[in] total_len Total size of the input number.
453 * @param[out] res Conversion result.
454 * @param[out] res_len Length of the result.
455 * @return LY_ERR value.
456 */
457static LY_ERR
458lyjson_exp_number(const struct ly_ctx *ctx, const char *in, const char *exponent,
Michal Vaskoc10488f2021-07-23 12:45:20 +0200459 uint64_t total_len, char **res, size_t *res_len)
aPiecek76034c32021-06-08 15:03:11 +0200460{
461
462#define MAYBE_WRITE_MINUS(ARRAY, INDEX, FLAG) \
463 if (FLAG) { \
464 ARRAY[INDEX++] = '-'; \
465 }
466
467/* Length of leading zero followed by the decimal point. */
468#define LEADING_ZERO 1
469
470/* Flags for the ::lyjson_count_in_row() */
471#define FORWARD 0
472#define BACKWARD 1
473
474 /* Buffer where the result is stored. */
475 char *buf;
476 /* Size without space for terminating NULL-byte. */
aPiecek0ba088e2021-06-15 12:53:17 +0200477 uint64_t buf_len;
aPiecek76034c32021-06-08 15:03:11 +0200478 /* Index to buf. */
479 uint32_t i = 0;
480 /* A 'numeric part' doesn't contain a minus sign or an leading zero.
481 * For example, in 0.45, there is the leading zero.
482 */
483 const char *num;
484 /* Length of the 'numeric part' ends before E/e. */
aPiecek0ba088e2021-06-15 12:53:17 +0200485 uint16_t num_len;
aPiecek76034c32021-06-08 15:03:11 +0200486 /* Position of decimal point in the num. */
487 char *dec_point;
488 /* Final position of decimal point in the buf. */
489 int32_t dp_position;
490 /* Exponent as integer. */
Michal Vasko73d77ab2021-07-23 12:45:55 +0200491 long long int e_val;
aPiecek76034c32021-06-08 15:03:11 +0200492 /* Byte for the decimal point. */
493 int8_t dot;
494 /* Required additional byte for the minus sign. */
495 uint8_t minus;
496 /* The number of zeros. */
497 long zeros;
498 /* If the number starts with leading zero followed by the decimal point. */
499 ly_bool leading_zero;
500
501 assert(ctx && in && exponent && res && res_len && (total_len > 2));
502 assert((in < exponent) && ((*exponent == 'e') || (*exponent == 'E')));
503
aPiecek0ba088e2021-06-15 12:53:17 +0200504 if ((exponent - in) > UINT16_MAX) {
505 LOGVAL(ctx, LYVE_SEMANTICS, "JSON number is too long.");
506 return LY_EVALID;
507 }
508
aPiecek76034c32021-06-08 15:03:11 +0200509 /* Convert exponent. */
510 errno = 0;
Michal Vasko73d77ab2021-07-23 12:45:55 +0200511 e_val = strtoll(exponent + 1, NULL, LY_BASE_DEC);
aPieceke4e0d6c2021-07-01 12:02:54 +0200512 if (errno || (e_val > UINT16_MAX) || (e_val < -UINT16_MAX)) {
aPiecek76034c32021-06-08 15:03:11 +0200513 LOGVAL(ctx, LYVE_SEMANTICS,
514 "Exponent out-of-bounds in a JSON Number value (%.*s).",
Michal Vasko54ba8912021-07-23 12:46:23 +0200515 (int)total_len, in);
aPiecek76034c32021-06-08 15:03:11 +0200516 return LY_EVALID;
517 }
518
519 minus = in[0] == '-';
520 if (in[minus] == '0') {
521 assert(in[minus + 1] == '.');
522 leading_zero = 1;
523 /* The leading zero has been found, it will be skipped. */
524 num = &in[minus + 1];
525 } else {
526 leading_zero = 0;
527 /* Set to the first number. */
528 num = &in[minus];
529 }
530 num_len = exponent - num;
531
532 /* Find the location of the decimal points. */
533 dec_point = ly_strnchr(num, '.', num_len);
534 dp_position = dec_point ?
535 dec_point - num + e_val :
536 num_len + e_val;
537
538 /* Remove zeros after the decimal point from the end of
539 * the 'numeric part' because these are useless.
540 * (For example, in 40.001000 these are the last 3).
541 */
542 num_len -= dp_position > 0 ?
543 lyjson_count_in_row(num + dp_position - 1, exponent, '0', BACKWARD) :
544 lyjson_count_in_row(num, exponent, '0', BACKWARD);
545
546 /* Decide what to do with the dot from the 'numeric part'. */
547 if (dec_point && ((int32_t)(num_len - 1) == dp_position)) {
548 /* Decimal point in the last place is useless. */
549 dot = -1;
550 } else if (dec_point) {
551 /* Decimal point is shifted. */
552 dot = 0;
553 } else {
554 /* Additional byte for the decimal point is requred. */
555 dot = 1;
556 }
557
558 /* Final composition of the result. */
559 if (dp_position <= 0) {
560 /* Adding decimal point before the integer with adding additional zero(s). */
561
562 zeros = labs(dp_position);
563 buf_len = minus + LEADING_ZERO + dot + zeros + num_len;
564 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
565 MAYBE_WRITE_MINUS(buf, i, minus);
566 buf[i++] = '0';
567 buf[i++] = '.';
568 memset(buf + i, '0', zeros);
569 i += zeros;
570 dp_position = -1;
571 lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
572 } else if (leading_zero && (dp_position < (ssize_t)num_len)) {
573 /* Insert decimal point between the integer's digits. */
574
575 /* Set a new range of 'numeric part'. Old decimal point is skipped. */
576 num++;
577 num_len--;
578 dp_position--;
579 /* Get the number of useless zeros between the old
580 * and new decimal point. For example, in the number 0.005E1,
581 * there is one useless zero.
582 */
583 zeros = lyjson_count_in_row(num, num + dp_position + 1, '0', FORWARD);
584 /* If the new decimal point will be in the place of the first non-zero subnumber. */
585 if (zeros == (dp_position + 1)) {
586 /* keep one zero as leading zero */
587 zeros--;
588 /* new decimal point will be behind the leading zero */
589 dp_position = 1;
590 dot = 1;
591 } else {
592 dot = 0;
593 }
594 buf_len = minus + dot + (num_len - zeros);
595 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
596 MAYBE_WRITE_MINUS(buf, i, minus);
597 /* Skip useless zeros and copy. */
598 lyjson_exp_number_copy_num_part(num + zeros, num_len - zeros, NULL, dp_position, buf + i);
599 } else if (dp_position < (ssize_t)num_len) {
600 /* Insert decimal point between the integer's digits. */
601
602 buf_len = minus + dot + num_len;
603 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
604 MAYBE_WRITE_MINUS(buf, i, minus);
605 lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
606 } else if (leading_zero) {
607 /* Adding decimal point after the decimal value make the integer result. */
608
609 /* Set a new range of 'numeric part'. Old decimal point is skipped. */
610 num++;
611 num_len--;
612 /* Get the number of useless zeros. */
613 zeros = lyjson_count_in_row(num, num + num_len, '0', FORWARD);
614 buf_len = minus + dp_position - zeros;
615 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
616 MAYBE_WRITE_MINUS(buf, i, minus);
617 /* Skip useless zeros and copy. */
618 i += lyjson_exp_number_copy_num_part(num + zeros, num_len - zeros, NULL, dp_position, buf + i);
619 /* Add multiples of ten behind the 'numeric part'. */
620 memset(buf + i, '0', buf_len - i);
621 } else {
622 /* Adding decimal point after the decimal value make the integer result. */
623
624 buf_len = minus + dp_position;
625 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
626 MAYBE_WRITE_MINUS(buf, i, minus);
627 i += lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
628 /* Add multiples of ten behind the 'numeric part'. */
629 memset(buf + i, '0', buf_len - i);
630 }
631
632 buf[buf_len] = '\0';
633 *res = buf;
634 *res_len = buf_len;
635
636#undef MAYBE_WRITE_MINUS
637#undef LEADING_ZERO
638#undef FORWARD
639#undef BACKWARD
640
aPieceke87c0a12021-05-13 15:43:26 +0200641 return LY_SUCCESS;
642}
643
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200644static LY_ERR
645lyjson_number(struct lyjson_ctx *jsonctx)
646{
aPiecek76034c32021-06-08 15:03:11 +0200647 size_t offset = 0, num_len;
648 const char *in = jsonctx->in->current, *exponent = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200649 uint8_t minus = 0;
aPiecek76034c32021-06-08 15:03:11 +0200650 char *num;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200651
652 if (in[offset] == '-') {
653 ++offset;
654 minus = 1;
655 }
656
657 if (in[offset] == '0') {
658 ++offset;
659 } else if (isdigit(in[offset])) {
660 ++offset;
661 while (isdigit(in[offset])) {
662 ++offset;
663 }
664 } else {
665invalid_character:
666 if (in[offset]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100667 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character in JSON Number value (\"%c\").", in[offset]);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200668 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100669 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200670 }
671 return LY_EVALID;
672 }
673
674 if (in[offset] == '.') {
675 ++offset;
676 if (!isdigit(in[offset])) {
677 goto invalid_character;
678 }
679 while (isdigit(in[offset])) {
680 ++offset;
681 }
682 }
683
684 if ((in[offset] == 'e') || (in[offset] == 'E')) {
aPiecek76034c32021-06-08 15:03:11 +0200685 exponent = &in[offset];
686 ++offset;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200687 if ((in[offset] == '+') || (in[offset] == '-')) {
688 ++offset;
689 }
690 if (!isdigit(in[offset])) {
691 goto invalid_character;
692 }
693 while (isdigit(in[offset])) {
694 ++offset;
695 }
696 }
697
aPiecek76034c32021-06-08 15:03:11 +0200698 if (lyjson_number_is_zero(in, exponent ? exponent : &in[offset])) {
699 lyjson_ctx_set_value(jsonctx, in, minus + 1, 0);
700 } else if (exponent && lyjson_number_is_zero(exponent + 1, &in[offset])) {
701 lyjson_ctx_set_value(jsonctx, in, exponent - in, 0);
702 } else if (exponent) {
703 LY_CHECK_RET(lyjson_exp_number(jsonctx->ctx, in, exponent, offset, &num, &num_len));
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200704 lyjson_ctx_set_value(jsonctx, num, num_len, 1);
705 } else {
aPiecek5b6dd182021-06-10 09:11:58 +0200706 if (offset > LY_NUMBER_MAXLEN) {
707 LOGVAL(jsonctx->ctx, LYVE_SEMANTICS,
708 "Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit.");
709 return LY_EVALID;
710 }
aPiecek76034c32021-06-08 15:03:11 +0200711 lyjson_ctx_set_value(jsonctx, in, offset, 0);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200712 }
713 ly_in_skip(jsonctx->in, offset);
714
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100715 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NUMBER);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200716 LY_CHECK_RET(lyjson_check_next(jsonctx));
717
718 return LY_SUCCESS;
719}
720
721static LY_ERR
722lyjson_object_name(struct lyjson_ctx *jsonctx)
723{
724 if (*jsonctx->in->current != '"') {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100725 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
Michal Vasko69730152020-10-09 16:30:07 +0200726 jsonctx->in->current, "a JSON object's member");
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200727 return LY_EVALID;
728 }
729 ly_in_skip(jsonctx->in, 1);
730
731 LY_CHECK_RET(lyjson_string_(jsonctx));
732 LY_CHECK_RET(skip_ws(jsonctx));
Michal Vasko08dc70b2020-10-07 13:58:47 +0200733 if (*jsonctx->in->current != ':') {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100734 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
735 "a JSON object's name-separator ':'");
Michal Vasko08dc70b2020-10-07 13:58:47 +0200736 return LY_EVALID;
737 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200738 ly_in_skip(jsonctx->in, 1);
739 LY_CHECK_RET(skip_ws(jsonctx));
740
741 return LY_SUCCESS;
742}
743
744static LY_ERR
745lyjson_object(struct lyjson_ctx *jsonctx)
746{
747 LY_CHECK_RET(skip_ws(jsonctx));
748
749 if (*jsonctx->in->current == '}') {
aPiecek93582ed2021-05-25 14:49:06 +0200750 assert(jsonctx->depth);
751 jsonctx->depth--;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200752 /* empty object */
753 ly_in_skip(jsonctx->in, 1);
754 lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100755 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_EMPTY);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200756 return LY_SUCCESS;
757 }
758
759 LY_CHECK_RET(lyjson_object_name(jsonctx));
760
761 /* output data are set by lyjson_string_() */
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100762 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200763
764 return LY_SUCCESS;
765}
766
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100767/**
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200768 * @brief Process JSON array envelope
769 *
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200770 * @param[in] jsonctx JSON parser context
771 * @return LY_SUCCESS or LY_EMEM
772 */
773static LY_ERR
774lyjson_array(struct lyjson_ctx *jsonctx)
775{
776 LY_CHECK_RET(skip_ws(jsonctx));
777
778 if (*jsonctx->in->current == ']') {
779 /* empty array */
780 ly_in_skip(jsonctx->in, 1);
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100781 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_EMPTY);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200782 } else {
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100783 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200784 }
785
786 /* erase previous values, array has no value on its own */
787 lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
788
789 return LY_SUCCESS;
790}
791
792static LY_ERR
793lyjson_value(struct lyjson_ctx *jsonctx)
794{
Michal Vasko69730152020-10-09 16:30:07 +0200795 if (jsonctx->status.count && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200796 return LY_SUCCESS;
797 }
798
Radek Krejcif13b87b2020-12-01 22:02:17 +0100799 if ((*jsonctx->in->current == 'f') && !strncmp(jsonctx->in->current, "false", ly_strlen_const("false"))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200800 /* false */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100801 lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("false"), 0);
802 ly_in_skip(jsonctx->in, ly_strlen_const("false"));
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100803 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_FALSE);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200804 LY_CHECK_RET(lyjson_check_next(jsonctx));
805
Radek Krejcif13b87b2020-12-01 22:02:17 +0100806 } else if ((*jsonctx->in->current == 't') && !strncmp(jsonctx->in->current, "true", ly_strlen_const("true"))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200807 /* true */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100808 lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("true"), 0);
809 ly_in_skip(jsonctx->in, ly_strlen_const("true"));
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100810 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_TRUE);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200811 LY_CHECK_RET(lyjson_check_next(jsonctx));
812
Radek Krejcif13b87b2020-12-01 22:02:17 +0100813 } else if ((*jsonctx->in->current == 'n') && !strncmp(jsonctx->in->current, "null", ly_strlen_const("null"))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200814 /* none */
Radek Krejci201963a2020-12-03 11:43:40 +0100815 lyjson_ctx_set_value(jsonctx, "", 0, 0);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100816 ly_in_skip(jsonctx->in, ly_strlen_const("null"));
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100817 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NULL);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200818 LY_CHECK_RET(lyjson_check_next(jsonctx));
819
820 } else if (*jsonctx->in->current == '"') {
821 /* string */
822 ly_in_skip(jsonctx->in, 1);
823 LY_CHECK_RET(lyjson_string(jsonctx));
824
825 } else if (*jsonctx->in->current == '[') {
826 /* array */
827 ly_in_skip(jsonctx->in, 1);
828 LY_CHECK_RET(lyjson_array(jsonctx));
829
830 } else if (*jsonctx->in->current == '{') {
aPiecek93582ed2021-05-25 14:49:06 +0200831 jsonctx->depth++;
832 if (jsonctx->depth > LY_MAX_BLOCK_DEPTH) {
833 LOGERR(jsonctx->ctx, LY_EINVAL,
834 "The maximum number of block nestings has been exceeded.");
835 return LY_EINVAL;
836 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200837 /* object */
838 ly_in_skip(jsonctx->in, 1);
839 LY_CHECK_RET(lyjson_object(jsonctx));
840
Michal Vasko69730152020-10-09 16:30:07 +0200841 } else if ((*jsonctx->in->current == '-') || ((*jsonctx->in->current >= '0') && (*jsonctx->in->current <= '9'))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200842 /* number */
843 LY_CHECK_RET(lyjson_number(jsonctx));
844
845 } else {
846 /* unexpected value */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100847 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
Michal Vasko69730152020-10-09 16:30:07 +0200848 jsonctx->in->current, "a JSON value");
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200849 return LY_EVALID;
850 }
851
852 return LY_SUCCESS;
853}
854
855LY_ERR
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100856lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, ly_bool subtree, struct lyjson_ctx **jsonctx_p)
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200857{
858 LY_ERR ret = LY_SUCCESS;
859 struct lyjson_ctx *jsonctx;
860
861 assert(ctx);
862 assert(in);
863 assert(jsonctx_p);
864
865 /* new context */
866 jsonctx = calloc(1, sizeof *jsonctx);
867 LY_CHECK_ERR_RET(!jsonctx, LOGMEM(ctx), LY_EMEM);
868 jsonctx->ctx = ctx;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200869 jsonctx->in = in;
870
Radek Krejciddace2c2021-01-08 11:30:56 +0100871 LOG_LOCINIT(NULL, NULL, NULL, in);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100872
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200873 /* parse JSON value, if any */
874 LY_CHECK_GOTO(ret = skip_ws(jsonctx), cleanup);
875 if (lyjson_ctx_status(jsonctx, 0) == LYJSON_END) {
876 /* empty data input */
877 goto cleanup;
878 }
879
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100880 if (subtree) {
881 ret = lyjson_object(jsonctx);
882 jsonctx->depth++;
883 } else {
884 ret = lyjson_value(jsonctx);
885 }
Michal Vasko69730152020-10-09 16:30:07 +0200886 if ((jsonctx->status.count > 1) && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100887 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200888 ret = LY_EVALID;
889 }
890
891cleanup:
892 if (ret) {
893 lyjson_ctx_free(jsonctx);
894 } else {
895 *jsonctx_p = jsonctx;
896 }
897 return ret;
898}
899
900void
901lyjson_ctx_backup(struct lyjson_ctx *jsonctx)
902{
903 if (jsonctx->backup.dynamic) {
904 free((char *)jsonctx->backup.value);
905 }
906 jsonctx->backup.status = lyjson_ctx_status(jsonctx, 0);
907 jsonctx->backup.status_count = jsonctx->status.count;
908 jsonctx->backup.value = jsonctx->value;
909 jsonctx->backup.value_len = jsonctx->value_len;
910 jsonctx->backup.input = jsonctx->in->current;
911 jsonctx->backup.dynamic = jsonctx->dynamic;
aPiecek93582ed2021-05-25 14:49:06 +0200912 jsonctx->backup.depth = jsonctx->depth;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200913 jsonctx->dynamic = 0;
914}
915
916void
917lyjson_ctx_restore(struct lyjson_ctx *jsonctx)
918{
919 if (jsonctx->dynamic) {
920 free((char *)jsonctx->value);
921 }
922 jsonctx->status.count = jsonctx->backup.status_count;
Michal Vasko22df3f02020-08-24 13:29:22 +0200923 jsonctx->status.objs[jsonctx->backup.status_count - 1] = (void *)jsonctx->backup.status;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200924 jsonctx->value = jsonctx->backup.value;
925 jsonctx->value_len = jsonctx->backup.value_len;
926 jsonctx->in->current = jsonctx->backup.input;
927 jsonctx->dynamic = jsonctx->backup.dynamic;
aPiecek93582ed2021-05-25 14:49:06 +0200928 jsonctx->depth = jsonctx->backup.depth;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200929 jsonctx->backup.dynamic = 0;
930}
931
932LY_ERR
933lyjson_ctx_next(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status)
934{
935 LY_ERR ret = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +0200936 ly_bool toplevel = 0;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200937 enum LYJSON_PARSER_STATUS prev;
938
939 assert(jsonctx);
940
941 prev = lyjson_ctx_status(jsonctx, 0);
942
Michal Vasko69730152020-10-09 16:30:07 +0200943 if ((prev == LYJSON_OBJECT) || (prev == LYJSON_ARRAY)) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200944 /* get value for the object's member OR the first value in the array */
945 ret = lyjson_value(jsonctx);
946 goto result;
947 } else {
948 /* the previous token is closed and should be completely processed */
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100949 LYJSON_STATUS_POP_RET(jsonctx);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200950 prev = lyjson_ctx_status(jsonctx, 0);
951 }
952
953 if (!jsonctx->status.count) {
954 /* we are done with the top level value */
955 toplevel = 1;
956 }
957 LY_CHECK_RET(skip_ws(jsonctx));
958 if (toplevel && !jsonctx->status.count) {
959 /* EOF expected, but there are some data after the top level token */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100960 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 +0200961 return LY_EVALID;
962 }
963
964 if (toplevel) {
965 /* we are done */
966 return LY_SUCCESS;
967 }
968
969 /* continue with the next token */
970 assert(prev == LYJSON_OBJECT || prev == LYJSON_ARRAY);
971
972 if (*jsonctx->in->current == ',') {
973 /* sibling item in the ... */
974 ly_in_skip(jsonctx->in, 1);
975 LY_CHECK_RET(skip_ws(jsonctx));
976
977 if (prev == LYJSON_OBJECT) {
978 /* ... object - get another object's member */
979 ret = lyjson_object_name(jsonctx);
980 } else { /* LYJSON_ARRAY */
981 /* ... array - get another complete value */
982 ret = lyjson_value(jsonctx);
983 }
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100984 } else if (((prev == LYJSON_OBJECT) && (*jsonctx->in->current == '}')) ||
985 ((prev == LYJSON_ARRAY) && (*jsonctx->in->current == ']'))) {
aPiecek93582ed2021-05-25 14:49:06 +0200986 if (*jsonctx->in->current == '}') {
987 assert(jsonctx->depth);
988 jsonctx->depth--;
989 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200990 ly_in_skip(jsonctx->in, 1);
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100991 LYJSON_STATUS_POP_RET(jsonctx);
992 LYJSON_STATUS_PUSH_RET(jsonctx, prev + 1);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200993 } else {
994 /* unexpected value */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100995 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
996 prev == LYJSON_ARRAY ? "another JSON value in array" : "another JSON object's member");
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200997 return LY_EVALID;
998 }
999
1000result:
Michal Vasko69730152020-10-09 16:30:07 +02001001 if ((ret == LY_SUCCESS) && (jsonctx->status.count > 1) && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001002 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001003 ret = LY_EVALID;
1004 }
1005
Michal Vasko69730152020-10-09 16:30:07 +02001006 if ((ret == LY_SUCCESS) && status) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001007 *status = lyjson_ctx_status(jsonctx, 0);
1008 }
1009
1010 return ret;
1011}
1012
1013enum LYJSON_PARSER_STATUS
1014lyjson_ctx_status(struct lyjson_ctx *jsonctx, uint32_t index)
1015{
1016 assert(jsonctx);
1017
1018 if (jsonctx->status.count < index) {
1019 return LYJSON_ERROR;
1020 } else if (jsonctx->status.count == index) {
1021 return LYJSON_ROOT;
1022 } else {
Michal Vasko27915722020-08-31 14:54:42 +02001023 return (enum LYJSON_PARSER_STATUS)(uintptr_t)jsonctx->status.objs[jsonctx->status.count - (index + 1)];
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001024 }
1025}
1026
1027void
1028lyjson_ctx_free(struct lyjson_ctx *jsonctx)
1029{
1030 if (!jsonctx) {
1031 return;
1032 }
1033
Radek Krejciddace2c2021-01-08 11:30:56 +01001034 LOG_LOCBACK(0, 0, 0, 1);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001035
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001036 if (jsonctx->dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +02001037 free((char *)jsonctx->value);
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001038 }
1039 if (jsonctx->backup.dynamic) {
1040 free((char *)jsonctx->backup.value);
1041 }
1042
1043 ly_set_erase(&jsonctx->status, NULL);
1044
1045 free(jsonctx);
1046}