blob: 4b252b70588c9712455e57f85700f7fe7b1301aa [file] [log] [blame]
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001/**
2 * @file json.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko09e04632023-03-22 14:34:10 +01004 * @author Michal Vasko <mvasko@cesnet.cz>
Radek Krejci50f0c6b2020-06-18 16:31:48 +02005 * @brief Generic JSON format parser for libyang
6 *
Michal Vasko09e04632023-03-22 14:34:10 +01007 * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
Radek Krejci50f0c6b2020-06-18 16:31:48 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
16#include <assert.h>
17#include <ctype.h>
18#include <errno.h>
Radek Krejci50f0c6b2020-06-18 16:31:48 +020019#include <stdlib.h>
Radek Krejci47fab892020-11-05 17:02:41 +010020#include <string.h>
Radek Krejci50f0c6b2020-06-18 16:31:48 +020021#include <sys/types.h>
22
Michal Vaskoafac7822020-10-20 14:22:26 +020023#include "in_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010024#include "json.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010025#include "ly_common.h"
aPiecek704f8e92021-08-25 13:35:05 +020026#include "tree_schema_internal.h"
Radek Krejci50f0c6b2020-06-18 16:31:48 +020027
Michal Vasko22df3f02020-08-24 13:29:22 +020028const char *
Radek Krejci50f0c6b2020-06-18 16:31:48 +020029lyjson_token2str(enum LYJSON_PARSER_STATUS status)
30{
31 switch (status) {
32 case LYJSON_ERROR:
33 return "error";
Radek Krejci50f0c6b2020-06-18 16:31:48 +020034 case LYJSON_OBJECT:
35 return "object";
Michal Vasko09e04632023-03-22 14:34:10 +010036 case LYJSON_OBJECT_NEXT:
37 return "object next";
Radek Krejci50f0c6b2020-06-18 16:31:48 +020038 case LYJSON_OBJECT_CLOSED:
39 return "object closed";
Radek Krejci50f0c6b2020-06-18 16:31:48 +020040 case LYJSON_ARRAY:
41 return "array";
Michal Vasko09e04632023-03-22 14:34:10 +010042 case LYJSON_ARRAY_NEXT:
43 return "array next";
Radek Krejci50f0c6b2020-06-18 16:31:48 +020044 case LYJSON_ARRAY_CLOSED:
45 return "array closed";
Michal Vasko09e04632023-03-22 14:34:10 +010046 case LYJSON_OBJECT_NAME:
47 return "object name";
Radek Krejci50f0c6b2020-06-18 16:31:48 +020048 case LYJSON_NUMBER:
49 return "number";
50 case LYJSON_STRING:
51 return "string";
Michal Vasko09e04632023-03-22 14:34:10 +010052 case LYJSON_TRUE:
53 return "true";
54 case LYJSON_FALSE:
55 return "false";
56 case LYJSON_NULL:
57 return "null";
Radek Krejci50f0c6b2020-06-18 16:31:48 +020058 case LYJSON_END:
59 return "end of input";
60 }
61
62 return "";
63}
64
Michal Vasko09e04632023-03-22 14:34:10 +010065enum LYJSON_PARSER_STATUS
66lyjson_ctx_status(struct lyjson_ctx *jsonctx)
Radek Krejci50f0c6b2020-06-18 16:31:48 +020067{
Michal Vasko09e04632023-03-22 14:34:10 +010068 assert(jsonctx);
69
70 if (!jsonctx->status.count) {
71 return LYJSON_END;
72 }
73
74 return (enum LYJSON_PARSER_STATUS)(uintptr_t)jsonctx->status.objs[jsonctx->status.count - 1];
75}
76
77uint32_t
78lyjson_ctx_depth(struct lyjson_ctx *jsonctx)
79{
80 return jsonctx->status.count;
81}
82
83/**
84 * @brief Skip WS in the JSON context.
85 *
86 * @param[in] jsonctx JSON parser context.
87 */
88static void
89lyjson_skip_ws(struct lyjson_ctx *jsonctx)
90{
91 /* skip whitespaces */
92 while (is_jsonws(*jsonctx->in->current)) {
Radek Krejcidd713ce2021-01-04 23:12:12 +010093 if (*jsonctx->in->current == '\n') {
94 LY_IN_NEW_LINE(jsonctx->in);
95 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +020096 ly_in_skip(jsonctx->in, 1);
97 }
Radek Krejci50f0c6b2020-06-18 16:31:48 +020098}
99
Michal Vasko09e04632023-03-22 14:34:10 +0100100/**
101 * @brief Set value in the JSON context.
102 *
103 * @param[in] jsonctx JSON parser context.
104 * @param[in] value Value to set.
105 * @param[in] value_len Length of @p value.
106 * @param[in] dynamic Whether @p value is dynamically-allocated.
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200107 */
108static void
Radek Krejci857189e2020-09-01 13:26:36 +0200109lyjson_ctx_set_value(struct lyjson_ctx *jsonctx, const char *value, size_t value_len, ly_bool dynamic)
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200110{
111 assert(jsonctx);
112
Juraj Vijtiukec285cd2021-01-14 11:41:20 +0100113 if (jsonctx->dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200114 free((char *)jsonctx->value);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200115 }
116 jsonctx->value = value;
117 jsonctx->value_len = value_len;
118 jsonctx->dynamic = dynamic;
119}
120
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200121/**
Michal Vasko09e04632023-03-22 14:34:10 +0100122 * @brief Parse a JSON string (starting after double quotes) and store it in the context.
123 *
124 * @param[in] jsonctx JSON parser context.
125 * @return LY_ERR value.
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200126 */
127static LY_ERR
Michal Vasko09e04632023-03-22 14:34:10 +0100128lyjson_string(struct lyjson_ctx *jsonctx)
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200129{
Michal Vasko09e04632023-03-22 14:34:10 +0100130 const char *in = jsonctx->in->current, *start, *c;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200131 char *buf = NULL;
132 size_t offset; /* read offset in input buffer */
133 size_t len; /* length of the output string (write offset in output buffer) */
134 size_t size = 0; /* size of the output buffer */
135 size_t u;
Michal Vasko7a266772024-01-23 11:02:38 +0100136 uint64_t start_line, orig_line;
Michal Vasko09e04632023-03-22 14:34:10 +0100137 uint32_t value;
138 uint8_t i;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200139
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]) {
Michal Vasko09e04632023-03-22 14:34:10 +0100149 switch (in[offset]) {
150 case '\\':
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200151 /* escape sequence */
Michal Vasko09e04632023-03-22 14:34:10 +0100152 c = &in[offset];
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200153 if (!buf) {
154 /* prepare output buffer */
Michal Vasko09e04632023-03-22 14:34:10 +0100155 buf = malloc(LYJSON_STRING_BUF_START);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200156 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
Michal Vasko09e04632023-03-22 14:34:10 +0100157 size = LYJSON_STRING_BUF_START;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200158 }
159
160 /* allocate enough for the offset and next character,
161 * we will need 4 bytes at most since we support only the predefined
162 * (one-char) entities and character references */
163 if (len + offset + 4 >= size) {
Juraj Vijtiukd746a352021-01-15 11:33:33 +0100164 size_t increment;
Michal Vasko2bf4af42023-01-04 12:08:38 +0100165
Michal Vasko09e04632023-03-22 14:34:10 +0100166 for (increment = LYJSON_STRING_BUF_STEP; len + offset + 4 >= size + increment; increment += LYJSON_STRING_BUF_STEP) {}
Juraj Vijtiukd746a352021-01-15 11:33:33 +0100167 buf = ly_realloc(buf, size + increment);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200168 LY_CHECK_ERR_RET(!buf, LOGMEM(jsonctx->ctx), LY_EMEM);
Michal Vasko09e04632023-03-22 14:34:10 +0100169 size += LYJSON_STRING_BUF_STEP;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200170 }
171
172 if (offset) {
173 /* store what we have so far */
174 memcpy(&buf[len], in, offset);
175 len += offset;
176 in += offset;
177 offset = 0;
178 }
179
Michal Vasko09e04632023-03-22 14:34:10 +0100180 i = 1;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200181 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 Vasko09e04632023-03-22 14:34:10 +0100219 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid basic multilingual plane character \"%s\".", c);
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),
Michal Vasko21eaa392024-02-20 15:48:42 +0100240 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character reference \"%.*s\" (0x%08" PRIx32 ").",
Michal Vasko09e04632023-03-22 14:34:10 +0100241 (int)(&in[offset] - c), c, 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 */
Michal Vasko09e04632023-03-22 14:34:10 +0100246 break;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200247
Michal Vasko09e04632023-03-22 14:34:10 +0100248 case '"':
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200249 /* 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;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200266
Michal Vasko09e04632023-03-22 14:34:10 +0100267 default:
268 /* get it as UTF-8 character for check */
269 c = &in[offset];
270 LY_CHECK_ERR_GOTO(ly_getutf8(&c, &value, &u),
Radek Krejci2efc45b2020-12-22 16:25:44 +0100271 LOGVAL(jsonctx->ctx, LY_VCODE_INCHAR, in[offset]), error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200272
Michal Vasko09e04632023-03-22 14:34:10 +0100273 LY_CHECK_ERR_GOTO(!is_jsonstrchar(value),
Michal Vasko21eaa392024-02-20 15:48:42 +0100274 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character in JSON string \"%.*s\" (0x%08" PRIx32 ").",
Michal Vasko09e04632023-03-22 14:34:10 +0100275 (int)(&in[offset] - start + u), start, value),
Michal Vasko69730152020-10-09 16:30:07 +0200276 error);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200277
278 /* character is ok, continue */
Michal Vasko09e04632023-03-22 14:34:10 +0100279 offset += u;
280 break;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200281 }
282 }
283
284 /* EOF reached before endchar */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100285 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Michal Vasko7a266772024-01-23 11:02:38 +0100286 orig_line = jsonctx->in->line;
287 jsonctx->in->line = start_line;
288 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Missing quotation-mark at the end of a JSON string.");
289 jsonctx->in->line = orig_line;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200290
291error:
292 free(buf);
293 return LY_EVALID;
294
295success:
Radek Krejcid54412f2020-12-17 20:25:35 +0100296 jsonctx->in->current = in;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200297 if (buf) {
298 lyjson_ctx_set_value(jsonctx, buf, len, 1);
299 } else {
300 lyjson_ctx_set_value(jsonctx, start, len, 0);
301 }
302
303 return LY_SUCCESS;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200304}
305
aPieceke87c0a12021-05-13 15:43:26 +0200306/**
aPiecek76034c32021-06-08 15:03:11 +0200307 * @brief Calculate how many @p c characters there are in a row.
308 *
309 * @param[in] str Count from this position.
310 * @param[in] end Position after the last checked character.
311 * @param[in] c Checked character.
312 * @param[in] backwards Set to 1, if to proceed from end-1 to str.
313 * @return Number of characters in a row.
314 */
315static uint32_t
316lyjson_count_in_row(const char *str, const char *end, char c, ly_bool backwards)
317{
318 uint32_t cnt;
319
320 assert(str && end);
321
322 if (str >= end) {
323 return 0;
324 }
325
326 if (!backwards) {
327 for (cnt = 0; (str != end) && (*str == c); ++str, ++cnt) {}
328 } else {
329 --end;
330 --str;
331 for (cnt = 0; (str != end) && (*end == c); --end, ++cnt) {}
332 }
333
334 return cnt;
335}
336
337/**
338 * @brief Check if the number can be shortened to zero.
339 *
aPiecek76034c32021-06-08 15:03:11 +0200340 * @param[in] in Start of input string;
341 * @param[in] end End of input string;
342 * @return 1 if number is zero, otherwise 0.
343 */
344static ly_bool
345lyjson_number_is_zero(const char *in, const char *end)
346{
aPiecek28e101a2021-06-10 09:09:31 +0200347 assert(in < end);
aPiecek76034c32021-06-08 15:03:11 +0200348
349 if ((in[0] == '-') || (in[0] == '+')) {
350 in++;
aPiecek28e101a2021-06-10 09:09:31 +0200351 assert(in < end);
aPiecek76034c32021-06-08 15:03:11 +0200352 }
353 if ((in[0] == '0') && (in[1] == '.')) {
354 in += 2;
aPiecek28e101a2021-06-10 09:09:31 +0200355 if (!(in < end)) {
356 return 1;
357 }
aPiecek76034c32021-06-08 15:03:11 +0200358 }
359
Michal Vasko21eaa392024-02-20 15:48:42 +0100360 return lyjson_count_in_row(in, end, '0', 0) == (uint32_t)(end - in);
aPiecek76034c32021-06-08 15:03:11 +0200361}
362
363/**
aPieceke87c0a12021-05-13 15:43:26 +0200364 * @brief Allocate buffer for number in string format.
365 *
366 * @param[in] jsonctx JSON context.
367 * @param[in] num_len Required space in bytes for a number.
368 * Terminating null byte is added by default.
369 * @param[out] buffer Output allocated buffer.
370 * @return LY_ERR value.
371 */
372static LY_ERR
aPiecek0ba088e2021-06-15 12:53:17 +0200373lyjson_get_buffer_for_number(const struct ly_ctx *ctx, uint64_t num_len, char **buffer)
aPieceke87c0a12021-05-13 15:43:26 +0200374{
375 *buffer = NULL;
376
aPiecek76034c32021-06-08 15:03:11 +0200377 LY_CHECK_ERR_RET((num_len + 1) > LY_NUMBER_MAXLEN, LOGVAL(ctx, LYVE_SEMANTICS,
aPieceke87c0a12021-05-13 15:43:26 +0200378 "Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit."), LY_EVALID);
379
aPiecek76034c32021-06-08 15:03:11 +0200380 /* allocate buffer for the result (add NULL-byte) */
aPieceke87c0a12021-05-13 15:43:26 +0200381 *buffer = malloc(num_len + 1);
aPiecek76034c32021-06-08 15:03:11 +0200382 LY_CHECK_ERR_RET(!(*buffer), LOGMEM(ctx), LY_EMEM);
383 return LY_SUCCESS;
384}
385
386/**
387 * @brief Copy the 'numeric part' (@p num) except its decimal point
388 * (@p dec_point) and insert the new decimal point (@p dp_position)
389 * only if it is to be placed in the 'numeric part' range (@p num).
390 *
391 * @param[in] num Begin of the 'numeric part'.
392 * @param[in] num_len Length of the 'numeric part'.
393 * @param[in] dec_point Pointer to the old decimal point.
394 * If it has a NULL value, it is ignored.
395 * @param[in] dp_position Position of the new decimal point.
396 * If it has a negative value, it is ignored.
397 * @param[out] dst Memory into which the copied result is written.
398 * @return Number of characters written to the @p dst.
399 */
400static uint32_t
Michal Vasko09e04632023-03-22 14:34:10 +0100401lyjson_exp_number_copy_num_part(const char *num, uint32_t num_len, char *dec_point, int32_t dp_position, char *dst)
aPiecek76034c32021-06-08 15:03:11 +0200402{
403 int32_t dec_point_idx;
404 int32_t n, d;
405
406 assert(num && dst);
407
408 dec_point_idx = dec_point ? dec_point - num : INT32_MAX;
409 assert((dec_point_idx >= 0) && (dec_point_idx != dp_position));
410
411 for (n = 0, d = 0; (uint32_t)n < num_len; n++) {
412 if (n == dec_point_idx) {
413 continue;
414 } else if (d == dp_position) {
415 dst[d++] = '.';
416 dst[d++] = num[n];
417 } else {
418 dst[d++] = num[n];
419 }
420 }
421
422 return d;
423}
424
425/**
426 * @brief Convert JSON number with exponent into the representation
427 * used by YANG.
428 *
429 * The input numeric string must be syntactically valid. Also, before
430 * calling this function, checks should be performed using the
431 * ::lyjson_number_is_zero().
432 *
433 * @param[in] ctx Context for the error message.
434 * @param[in] in Beginning of the string containing the number.
435 * @param[in] exponent Pointer to the letter E/e.
436 * @param[in] total_len Total size of the input number.
437 * @param[out] res Conversion result.
438 * @param[out] res_len Length of the result.
439 * @return LY_ERR value.
440 */
441static LY_ERR
Michal Vasko09e04632023-03-22 14:34:10 +0100442lyjson_exp_number(const struct ly_ctx *ctx, const char *in, const char *exponent, uint64_t total_len, char **res,
443 size_t *res_len)
aPiecek76034c32021-06-08 15:03:11 +0200444{
445
446#define MAYBE_WRITE_MINUS(ARRAY, INDEX, FLAG) \
447 if (FLAG) { \
448 ARRAY[INDEX++] = '-'; \
449 }
450
451/* Length of leading zero followed by the decimal point. */
452#define LEADING_ZERO 1
453
454/* Flags for the ::lyjson_count_in_row() */
455#define FORWARD 0
456#define BACKWARD 1
457
458 /* Buffer where the result is stored. */
459 char *buf;
460 /* Size without space for terminating NULL-byte. */
aPiecek0ba088e2021-06-15 12:53:17 +0200461 uint64_t buf_len;
aPiecek76034c32021-06-08 15:03:11 +0200462 /* Index to buf. */
463 uint32_t i = 0;
464 /* A 'numeric part' doesn't contain a minus sign or an leading zero.
465 * For example, in 0.45, there is the leading zero.
466 */
467 const char *num;
468 /* Length of the 'numeric part' ends before E/e. */
aPiecek0ba088e2021-06-15 12:53:17 +0200469 uint16_t num_len;
aPiecek76034c32021-06-08 15:03:11 +0200470 /* Position of decimal point in the num. */
471 char *dec_point;
472 /* Final position of decimal point in the buf. */
473 int32_t dp_position;
474 /* Exponent as integer. */
Michal Vasko2bf4af42023-01-04 12:08:38 +0100475 long long e_val;
aPiecek76034c32021-06-08 15:03:11 +0200476 /* Byte for the decimal point. */
477 int8_t dot;
478 /* Required additional byte for the minus sign. */
479 uint8_t minus;
480 /* The number of zeros. */
481 long zeros;
482 /* If the number starts with leading zero followed by the decimal point. */
483 ly_bool leading_zero;
484
485 assert(ctx && in && exponent && res && res_len && (total_len > 2));
486 assert((in < exponent) && ((*exponent == 'e') || (*exponent == 'E')));
487
aPiecek0ba088e2021-06-15 12:53:17 +0200488 if ((exponent - in) > UINT16_MAX) {
489 LOGVAL(ctx, LYVE_SEMANTICS, "JSON number is too long.");
490 return LY_EVALID;
491 }
492
aPiecek76034c32021-06-08 15:03:11 +0200493 /* Convert exponent. */
494 errno = 0;
Michal Vasko73d77ab2021-07-23 12:45:55 +0200495 e_val = strtoll(exponent + 1, NULL, LY_BASE_DEC);
aPieceke4e0d6c2021-07-01 12:02:54 +0200496 if (errno || (e_val > UINT16_MAX) || (e_val < -UINT16_MAX)) {
aPiecek76034c32021-06-08 15:03:11 +0200497 LOGVAL(ctx, LYVE_SEMANTICS,
498 "Exponent out-of-bounds in a JSON Number value (%.*s).",
Michal Vasko54ba8912021-07-23 12:46:23 +0200499 (int)total_len, in);
aPiecek76034c32021-06-08 15:03:11 +0200500 return LY_EVALID;
501 }
502
503 minus = in[0] == '-';
504 if (in[minus] == '0') {
505 assert(in[minus + 1] == '.');
506 leading_zero = 1;
507 /* The leading zero has been found, it will be skipped. */
508 num = &in[minus + 1];
509 } else {
510 leading_zero = 0;
511 /* Set to the first number. */
512 num = &in[minus];
513 }
514 num_len = exponent - num;
515
516 /* Find the location of the decimal points. */
517 dec_point = ly_strnchr(num, '.', num_len);
518 dp_position = dec_point ?
519 dec_point - num + e_val :
520 num_len + e_val;
521
522 /* Remove zeros after the decimal point from the end of
523 * the 'numeric part' because these are useless.
524 * (For example, in 40.001000 these are the last 3).
525 */
526 num_len -= dp_position > 0 ?
527 lyjson_count_in_row(num + dp_position - 1, exponent, '0', BACKWARD) :
528 lyjson_count_in_row(num, exponent, '0', BACKWARD);
529
530 /* Decide what to do with the dot from the 'numeric part'. */
531 if (dec_point && ((int32_t)(num_len - 1) == dp_position)) {
532 /* Decimal point in the last place is useless. */
533 dot = -1;
534 } else if (dec_point) {
535 /* Decimal point is shifted. */
536 dot = 0;
537 } else {
538 /* Additional byte for the decimal point is requred. */
539 dot = 1;
540 }
541
542 /* Final composition of the result. */
543 if (dp_position <= 0) {
544 /* Adding decimal point before the integer with adding additional zero(s). */
545
546 zeros = labs(dp_position);
547 buf_len = minus + LEADING_ZERO + dot + zeros + num_len;
548 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
549 MAYBE_WRITE_MINUS(buf, i, minus);
550 buf[i++] = '0';
551 buf[i++] = '.';
552 memset(buf + i, '0', zeros);
553 i += zeros;
554 dp_position = -1;
555 lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
556 } else if (leading_zero && (dp_position < (ssize_t)num_len)) {
557 /* Insert decimal point between the integer's digits. */
558
559 /* Set a new range of 'numeric part'. Old decimal point is skipped. */
560 num++;
561 num_len--;
562 dp_position--;
563 /* Get the number of useless zeros between the old
564 * and new decimal point. For example, in the number 0.005E1,
565 * there is one useless zero.
566 */
567 zeros = lyjson_count_in_row(num, num + dp_position + 1, '0', FORWARD);
568 /* If the new decimal point will be in the place of the first non-zero subnumber. */
569 if (zeros == (dp_position + 1)) {
570 /* keep one zero as leading zero */
571 zeros--;
572 /* new decimal point will be behind the leading zero */
573 dp_position = 1;
574 dot = 1;
575 } else {
576 dot = 0;
577 }
578 buf_len = minus + dot + (num_len - zeros);
579 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
580 MAYBE_WRITE_MINUS(buf, i, minus);
581 /* Skip useless zeros and copy. */
582 lyjson_exp_number_copy_num_part(num + zeros, num_len - zeros, NULL, dp_position, buf + i);
583 } else if (dp_position < (ssize_t)num_len) {
584 /* Insert decimal point between the integer's digits. */
585
586 buf_len = minus + dot + num_len;
587 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
588 MAYBE_WRITE_MINUS(buf, i, minus);
589 lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
590 } else if (leading_zero) {
591 /* Adding decimal point after the decimal value make the integer result. */
592
593 /* Set a new range of 'numeric part'. Old decimal point is skipped. */
594 num++;
595 num_len--;
596 /* Get the number of useless zeros. */
597 zeros = lyjson_count_in_row(num, num + num_len, '0', FORWARD);
598 buf_len = minus + dp_position - zeros;
599 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
600 MAYBE_WRITE_MINUS(buf, i, minus);
601 /* Skip useless zeros and copy. */
602 i += lyjson_exp_number_copy_num_part(num + zeros, num_len - zeros, NULL, dp_position, buf + i);
603 /* Add multiples of ten behind the 'numeric part'. */
604 memset(buf + i, '0', buf_len - i);
605 } else {
606 /* Adding decimal point after the decimal value make the integer result. */
607
608 buf_len = minus + dp_position;
609 LY_CHECK_RET(lyjson_get_buffer_for_number(ctx, buf_len, &buf));
610 MAYBE_WRITE_MINUS(buf, i, minus);
611 i += lyjson_exp_number_copy_num_part(num, num_len, dec_point, dp_position, buf + i);
612 /* Add multiples of ten behind the 'numeric part'. */
613 memset(buf + i, '0', buf_len - i);
614 }
615
616 buf[buf_len] = '\0';
617 *res = buf;
618 *res_len = buf_len;
619
620#undef MAYBE_WRITE_MINUS
621#undef LEADING_ZERO
622#undef FORWARD
623#undef BACKWARD
624
aPieceke87c0a12021-05-13 15:43:26 +0200625 return LY_SUCCESS;
626}
627
Michal Vasko09e04632023-03-22 14:34:10 +0100628/**
629 * @brief Parse a JSON number and store it in the context.
630 *
631 * @param[in] jsonctx JSON parser context.
632 * @return LY_ERR value.
633 */
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200634static LY_ERR
635lyjson_number(struct lyjson_ctx *jsonctx)
636{
aPiecek76034c32021-06-08 15:03:11 +0200637 size_t offset = 0, num_len;
638 const char *in = jsonctx->in->current, *exponent = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200639 uint8_t minus = 0;
aPiecek76034c32021-06-08 15:03:11 +0200640 char *num;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200641
642 if (in[offset] == '-') {
643 ++offset;
644 minus = 1;
645 }
646
647 if (in[offset] == '0') {
648 ++offset;
649 } else if (isdigit(in[offset])) {
650 ++offset;
651 while (isdigit(in[offset])) {
652 ++offset;
653 }
654 } else {
655invalid_character:
656 if (in[offset]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100657 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Invalid character in JSON Number value (\"%c\").", in[offset]);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200658 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100659 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200660 }
661 return LY_EVALID;
662 }
663
664 if (in[offset] == '.') {
665 ++offset;
666 if (!isdigit(in[offset])) {
667 goto invalid_character;
668 }
669 while (isdigit(in[offset])) {
670 ++offset;
671 }
672 }
673
674 if ((in[offset] == 'e') || (in[offset] == 'E')) {
aPiecek76034c32021-06-08 15:03:11 +0200675 exponent = &in[offset];
676 ++offset;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200677 if ((in[offset] == '+') || (in[offset] == '-')) {
678 ++offset;
679 }
680 if (!isdigit(in[offset])) {
681 goto invalid_character;
682 }
683 while (isdigit(in[offset])) {
684 ++offset;
685 }
686 }
687
aPiecek76034c32021-06-08 15:03:11 +0200688 if (lyjson_number_is_zero(in, exponent ? exponent : &in[offset])) {
689 lyjson_ctx_set_value(jsonctx, in, minus + 1, 0);
690 } else if (exponent && lyjson_number_is_zero(exponent + 1, &in[offset])) {
691 lyjson_ctx_set_value(jsonctx, in, exponent - in, 0);
692 } else if (exponent) {
693 LY_CHECK_RET(lyjson_exp_number(jsonctx->ctx, in, exponent, offset, &num, &num_len));
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200694 lyjson_ctx_set_value(jsonctx, num, num_len, 1);
695 } else {
aPiecek5b6dd182021-06-10 09:11:58 +0200696 if (offset > LY_NUMBER_MAXLEN) {
697 LOGVAL(jsonctx->ctx, LYVE_SEMANTICS,
698 "Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit.");
699 return LY_EVALID;
700 }
aPiecek76034c32021-06-08 15:03:11 +0200701 lyjson_ctx_set_value(jsonctx, in, offset, 0);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200702 }
703 ly_in_skip(jsonctx->in, offset);
704
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200705 return LY_SUCCESS;
706}
707
708LY_ERR
Michal Vasko09e04632023-03-22 14:34:10 +0100709lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, struct lyjson_ctx **jsonctx_p)
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200710{
711 LY_ERR ret = LY_SUCCESS;
712 struct lyjson_ctx *jsonctx;
713
Michal Vasko09e04632023-03-22 14:34:10 +0100714 assert(ctx && in && jsonctx_p);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200715
716 /* new context */
717 jsonctx = calloc(1, sizeof *jsonctx);
718 LY_CHECK_ERR_RET(!jsonctx, LOGMEM(ctx), LY_EMEM);
719 jsonctx->ctx = ctx;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200720 jsonctx->in = in;
721
Michal Vasko7a266772024-01-23 11:02:38 +0100722 /* input line logging */
723 ly_log_location(NULL, NULL, NULL, in);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100724
Michal Vasko09e04632023-03-22 14:34:10 +0100725 /* WS are always expected to be skipped */
726 lyjson_skip_ws(jsonctx);
727
728 if (jsonctx->in->current[0] == '\0') {
729 /* empty file, invalid */
730 LOGVAL(jsonctx->ctx, LYVE_SYNTAX, "Empty JSON file.");
731 ret = LY_EVALID;
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200732 goto cleanup;
733 }
734
Michal Vasko09e04632023-03-22 14:34:10 +0100735 /* start JSON parsing */
736 LY_CHECK_GOTO(ret = lyjson_ctx_next(jsonctx, NULL), cleanup);
Radek Krejci50f0c6b2020-06-18 16:31:48 +0200737
738cleanup:
739 if (ret) {
740 lyjson_ctx_free(jsonctx);
741 } else {
742 *jsonctx_p = jsonctx;
743 }
744 return ret;
745}
746
Michal Vasko09e04632023-03-22 14:34:10 +0100747/**
748 * @brief Parse next JSON token, object-name is expected.
749 *
750 * @param[in] jsonctx JSON parser context.
751 * @return LY_ERR value.
752 */
753static LY_ERR
754lyjson_next_object_name(struct lyjson_ctx *jsonctx)
755{
756 switch (*jsonctx->in->current) {
757 case '\0':
758 /* EOF */
759 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
760 return LY_EVALID;
761
762 case '"':
763 /* object name */
764 ly_in_skip(jsonctx->in, 1);
765 LY_CHECK_RET(lyjson_string(jsonctx));
766 lyjson_skip_ws(jsonctx);
767
768 if (*jsonctx->in->current != ':') {
769 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current), jsonctx->in->current,
770 "a JSON value name-separator ':'");
771 return LY_EVALID;
772 }
773 ly_in_skip(jsonctx->in, 1);
774 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_NAME);
775 break;
776
777 case '}':
778 /* object end */
779 ly_in_skip(jsonctx->in, 1);
780 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_CLOSED);
781 break;
782
783 default:
784 /* unexpected value */
785 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
786 jsonctx->in->current, "a JSON object name");
787 return LY_EVALID;
788 }
789
790 return LY_SUCCESS;
791}
792
793/**
794 * @brief Parse next JSON token, value is expected.
795 *
796 * @param[in] jsonctx JSON parser context.
797 * @param[in] array_end Whether array-end is accepted or not.
798 * @return LY_ERR value.
799 */
800static LY_ERR
801lyjson_next_value(struct lyjson_ctx *jsonctx, ly_bool array_end)
802{
803 switch (*jsonctx->in->current) {
804 case '\0':
805 /* EOF */
806 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
807 return LY_EVALID;
808
809 case '"':
810 /* string */
811 ly_in_skip(jsonctx->in, 1);
812 LY_CHECK_RET(lyjson_string(jsonctx));
813 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_STRING);
814 break;
815
816 case '-':
817 case '0':
818 case '1':
819 case '2':
820 case '3':
821 case '4':
822 case '5':
823 case '6':
824 case '7':
825 case '8':
826 case '9':
827 /* number */
828 LY_CHECK_RET(lyjson_number(jsonctx));
829 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NUMBER);
830 break;
831
832 case '{':
833 /* object */
834 ly_in_skip(jsonctx->in, 1);
835 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT);
836 break;
837
838 case '[':
839 /* array */
840 ly_in_skip(jsonctx->in, 1);
841 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY);
842 break;
843
844 case 't':
845 if (strncmp(jsonctx->in->current + 1, "rue", ly_strlen_const("rue"))) {
846 goto unexpected_value;
847 }
848
849 /* true */
850 lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("true"), 0);
851 ly_in_skip(jsonctx->in, ly_strlen_const("true"));
852 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_TRUE);
853 break;
854
855 case 'f':
856 if (strncmp(jsonctx->in->current + 1, "alse", ly_strlen_const("alse"))) {
857 goto unexpected_value;
858 }
859
860 /* false */
861 lyjson_ctx_set_value(jsonctx, jsonctx->in->current, ly_strlen_const("false"), 0);
862 ly_in_skip(jsonctx->in, ly_strlen_const("false"));
863 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_FALSE);
864 break;
865
866 case 'n':
867 if (strncmp(jsonctx->in->current + 1, "ull", ly_strlen_const("ull"))) {
868 goto unexpected_value;
869 }
870
871 /* null */
872 lyjson_ctx_set_value(jsonctx, "", 0, 0);
873 ly_in_skip(jsonctx->in, ly_strlen_const("null"));
874 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_NULL);
875 break;
876
877 case ']':
878 if (!array_end) {
879 goto unexpected_value;
880 }
881
882 /* array end */
883 ly_in_skip(jsonctx->in, 1);
884 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_CLOSED);
885 break;
886
887 default:
888unexpected_value:
889 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
890 jsonctx->in->current, "a JSON value");
891 return LY_EVALID;
892 }
893
894 if (jsonctx->status.count > LY_MAX_BLOCK_DEPTH * 10) {
895 LOGERR(jsonctx->ctx, LY_EINVAL, "Maximum number %d of nestings has been exceeded.", LY_MAX_BLOCK_DEPTH * 10);
896 return LY_EINVAL;
897 }
898
899 return LY_SUCCESS;
900}
901
902/**
903 * @brief Parse next JSON token, object-next-item is expected.
904 *
905 * @param[in] jsonctx JSON parser context.
906 * @return LY_ERR value.
907 */
908static LY_ERR
909lyjson_next_object_item(struct lyjson_ctx *jsonctx)
910{
911 switch (*jsonctx->in->current) {
912 case '\0':
913 /* EOF */
914 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
915 return LY_EVALID;
916
917 case '}':
918 /* object end */
919 ly_in_skip(jsonctx->in, 1);
920 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_CLOSED);
921 break;
922
923 case ',':
924 /* next object item */
925 ly_in_skip(jsonctx->in, 1);
926 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_OBJECT_NEXT);
927 break;
928
929 default:
930 /* unexpected value */
931 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
932 jsonctx->in->current, "a JSON object-end or next item");
933 return LY_EVALID;
934 }
935
936 return LY_SUCCESS;
937}
938
939/**
940 * @brief Parse next JSON token, array-next-item is expected.
941 *
942 * @param[in] jsonctx JSON parser context.
943 * @return LY_ERR value.
944 */
945static LY_ERR
946lyjson_next_array_item(struct lyjson_ctx *jsonctx)
947{
948 switch (*jsonctx->in->current) {
949 case '\0':
950 /* EOF */
951 LOGVAL(jsonctx->ctx, LY_VCODE_EOF);
952 return LY_EVALID;
953
954 case ']':
955 /* array end */
956 ly_in_skip(jsonctx->in, 1);
957 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_CLOSED);
958 break;
959
960 case ',':
961 /* next array item */
962 ly_in_skip(jsonctx->in, 1);
963 LYJSON_STATUS_PUSH_RET(jsonctx, LYJSON_ARRAY_NEXT);
964 break;
965
966 default:
967 /* unexpected value */
968 LOGVAL(jsonctx->ctx, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(jsonctx->in->current),
969 jsonctx->in->current, "a JSON array-end or next item");
970 return LY_EVALID;
971 }
972
973 return LY_SUCCESS;
974}
975
976LY_ERR
977lyjson_ctx_next(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status)
978{
979 LY_ERR ret = LY_SUCCESS;
980 enum LYJSON_PARSER_STATUS cur;
981
982 assert(jsonctx);
983
984 cur = lyjson_ctx_status(jsonctx);
985 switch (cur) {
986 case LYJSON_OBJECT:
987 LY_CHECK_GOTO(ret = lyjson_next_object_name(jsonctx), cleanup);
988 break;
989 case LYJSON_ARRAY:
990 LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 1), cleanup);
991 break;
992 case LYJSON_OBJECT_NEXT:
993 LYJSON_STATUS_POP(jsonctx);
994 LY_CHECK_GOTO(ret = lyjson_next_object_name(jsonctx), cleanup);
995 break;
996 case LYJSON_ARRAY_NEXT:
997 LYJSON_STATUS_POP(jsonctx);
998 LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 0), cleanup);
999 break;
1000 case LYJSON_OBJECT_NAME:
1001 lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
1002 LYJSON_STATUS_POP(jsonctx);
1003 LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 0), cleanup);
1004 break;
1005 case LYJSON_OBJECT_CLOSED:
1006 case LYJSON_ARRAY_CLOSED:
1007 LYJSON_STATUS_POP(jsonctx);
1008 /* fallthrough */
1009 case LYJSON_NUMBER:
1010 case LYJSON_STRING:
1011 case LYJSON_TRUE:
1012 case LYJSON_FALSE:
1013 case LYJSON_NULL:
1014 lyjson_ctx_set_value(jsonctx, NULL, 0, 0);
1015 LYJSON_STATUS_POP(jsonctx);
1016 cur = lyjson_ctx_status(jsonctx);
1017
1018 if (cur == LYJSON_OBJECT) {
1019 LY_CHECK_GOTO(ret = lyjson_next_object_item(jsonctx), cleanup);
1020 break;
1021 } else if (cur == LYJSON_ARRAY) {
1022 LY_CHECK_GOTO(ret = lyjson_next_array_item(jsonctx), cleanup);
1023 break;
1024 }
1025
1026 assert(cur == LYJSON_END);
1027 goto cleanup;
1028 case LYJSON_END:
1029 LY_CHECK_GOTO(ret = lyjson_next_value(jsonctx, 0), cleanup);
1030 break;
1031 case LYJSON_ERROR:
1032 LOGINT(jsonctx->ctx);
1033 ret = LY_EINT;
1034 goto cleanup;
1035 }
1036
1037 /* skip WS */
1038 lyjson_skip_ws(jsonctx);
1039
1040cleanup:
1041 if (!ret && status) {
1042 *status = lyjson_ctx_status(jsonctx);
1043 }
1044 return ret;
1045}
1046
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001047void
1048lyjson_ctx_backup(struct lyjson_ctx *jsonctx)
1049{
1050 if (jsonctx->backup.dynamic) {
1051 free((char *)jsonctx->backup.value);
1052 }
Michal Vasko09e04632023-03-22 14:34:10 +01001053 jsonctx->backup.status = lyjson_ctx_status(jsonctx);
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001054 jsonctx->backup.status_count = jsonctx->status.count;
1055 jsonctx->backup.value = jsonctx->value;
1056 jsonctx->backup.value_len = jsonctx->value_len;
1057 jsonctx->backup.input = jsonctx->in->current;
1058 jsonctx->backup.dynamic = jsonctx->dynamic;
1059 jsonctx->dynamic = 0;
1060}
1061
1062void
1063lyjson_ctx_restore(struct lyjson_ctx *jsonctx)
1064{
1065 if (jsonctx->dynamic) {
1066 free((char *)jsonctx->value);
1067 }
1068 jsonctx->status.count = jsonctx->backup.status_count;
Michal Vasko22df3f02020-08-24 13:29:22 +02001069 jsonctx->status.objs[jsonctx->backup.status_count - 1] = (void *)jsonctx->backup.status;
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001070 jsonctx->value = jsonctx->backup.value;
1071 jsonctx->value_len = jsonctx->backup.value_len;
1072 jsonctx->in->current = jsonctx->backup.input;
1073 jsonctx->dynamic = jsonctx->backup.dynamic;
1074 jsonctx->backup.dynamic = 0;
1075}
1076
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001077void
1078lyjson_ctx_free(struct lyjson_ctx *jsonctx)
1079{
1080 if (!jsonctx) {
1081 return;
1082 }
1083
Michal Vasko7a266772024-01-23 11:02:38 +01001084 ly_log_location_revert(0, 0, 0, 1);
Radek Krejci2efc45b2020-12-22 16:25:44 +01001085
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001086 if (jsonctx->dynamic) {
Michal Vasko22df3f02020-08-24 13:29:22 +02001087 free((char *)jsonctx->value);
Radek Krejci50f0c6b2020-06-18 16:31:48 +02001088 }
1089 if (jsonctx->backup.dynamic) {
1090 free((char *)jsonctx->backup.value);
1091 }
1092
1093 ly_set_erase(&jsonctx->status, NULL);
1094
1095 free(jsonctx);
1096}