blob: 5c45c8c084b6fedec7e74a4a92d1605afb6057ab [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;
Michal Vasko2bf4af42023-01-04 12:08:38 +0100167
Radek Krejcidf549132021-01-21 10:32:32 +0100168 for (increment = BUFSIZE_STEP; len + offset + 4 >= size + increment; increment += BUFSIZE_STEP) {}
Juraj Vijtiukd746a352021-01-15 11:33:33 +0100169 buf = ly_realloc(buf, size + increment);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200170 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
171 size += BUFSIZE_STEP;
172 }
173
174 if (offset) {
175 /* store what we have so far */
176 memcpy(&buf[len], in, offset);
177 len += offset;
178 in += offset;
179 offset = 0;
180 }
181
182 switch (in[++offset]) {
183 case '"':
184 /* quotation mark */
185 value = 0x22;
186 break;
187 case '\\':
188 /* reverse solidus */
189 value = 0x5c;
190 break;
191 case '/':
192 /* solidus */
193 value = 0x2f;
194 break;
195 case 'b':
196 /* backspace */
197 value = 0x08;
198 break;
199 case 'f':
200 /* form feed */
201 value = 0x0c;
202 break;
203 case 'n':
204 /* line feed */
205 value = 0x0a;
206 break;
207 case 'r':
208 /* carriage return */
209 value = 0x0d;
210 break;
211 case 't':
212 /* tab */
213 value = 0x09;
214 break;
215 case 'u':
216 /* Basic Multilingual Plane character \uXXXX */
217 offset++;
218 for (value = i = 0; i < 4; i++) {
Juraj Vijtiuk2b94e4b2020-11-16 23:52:07 +0100219 if (!in[offset + i]) {
Michal Vasko2be1d762021-03-11 16:53:15 +0100220 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid basic multilingual plane character \"%s\".", slash);
Juraj Vijtiuk2b94e4b2020-11-16 23:52:07 +0100221 goto error;
222 } else if (isdigit(in[offset + i])) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200223 u = (in[offset + i] - '0');
224 } else if (in[offset + i] > 'F') {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100225 u = LY_BASE_DEC + (in[offset + i] - 'a');
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200226 } else {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100227 u = LY_BASE_DEC + (in[offset + i] - 'A');
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200228 }
Radek Krejcif13b87b2020-12-01 22:02:17 +0100229 value = (LY_BASE_HEX * value) + u;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200230 }
231 break;
232 default:
233 /* invalid escape sequence */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100234 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character escape sequence \\%c.", in[offset]);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200235 goto error;
236
237 }
238
239 offset += i; /* add read escaped characters */
240 LY_CHECK_ERR_GOTO(ly_pututf8(&buf[len], value, &u),
Radek Krejci2efc45b2020-12-22 16:25:44 +0100241 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character reference \"%.*s\" (0x%08x).",
Michal Vasko2be1d762021-03-11 16:53:15 +0100242 (int)(&in[offset] - slash), slash, value),
Michal Vasko69730152020-10-09 16:30:07 +0200243 error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200244 len += u; /* update number of bytes in buffer */
245 in += offset; /* move the input by the processed bytes stored in the buffer ... */
246 offset = 0; /* ... and reset the offset index for future moving data into buffer */
247
248 } else if (in[offset] == '"') {
249 /* end of string */
250 if (buf) {
251 /* realloc exact size string */
252 buf = ly_realloc(buf, len + offset + 1);
253 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
254 size = len + offset + 1;
Michal Vasko08e9b112021-06-11 15:41:17 +0200255 if (offset) {
256 memcpy(&buf[len], in, offset);
257 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200258
259 /* set terminating NULL byte */
260 buf[len + offset] = '\0';
261 }
262 len += offset;
263 ++offset;
264 in += offset;
265 goto success;
266 } else {
267 /* get it as UTF-8 character for check */
268 const char *c = &in[offset];
269 uint32_t code = 0;
270 size_t code_len = 0;
271
272 LY_CHECK_ERR_GOTO(ly_getutf8(&c, &code, &code_len),
Radek Krejci2efc45b2020-12-22 16:25:44 +0100273 LOGVAL(jsonctx->ctx, LY_VCODE_INCHAR, in[offset]), error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200274
275 LY_CHECK_ERR_GOTO(!is_jsonstrchar(code),
Radek Krejci2efc45b2020-12-22 16:25:44 +0100276 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character in JSON string \"%.*s\" (0x%08x).",
Radek Krejci422afb12021-03-04 16:38:16 +0100277 (int)(&in[offset] - start + code_len), start, code),
Michal Vasko69730152020-10-09 16:30:07 +0200278 error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200279
280 /* character is ok, continue */
281 offset += code_len;
282 }
283 }
284
285 /* EOF reached before endchar */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100286 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
287 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 +0200288
289error:
290 free(buf);
291 return LY_EVALID;
292
293success:
Radek Krejcid54412f2020-12-17 20:25:35 +0100294 jsonctx->in->current = in;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200295 if (buf) {
296 lyjson_ctx_set_value(jsonctx, buf, len, 1);
297 } else {
298 lyjson_ctx_set_value(jsonctx, start, len, 0);
299 }
300
301 return LY_SUCCESS;
302
303#undef BUFSIZE
304#undef BUFSIZE_STEP
305}
306
307/*
308 *
309 * Wrapper around lyjson_string_() adding LYJSON_STRING status into context to allow using lyjson_string_() for parsing object's name.
310 */
311static LY_ERR
312lyjson_string(struct lyjson_ctx *jsonctx)
313{
314 LY_CHECK_RET(lyjson_string_(jsonctx));
315
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100316 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_STRING);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200317 LY_CHECK_RET(lyjson_check_next(jsonctx));
318
319 return LY_SUCCESS;
320}
321
aPieceke87c0a12021-05-13 15:43:26 +0200322/**
aPiecek76034c32021-06-08 15:03:11 +0200323 * @brief Calculate how many @p c characters there are in a row.
324 *
325 * @param[in] str Count from this position.
326 * @param[in] end Position after the last checked character.
327 * @param[in] c Checked character.
328 * @param[in] backwards Set to 1, if to proceed from end-1 to str.
329 * @return Number of characters in a row.
330 */
331static uint32_t
332lyjson_count_in_row(const char *str, const char *end, char c, ly_bool backwards)
333{
334 uint32_t cnt;
335
336 assert(str && end);
337
338 if (str >= end) {
339 return 0;
340 }
341
342 if (!backwards) {
343 for (cnt = 0; (str != end) && (*str == c); ++str, ++cnt) {}
344 } else {
345 --end;
346 --str;
347 for (cnt = 0; (str != end) && (*end == c); --end, ++cnt) {}
348 }
349
350 return cnt;
351}
352
353/**
354 * @brief Check if the number can be shortened to zero.
355 *
aPiecek76034c32021-06-08 15:03:11 +0200356 * @param[in] in Start of input string;
357 * @param[in] end End of input string;
358 * @return 1 if number is zero, otherwise 0.
359 */
360static ly_bool
361lyjson_number_is_zero(const char *in, const char *end)
362{
aPiecek28e101a2021-06-10 09:09:31 +0200363 assert(in < end);
aPiecek76034c32021-06-08 15:03:11 +0200364
365 if ((in[0] == '-') || (in[0] == '+')) {
366 in++;
aPiecek28e101a2021-06-10 09:09:31 +0200367 assert(in < end);
aPiecek76034c32021-06-08 15:03:11 +0200368 }
369 if ((in[0] == '0') && (in[1] == '.')) {
370 in += 2;
aPiecek28e101a2021-06-10 09:09:31 +0200371 if (!(in < end)) {
372 return 1;
373 }
aPiecek76034c32021-06-08 15:03:11 +0200374 }
375
376 return lyjson_count_in_row(in, end, '0', 0) == end - in;
377}
378
379/**
aPieceke87c0a12021-05-13 15:43:26 +0200380 * @brief Allocate buffer for number in string format.
381 *
382 * @param[in] jsonctx JSON context.
383 * @param[in] num_len Required space in bytes for a number.
384 * Terminating null byte is added by default.
385 * @param[out] buffer Output allocated buffer.
386 * @return LY_ERR value.
387 */
388static LY_ERR
aPiecek0ba088e2021-06-15 12:53:17 +0200389lyjson_get_buffer_for_number(const struct ly_ctx *ctx, uint64_t num_len, char **buffer)
aPieceke87c0a12021-05-13 15:43:26 +0200390{
391 *buffer = NULL;
392
aPiecek76034c32021-06-08 15:03:11 +0200393 LY_CHECK_ERR_RET((num_len + 1) > LY_NUMBER_MAXLEN, LOGVAL(ctx, LYVE_SEMANTICS,
aPieceke87c0a12021-05-13 15:43:26 +0200394 "Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit."), LY_EVALID);
395
aPiecek76034c32021-06-08 15:03:11 +0200396 /* allocate buffer for the result (add NULL-byte) */
aPieceke87c0a12021-05-13 15:43:26 +0200397 *buffer = malloc(num_len + 1);
aPiecek76034c32021-06-08 15:03:11 +0200398 LY_CHECK_ERR_RET(!(*buffer), LOGMEM(ctx), LY_EMEM);
399 return LY_SUCCESS;
400}
401
402/**
403 * @brief Copy the 'numeric part' (@p num) except its decimal point
404 * (@p dec_point) and insert the new decimal point (@p dp_position)
405 * only if it is to be placed in the 'numeric part' range (@p num).
406 *
407 * @param[in] num Begin of the 'numeric part'.
408 * @param[in] num_len Length of the 'numeric part'.
409 * @param[in] dec_point Pointer to the old decimal point.
410 * If it has a NULL value, it is ignored.
411 * @param[in] dp_position Position of the new decimal point.
412 * If it has a negative value, it is ignored.
413 * @param[out] dst Memory into which the copied result is written.
414 * @return Number of characters written to the @p dst.
415 */
416static uint32_t
417lyjson_exp_number_copy_num_part(const char *num, uint32_t num_len,
418 char *dec_point, int32_t dp_position, char *dst)
419{
420 int32_t dec_point_idx;
421 int32_t n, d;
422
423 assert(num && dst);
424
425 dec_point_idx = dec_point ? dec_point - num : INT32_MAX;
426 assert((dec_point_idx >= 0) && (dec_point_idx != dp_position));
427
428 for (n = 0, d = 0; (uint32_t)n < num_len; n++) {
429 if (n == dec_point_idx) {
430 continue;
431 } else if (d == dp_position) {
432 dst[d++] = '.';
433 dst[d++] = num[n];
434 } else {
435 dst[d++] = num[n];
436 }
437 }
438
439 return d;
440}
441
442/**
443 * @brief Convert JSON number with exponent into the representation
444 * used by YANG.
445 *
446 * The input numeric string must be syntactically valid. Also, before
447 * calling this function, checks should be performed using the
448 * ::lyjson_number_is_zero().
449 *
450 * @param[in] ctx Context for the error message.
451 * @param[in] in Beginning of the string containing the number.
452 * @param[in] exponent Pointer to the letter E/e.
453 * @param[in] total_len Total size of the input number.
454 * @param[out] res Conversion result.
455 * @param[out] res_len Length of the result.
456 * @return LY_ERR value.
457 */
458static LY_ERR
459lyjson_exp_number(const struct ly_ctx *ctx, const char *in, const char *exponent,
Michal Vaskoc10488f2021-07-23 12:45:20 +0200460 uint64_t total_len, char **res, size_t *res_len)
aPiecek76034c32021-06-08 15:03:11 +0200461{
462
463#define MAYBE_WRITE_MINUS(ARRAY, INDEX, FLAG) \
464 if (FLAG) { \
465 ARRAY[INDEX++] = '-'; \
466 }
467
468/* Length of leading zero followed by the decimal point. */
469#define LEADING_ZERO 1
470
471/* Flags for the ::lyjson_count_in_row() */
472#define FORWARD 0
473#define BACKWARD 1
474
475 /* Buffer where the result is stored. */
476 char *buf;
477 /* Size without space for terminating NULL-byte. */
aPiecek0ba088e2021-06-15 12:53:17 +0200478 uint64_t buf_len;
aPiecek76034c32021-06-08 15:03:11 +0200479 /* Index to buf. */
480 uint32_t i = 0;
481 /* A 'numeric part' doesn't contain a minus sign or an leading zero.
482 * For example, in 0.45, there is the leading zero.
483 */
484 const char *num;
485 /* Length of the 'numeric part' ends before E/e. */
aPiecek0ba088e2021-06-15 12:53:17 +0200486 uint16_t num_len;
aPiecek76034c32021-06-08 15:03:11 +0200487 /* Position of decimal point in the num. */
488 char *dec_point;
489 /* Final position of decimal point in the buf. */
490 int32_t dp_position;
491 /* Exponent as integer. */
Michal Vasko2bf4af42023-01-04 12:08:38 +0100492 long long e_val;
aPiecek76034c32021-06-08 15:03:11 +0200493 /* Byte for the decimal point. */
494 int8_t dot;
495 /* Required additional byte for the minus sign. */
496 uint8_t minus;
497 /* The number of zeros. */
498 long zeros;
499 /* If the number starts with leading zero followed by the decimal point. */
500 ly_bool leading_zero;
501
502 assert(ctx && in && exponent && res && res_len && (total_len > 2));
503 assert((in < exponent) && ((*exponent == 'e') || (*exponent == 'E')));
504
aPiecek0ba088e2021-06-15 12:53:17 +0200505 if ((exponent - in) > UINT16_MAX) {
506 LOGVAL(ctx, LYVE_SEMANTICS, "JSON number is too long.");
507 return LY_EVALID;
508 }
509
aPiecek76034c32021-06-08 15:03:11 +0200510 /* Convert exponent. */
511 errno = 0;
Michal Vasko73d77ab2021-07-23 12:45:55 +0200512 e_val = strtoll(exponent + 1, NULL, LY_BASE_DEC);
aPieceke4e0d6c2021-07-01 12:02:54 +0200513 if (errno || (e_val > UINT16_MAX) || (e_val < -UINT16_MAX)) {
aPiecek76034c32021-06-08 15:03:11 +0200514 LOGVAL(ctx, LYVE_SEMANTICS,
515 "Exponent out-of-bounds in a JSON Number value (%.*s).",
Michal Vasko54ba8912021-07-23 12:46:23 +0200516 (int)total_len, in);
aPiecek76034c32021-06-08 15:03:11 +0200517 return LY_EVALID;
518 }
519
520 minus = in[0] == '-';
521 if (in[minus] == '0') {
522 assert(in[minus + 1] == '.');
523 leading_zero = 1;
524 /* The leading zero has been found, it will be skipped. */
525 num = &in[minus + 1];
526 } else {
527 leading_zero = 0;
528 /* Set to the first number. */
529 num = &in[minus];
530 }
531 num_len = exponent - num;
532
533 /* Find the location of the decimal points. */
534 dec_point = ly_strnchr(num, '.', num_len);
535 dp_position = dec_point ?
536 dec_point - num + e_val :
537 num_len + e_val;
538
539 /* Remove zeros after the decimal point from the end of
540 * the 'numeric part' because these are useless.
541 * (For example, in 40.001000 these are the last 3).
542 */
543 num_len -= dp_position > 0 ?
544 lyjson_count_in_row(num + dp_position - 1, exponent, '0', BACKWARD) :
545 lyjson_count_in_row(num, exponent, '0', BACKWARD);
546
547 /* Decide what to do with the dot from the 'numeric part'. */
548 if (dec_point && ((int32_t)(num_len - 1) == dp_position)) {
549 /* Decimal point in the last place is useless. */
550 dot = -1;
551 } else if (dec_point) {
552 /* Decimal point is shifted. */
553 dot = 0;
554 } else {
555 /* Additional byte for the decimal point is requred. */
556 dot = 1;
557 }
558
559 /* Final composition of the result. */
560 if (dp_position <= 0) {
561 /* Adding decimal point before the integer with adding additional zero(s). */
562
563 zeros = labs(dp_position);
564 buf_len = minus + LEADING_ZERO + dot + zeros + num_len;
565 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
566 MAYBE_WRITE_MINUS(buf, i, minus);
567 buf[i++] = '0';
568 buf[i++] = '.';
569 memset(buf + i, '0', zeros);
570 i += zeros;
571 dp_position = -1;
572 lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
573 } else if (leading_zero && (dp_position < (ssize_t)num_len)) {
574 /* Insert decimal point between the integer's digits. */
575
576 /* Set a new range of 'numeric part'. Old decimal point is skipped. */
577 num++;
578 num_len--;
579 dp_position--;
580 /* Get the number of useless zeros between the old
581 * and new decimal point. For example, in the number 0.005E1,
582 * there is one useless zero.
583 */
584 zeros = lyjson_count_in_row(num, num + dp_position + 1, '0', FORWARD);
585 /* If the new decimal point will be in the place of the first non-zero subnumber. */
586 if (zeros == (dp_position + 1)) {
587 /* keep one zero as leading zero */
588 zeros--;
589 /* new decimal point will be behind the leading zero */
590 dp_position = 1;
591 dot = 1;
592 } else {
593 dot = 0;
594 }
595 buf_len = minus + dot + (num_len - zeros);
596 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
597 MAYBE_WRITE_MINUS(buf, i, minus);
598 /* Skip useless zeros and copy. */
599 lyjson_exp_number_copy_num_part(num + zeros, num_len - zeros, NULL, dp_position, buf + i);
600 } else if (dp_position < (ssize_t)num_len) {
601 /* Insert decimal point between the integer's digits. */
602
603 buf_len = minus + dot + num_len;
604 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
605 MAYBE_WRITE_MINUS(buf, i, minus);
606 lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
607 } else if (leading_zero) {
608 /* Adding decimal point after the decimal value make the integer result. */
609
610 /* Set a new range of 'numeric part'. Old decimal point is skipped. */
611 num++;
612 num_len--;
613 /* Get the number of useless zeros. */
614 zeros = lyjson_count_in_row(num, num + num_len, '0', FORWARD);
615 buf_len = minus + dp_position - zeros;
616 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
617 MAYBE_WRITE_MINUS(buf, i, minus);
618 /* Skip useless zeros and copy. */
619 i += lyjson_exp_number_copy_num_part(num + zeros, num_len - zeros, NULL, dp_position, buf + i);
620 /* Add multiples of ten behind the 'numeric part'. */
621 memset(buf + i, '0', buf_len - i);
622 } else {
623 /* Adding decimal point after the decimal value make the integer result. */
624
625 buf_len = minus + dp_position;
626 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
627 MAYBE_WRITE_MINUS(buf, i, minus);
628 i += lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
629 /* Add multiples of ten behind the 'numeric part'. */
630 memset(buf + i, '0', buf_len - i);
631 }
632
633 buf[buf_len] = '\0';
634 *res = buf;
635 *res_len = buf_len;
636
637#undef MAYBE_WRITE_MINUS
638#undef LEADING_ZERO
639#undef FORWARD
640#undef BACKWARD
641
aPieceke87c0a12021-05-13 15:43:26 +0200642 return LY_SUCCESS;
643}
644
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200645static LY_ERR
646lyjson_number(struct lyjson_ctx *jsonctx)
647{
aPiecek76034c32021-06-08 15:03:11 +0200648 size_t offset = 0, num_len;
649 const char *in = jsonctx->in->current, *exponent = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200650 uint8_t minus = 0;
aPiecek76034c32021-06-08 15:03:11 +0200651 char *num;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200652
653 if (in[offset] == '-') {
654 ++offset;
655 minus = 1;
656 }
657
658 if (in[offset] == '0') {
659 ++offset;
660 } else if (isdigit(in[offset])) {
661 ++offset;
662 while (isdigit(in[offset])) {
663 ++offset;
664 }
665 } else {
666invalid_character:
667 if (in[offset]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100668 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character in JSON Number value (\"%c\").", in[offset]);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200669 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100670 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200671 }
672 return LY_EVALID;
673 }
674
675 if (in[offset] == '.') {
676 ++offset;
677 if (!isdigit(in[offset])) {
678 goto invalid_character;
679 }
680 while (isdigit(in[offset])) {
681 ++offset;
682 }
683 }
684
685 if ((in[offset] == 'e') || (in[offset] == 'E')) {
aPiecek76034c32021-06-08 15:03:11 +0200686 exponent = &in[offset];
687 ++offset;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200688 if ((in[offset] == '+') || (in[offset] == '-')) {
689 ++offset;
690 }
691 if (!isdigit(in[offset])) {
692 goto invalid_character;
693 }
694 while (isdigit(in[offset])) {
695 ++offset;
696 }
697 }
698
aPiecek76034c32021-06-08 15:03:11 +0200699 if (lyjson_number_is_zero(in, exponent ? exponent : &in[offset])) {
700 lyjson_ctx_set_value(jsonctx, in, minus + 1, 0);
701 } else if (exponent && lyjson_number_is_zero(exponent + 1, &in[offset])) {
702 lyjson_ctx_set_value(jsonctx, in, exponent - in, 0);
703 } else if (exponent) {
704 LY_CHECK_RET(lyjson_exp_number(jsonctx->ctx, in, exponent, offset, &num, &num_len));
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200705 lyjson_ctx_set_value(jsonctx, num, num_len, 1);
706 } else {
aPiecek5b6dd182021-06-10 09:11:58 +0200707 if (offset > LY_NUMBER_MAXLEN) {
708 LOGVAL(jsonctx->ctx, LYVE_SEMANTICS,
709 "Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit.");
710 return LY_EVALID;
711 }
aPiecek76034c32021-06-08 15:03:11 +0200712 lyjson_ctx_set_value(jsonctx, in, offset, 0);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200713 }
714 ly_in_skip(jsonctx->in, offset);
715
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100716 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NUMBER);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200717 LY_CHECK_RET(lyjson_check_next(jsonctx));
718
719 return LY_SUCCESS;
720}
721
722static LY_ERR
723lyjson_object_name(struct lyjson_ctx *jsonctx)
724{
725 if (*jsonctx->in->current != '"') {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100726 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
Michal Vasko69730152020-10-09 16:30:07 +0200727 jsonctx->in->current, "a JSON object's member");
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200728 return LY_EVALID;
729 }
730 ly_in_skip(jsonctx->in, 1);
731
732 LY_CHECK_RET(lyjson_string_(jsonctx));
733 LY_CHECK_RET(skip_ws(jsonctx));
Michal Vasko08dc70b2020-10-07 13:58:47 +0200734 if (*jsonctx->in->current != ':') {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100735 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
736 "a JSON object's name-separator ':'");
Michal Vasko08dc70b2020-10-07 13:58:47 +0200737 return LY_EVALID;
738 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200739 ly_in_skip(jsonctx->in, 1);
740 LY_CHECK_RET(skip_ws(jsonctx));
741
742 return LY_SUCCESS;
743}
744
745static LY_ERR
746lyjson_object(struct lyjson_ctx *jsonctx)
747{
748 LY_CHECK_RET(skip_ws(jsonctx));
749
750 if (*jsonctx->in->current == '}') {
aPiecek93582ed2021-05-25 14:49:06 +0200751 assert(jsonctx->depth);
752 jsonctx->depth--;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200753 /* empty object */
754 ly_in_skip(jsonctx->in, 1);
755 lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100756 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_EMPTY);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200757 return LY_SUCCESS;
758 }
759
760 LY_CHECK_RET(lyjson_object_name(jsonctx));
761
762 /* output data are set by lyjson_string_() */
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100763 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200764
765 return LY_SUCCESS;
766}
767
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100768/**
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200769 * @brief Process JSON array envelope
770 *
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200771 * @param[in] jsonctx JSON parser context
772 * @return LY_SUCCESS or LY_EMEM
773 */
774static LY_ERR
775lyjson_array(struct lyjson_ctx *jsonctx)
776{
777 LY_CHECK_RET(skip_ws(jsonctx));
778
779 if (*jsonctx->in->current == ']') {
780 /* empty array */
781 ly_in_skip(jsonctx->in, 1);
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100782 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_EMPTY);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200783 } else {
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100784 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200785 }
786
787 /* erase previous values, array has no value on its own */
788 lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
789
790 return LY_SUCCESS;
791}
792
793static LY_ERR
794lyjson_value(struct lyjson_ctx *jsonctx)
795{
Michal Vasko69730152020-10-09 16:30:07 +0200796 if (jsonctx->status.count && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200797 return LY_SUCCESS;
798 }
799
Radek Krejcif13b87b2020-12-01 22:02:17 +0100800 if ((*jsonctx->in->current == 'f') && !strncmp(jsonctx->in->current, "false", ly_strlen_const("false"))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200801 /* false */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100802 lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("false"), 0);
803 ly_in_skip(jsonctx->in, ly_strlen_const("false"));
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100804 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_FALSE);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200805 LY_CHECK_RET(lyjson_check_next(jsonctx));
806
Radek Krejcif13b87b2020-12-01 22:02:17 +0100807 } else if ((*jsonctx->in->current == 't') && !strncmp(jsonctx->in->current, "true", ly_strlen_const("true"))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200808 /* true */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100809 lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("true"), 0);
810 ly_in_skip(jsonctx->in, ly_strlen_const("true"));
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100811 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_TRUE);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200812 LY_CHECK_RET(lyjson_check_next(jsonctx));
813
Radek Krejcif13b87b2020-12-01 22:02:17 +0100814 } else if ((*jsonctx->in->current == 'n') && !strncmp(jsonctx->in->current, "null", ly_strlen_const("null"))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200815 /* none */
Radek Krejci201963a2020-12-03 11:43:40 +0100816 lyjson_ctx_set_value(jsonctx, "", 0, 0);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100817 ly_in_skip(jsonctx->in, ly_strlen_const("null"));
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100818 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NULL);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200819 LY_CHECK_RET(lyjson_check_next(jsonctx));
820
821 } else if (*jsonctx->in->current == '"') {
822 /* string */
823 ly_in_skip(jsonctx->in, 1);
824 LY_CHECK_RET(lyjson_string(jsonctx));
825
826 } else if (*jsonctx->in->current == '[') {
827 /* array */
828 ly_in_skip(jsonctx->in, 1);
829 LY_CHECK_RET(lyjson_array(jsonctx));
830
831 } else if (*jsonctx->in->current == '{') {
aPiecek93582ed2021-05-25 14:49:06 +0200832 jsonctx->depth++;
833 if (jsonctx->depth > LY_MAX_BLOCK_DEPTH) {
834 LOGERR(jsonctx->ctx, LY_EINVAL,
835 "The maximum number of block nestings has been exceeded.");
836 return LY_EINVAL;
837 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200838 /* object */
839 ly_in_skip(jsonctx->in, 1);
840 LY_CHECK_RET(lyjson_object(jsonctx));
841
Michal Vasko69730152020-10-09 16:30:07 +0200842 } else if ((*jsonctx->in->current == '-') || ((*jsonctx->in->current >= '0') && (*jsonctx->in->current <= '9'))) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200843 /* number */
844 LY_CHECK_RET(lyjson_number(jsonctx));
845
846 } else {
847 /* unexpected value */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100848 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
Michal Vasko69730152020-10-09 16:30:07 +0200849 jsonctx->in->current, "a JSON value");
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200850 return LY_EVALID;
851 }
852
853 return LY_SUCCESS;
854}
855
856LY_ERR
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100857lyjson_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 +0200858{
859 LY_ERR ret = LY_SUCCESS;
860 struct lyjson_ctx *jsonctx;
861
862 assert(ctx);
863 assert(in);
864 assert(jsonctx_p);
865
866 /* new context */
867 jsonctx = calloc(1, sizeof *jsonctx);
868 LY_CHECK_ERR_RET(!jsonctx, LOGMEM(ctx), LY_EMEM);
869 jsonctx->ctx = ctx;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200870 jsonctx->in = in;
871
Michal Vaskof8ebf132022-11-21 14:06:48 +0100872 LOG_LOCSET(NULL, NULL, NULL, in);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100873
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200874 /* parse JSON value, if any */
875 LY_CHECK_GOTO(ret = skip_ws(jsonctx), cleanup);
876 if (lyjson_ctx_status(jsonctx, 0) == LYJSON_END) {
877 /* empty data input */
878 goto cleanup;
879 }
880
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100881 if (subtree) {
882 ret = lyjson_object(jsonctx);
883 jsonctx->depth++;
884 } else {
885 ret = lyjson_value(jsonctx);
886 }
Michal Vasko69730152020-10-09 16:30:07 +0200887 if ((jsonctx->status.count > 1) && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100888 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200889 ret = LY_EVALID;
890 }
891
892cleanup:
893 if (ret) {
894 lyjson_ctx_free(jsonctx);
895 } else {
896 *jsonctx_p = jsonctx;
897 }
898 return ret;
899}
900
901void
902lyjson_ctx_backup(struct lyjson_ctx *jsonctx)
903{
904 if (jsonctx->backup.dynamic) {
905 free((char *)jsonctx->backup.value);
906 }
907 jsonctx->backup.status = lyjson_ctx_status(jsonctx, 0);
908 jsonctx->backup.status_count = jsonctx->status.count;
909 jsonctx->backup.value = jsonctx->value;
910 jsonctx->backup.value_len = jsonctx->value_len;
911 jsonctx->backup.input = jsonctx->in->current;
912 jsonctx->backup.dynamic = jsonctx->dynamic;
aPiecek93582ed2021-05-25 14:49:06 +0200913 jsonctx->backup.depth = jsonctx->depth;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200914 jsonctx->dynamic = 0;
915}
916
917void
918lyjson_ctx_restore(struct lyjson_ctx *jsonctx)
919{
920 if (jsonctx->dynamic) {
921 free((char *)jsonctx->value);
922 }
923 jsonctx->status.count = jsonctx->backup.status_count;
Michal Vasko22df3f02020-08-24 13:29:22 +0200924 jsonctx->status.objs[jsonctx->backup.status_count - 1] = (void *)jsonctx->backup.status;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200925 jsonctx->value = jsonctx->backup.value;
926 jsonctx->value_len = jsonctx->backup.value_len;
927 jsonctx->in->current = jsonctx->backup.input;
928 jsonctx->dynamic = jsonctx->backup.dynamic;
aPiecek93582ed2021-05-25 14:49:06 +0200929 jsonctx->depth = jsonctx->backup.depth;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200930 jsonctx->backup.dynamic = 0;
931}
932
933LY_ERR
934lyjson_ctx_next(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status)
935{
936 LY_ERR ret = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +0200937 ly_bool toplevel = 0;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200938 enum LYJSON_PARSER_STATUS prev;
939
940 assert(jsonctx);
941
942 prev = lyjson_ctx_status(jsonctx, 0);
943
Michal Vasko69730152020-10-09 16:30:07 +0200944 if ((prev == LYJSON_OBJECT) || (prev == LYJSON_ARRAY)) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200945 /* get value for the object's member OR the first value in the array */
946 ret = lyjson_value(jsonctx);
947 goto result;
948 } else {
949 /* the previous token is closed and should be completely processed */
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100950 LYJSON_STATUS_POP_RET(jsonctx);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200951 prev = lyjson_ctx_status(jsonctx, 0);
952 }
953
954 if (!jsonctx->status.count) {
955 /* we are done with the top level value */
956 toplevel = 1;
957 }
958 LY_CHECK_RET(skip_ws(jsonctx));
959 if (toplevel && !jsonctx->status.count) {
960 /* EOF expected, but there are some data after the top level token */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100961 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 +0200962 return LY_EVALID;
963 }
964
965 if (toplevel) {
966 /* we are done */
Michal Vasko55bce0e2022-02-15 10:46:08 +0100967 goto result;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200968 }
969
970 /* continue with the next token */
971 assert(prev == LYJSON_OBJECT || prev == LYJSON_ARRAY);
972
973 if (*jsonctx->in->current == ',') {
974 /* sibling item in the ... */
975 ly_in_skip(jsonctx->in, 1);
976 LY_CHECK_RET(skip_ws(jsonctx));
977
978 if (prev == LYJSON_OBJECT) {
979 /* ... object - get another object's member */
980 ret = lyjson_object_name(jsonctx);
981 } else { /* LYJSON_ARRAY */
982 /* ... array - get another complete value */
983 ret = lyjson_value(jsonctx);
984 }
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100985 } else if (((prev == LYJSON_OBJECT) && (*jsonctx->in->current == '}')) ||
986 ((prev == LYJSON_ARRAY) && (*jsonctx->in->current == ']'))) {
aPiecek93582ed2021-05-25 14:49:06 +0200987 if (*jsonctx->in->current == '}') {
988 assert(jsonctx->depth);
989 jsonctx->depth--;
990 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200991 ly_in_skip(jsonctx->in, 1);
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100992 LYJSON_STATUS_POP_RET(jsonctx);
993 LYJSON_STATUS_PUSH_RET(jsonctx, prev + 1);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200994 } else {
995 /* unexpected value */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100996 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
997 prev == LYJSON_ARRAY ? "another JSON value in array" : "another JSON object's member");
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200998 return LY_EVALID;
999 }
1000
1001result:
Michal Vasko69730152020-10-09 16:30:07 +02001002 if ((ret == LY_SUCCESS) && (jsonctx->status.count > 1) && (lyjson_ctx_status(jsonctx, 0) == LYJSON_END)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001003 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001004 ret = LY_EVALID;
1005 }
1006
Michal Vasko69730152020-10-09 16:30:07 +02001007 if ((ret == LY_SUCCESS) && status) {
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001008 *status = lyjson_ctx_status(jsonctx, 0);
1009 }
1010
1011 return ret;
1012}
1013
1014enum LYJSON_PARSER_STATUS
1015lyjson_ctx_status(struct lyjson_ctx *jsonctx, uint32_t index)
1016{
1017 assert(jsonctx);
1018
1019 if (jsonctx->status.count < index) {
1020 return LYJSON_ERROR;
1021 } else if (jsonctx->status.count == index) {
1022 return LYJSON_ROOT;
1023 } else {
Michal Vasko27915722020-08-31 14:54:42 +02001024 return (enum LYJSON_PARSER_STATUS)(uintptr_t)jsonctx->status.objs[jsonctx->status.count - (index + 1)];
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001025 }
1026}
1027
1028void
1029lyjson_ctx_free(struct lyjson_ctx *jsonctx)
1030{
1031 if (!jsonctx) {
1032 return;
1033 }
1034
Radek Krejciddace2c2021-01-08 11:30:56 +01001035 LOG_LOCBACK(0, 0, 0, 1);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001036
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001037 if (jsonctx->dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +02001038 free((char *)jsonctx->value);
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001039 }
1040 if (jsonctx->backup.dynamic) {
1041 free((char *)jsonctx->backup.value);
1042 }
1043
1044 ly_set_erase(&jsonctx->status, NULL);
1045
1046 free(jsonctx);
1047}