VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/json.cpp@ 108869

Last change on this file since 108869 was 108869, checked in by vboxsync, 5 weeks ago

Runtime/RTJson*: Add support for a subset of the JSON5 specification, bugref:10388

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.8 KB
Line 
1/* $Id: json.cpp 108869 2025-04-07 11:36:49Z vboxsync $ */
2/** @file
3 * IPRT JSON parser API (JSON).
4 */
5
6/*
7 * Copyright (C) 2016-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/json.h>
42#include "internal/iprt.h"
43
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/ctype.h>
47#include <iprt/err.h>
48#include <iprt/mem.h>
49#include <iprt/stream.h>
50#include <iprt/string.h>
51#include <iprt/utf16.h>
52#include <iprt/vfs.h>
53
54#include <stdlib.h> /* strtod() */
55#include <errno.h> /* errno */
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61
62/**
63 * JSON parser position information.
64 */
65typedef struct RTJSONPOS
66{
67 /** Line in the source. */
68 size_t iLine;
69 /** Current start character .*/
70 size_t iChStart;
71 /** Current end character. */
72 size_t iChEnd;
73} RTJSONPOS;
74/** Pointer to a position. */
75typedef RTJSONPOS *PRTJSONPOS;
76
77/**
78 * JSON token class.
79 */
80typedef enum RTJSONTOKENCLASS
81{
82 /** Invalid. */
83 RTJSONTOKENCLASS_INVALID = 0,
84 /** Array begin. */
85 RTJSONTOKENCLASS_BEGIN_ARRAY,
86 /** Object begin. */
87 RTJSONTOKENCLASS_BEGIN_OBJECT,
88 /** Array end. */
89 RTJSONTOKENCLASS_END_ARRAY,
90 /** Object end. */
91 RTJSONTOKENCLASS_END_OBJECT,
92 /** Separator for name/value pairs. */
93 RTJSONTOKENCLASS_NAME_SEPARATOR,
94 /** Value separator. */
95 RTJSONTOKENCLASS_VALUE_SEPARATOR,
96 /** String */
97 RTJSONTOKENCLASS_STRING,
98 /** Integer number. */
99 RTJSONTOKENCLASS_INTEGER,
100 /** Floating point number. */
101 RTJSONTOKENCLASS_NUMBER,
102 /** null keyword. */
103 RTJSONTOKENCLASS_NULL,
104 /** false keyword. */
105 RTJSONTOKENCLASS_FALSE,
106 /** true keyword. */
107 RTJSONTOKENCLASS_TRUE,
108 /** An object key. */
109 RTJSONTOKENCLASS_OBJECT_KEY,
110 /** End of stream */
111 RTJSONTOKENCLASS_EOS,
112 /** 32bit hack. */
113 RTJSONTOKENCLASS_32BIT_HACK = 0x7fffffff
114} RTJSONTOKENCLASS;
115/** Pointer to a token class. */
116typedef RTJSONTOKENCLASS *PRTJSONTOKENCLASS;
117
118/**
119 * JSON token.
120 */
121typedef struct RTJSONTOKEN
122{
123 /** Token class. */
124 RTJSONTOKENCLASS enmClass;
125 /** Token position in the source buffer. */
126 RTJSONPOS Pos;
127 /** Data based on the token class. */
128 union
129 {
130 /** String. */
131 struct
132 {
133 /** Pointer to the start of the string. */
134 char *pszStr;
135 } String;
136 /** Json5 identifier. */
137 struct
138 {
139 /** Pointer to the start of the object key. */
140 char *pszKey;
141 } ObjectKey;
142 /** Number. */
143 struct
144 {
145 int64_t i64Num;
146 } Integer;
147 /** Floating point number. */
148 double rdNum;
149 } Class;
150} RTJSONTOKEN;
151/** Pointer to a JSON token. */
152typedef RTJSONTOKEN *PRTJSONTOKEN;
153/** Pointer to a const script token. */
154typedef const RTJSONTOKEN *PCRTJSONTOKEN;
155
156/**
157 * Tokenizer read input callback.
158 *
159 * @returns IPRT status code.
160 * @param pvUser Opaque user data for the callee.
161 * @param offInput Start offset from the start of the input stream to read from.
162 * @param pvBuf Where to store the read data.
163 * @param cbBuf How much to read.
164 * @param pcbRead Where to store the amount of data read on success.
165 */
166typedef DECLCALLBACKTYPE(int, FNRTJSONTOKENIZERREAD,(void *pvUser, size_t offInput, void *pvBuf, size_t cbBuf,
167 size_t *pcbRead));
168/** Pointer to a tokenizer read buffer callback. */
169typedef FNRTJSONTOKENIZERREAD *PFNRTJSONTOKENIZERREAD;
170
171/**
172 * Tokenizer state.
173 */
174typedef struct RTJSONTOKENIZER
175{
176 /** Read callback. */
177 PFNRTJSONTOKENIZERREAD pfnRead;
178 /** Opaque user data. */
179 void *pvUser;
180 /** Current offset into the input stream. */
181 size_t offInput;
182 /** Number of valid bytes in the input buffer. */
183 size_t cbBuf;
184 /** Current offset into the input buffer. */
185 size_t offBuf;
186 /** Input cache buffer. */
187 char achBuf[512];
188 /** Current position into the input stream. */
189 RTJSONPOS Pos;
190 /** Token 1. */
191 RTJSONTOKEN Token1;
192 /** Pointer to the current active token. */
193 PRTJSONTOKEN pTokenCurr;
194 /** The tokenizer error state. */
195 int rcTok;
196 /** Where to return extended error information.*/
197 PRTERRINFO pErrInfo;
198 /** Flags passed when the tokenizer was created (combination of RTJSON_PARSE_F_XXX). */
199 uint32_t fFlags;
200} RTJSONTOKENIZER;
201/** Pointer to a JSON tokenizer. */
202typedef RTJSONTOKENIZER *PRTJSONTOKENIZER;
203
204/** Pointer to the internal JSON value instance. */
205typedef struct RTJSONVALINT *PRTJSONVALINT;
206
207/**
208 * A JSON value.
209 */
210typedef struct RTJSONVALINT
211{
212 /** Type of the JSON value. */
213 RTJSONVALTYPE enmType;
214 /** Reference count for this JSON value. */
215 volatile uint32_t cRefs;
216 /** Type dependent data. */
217 union
218 {
219 /** String type*/
220 struct
221 {
222 /** Pointer to the string. */
223 char *pszStr;
224 } String;
225 /** Number type. */
226 struct
227 {
228 /** Signed 64-bit integer. */
229 int64_t i64Num;
230 } Integer;
231 /** Floating point number . */
232 double rdNum;
233 /** Array type. */
234 struct
235 {
236 /** Number of elements in the array. */
237 unsigned cItems;
238 /** Pointer to the array of items. */
239 PRTJSONVALINT *papItems;
240 } Array;
241 /** Object type. */
242 struct
243 {
244 /** Number of members. */
245 unsigned cMembers;
246 /** Pointer to the array holding the member names. */
247 char **papszNames;
248 /** Pointer to the array holding the values. */
249 PRTJSONVALINT *papValues;
250 } Object;
251 } Type;
252} RTJSONVALINT;
253
254/**
255 * A JSON iterator.
256 */
257typedef struct RTJSONITINT
258{
259 /** Referenced JSON value. */
260 PRTJSONVALINT pJsonVal;
261 /** Current index. */
262 unsigned idxCur;
263} RTJSONITINT;
264/** Pointer to the internal JSON iterator instance. */
265typedef RTJSONITINT *PRTJSONITINT;
266
267/**
268 * Passing arguments for the read callbacks.
269 */
270typedef struct RTJSONREADERARGS
271{
272 /** Buffer/File size */
273 size_t cbData;
274 /** Data specific for one callback. */
275 union
276 {
277 PRTSTREAM hStream;
278 const uint8_t *pbBuf;
279 RTVFSFILE hVfsFile;
280 } u;
281} RTJSONREADERARGS;
282/** Pointer to a readers argument. */
283typedef RTJSONREADERARGS *PRTJSONREADERARGS;
284
285
286/*********************************************************************************************************************************
287* Internal Functions *
288*********************************************************************************************************************************/
289static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken, PRTJSONVALINT *ppJsonVal);
290
291
292/**
293 * Fill the input buffer from the input stream.
294 *
295 * @returns IPRT status code.
296 * @param pTokenizer The tokenizer state.
297 */
298static int rtJsonTokenizerRead(PRTJSONTOKENIZER pTokenizer)
299{
300 size_t cbRead = 0;
301 int rc = pTokenizer->pfnRead(pTokenizer->pvUser, pTokenizer->offInput, &pTokenizer->achBuf[0],
302 sizeof(pTokenizer->achBuf), &cbRead);
303 if (RT_SUCCESS(rc))
304 {
305 pTokenizer->cbBuf = cbRead;
306 pTokenizer->offInput += cbRead;
307 pTokenizer->offBuf = 0;
308 /* Validate UTF-8 encoding. */
309 rc = RTStrValidateEncodingEx(&pTokenizer->achBuf[0], cbRead, 0 /* fFlags */);
310 /* If we read less than requested we reached the end and fill the remainder with terminators. */
311 if (cbRead < sizeof(pTokenizer->achBuf))
312 memset(&pTokenizer->achBuf[cbRead], 0, sizeof(pTokenizer->achBuf) - cbRead);
313 }
314
315 return rc;
316}
317
318/**
319 * Skips the given amount of characters in the input stream.
320 *
321 * @returns IPRT status code.
322 * @param pTokenizer The tokenizer state.
323 * @param cchSkip The amount of characters to skip.
324 */
325static int rtJsonTokenizerSkip(PRTJSONTOKENIZER pTokenizer, size_t cchSkip)
326{
327 int rc = VINF_SUCCESS;
328
329 /*
330 * In case we reached the end of the stream don't even attempt to read new data.
331 * Safety precaution for possible bugs in the parser causing out of bounds reads
332 */
333 if (pTokenizer->achBuf[pTokenizer->offBuf] == '\0')
334 return rc;
335
336 while ( cchSkip > 0
337 && pTokenizer->offBuf < pTokenizer->cbBuf
338 && RT_SUCCESS(rc))
339 {
340 size_t cchThisSkip = RT_MIN(cchSkip, pTokenizer->cbBuf - pTokenizer->offBuf);
341
342 pTokenizer->offBuf += cchThisSkip;
343 /* Read new data if required and we didn't reach the end yet. */
344 if ( pTokenizer->offBuf == pTokenizer->cbBuf
345 && pTokenizer->cbBuf == sizeof(pTokenizer->achBuf))
346 rc = rtJsonTokenizerRead(pTokenizer);
347
348 cchSkip -= cchThisSkip;
349 }
350
351 return rc;
352}
353
354
355/**
356 * Returns whether the tokenizer reached the end of the stream.
357 *
358 * @returns true if the tokenizer reached the end of stream marker
359 * false otherwise.
360 * @param pTokenizer The tokenizer state.
361 */
362DECLINLINE(bool) rtJsonTokenizerIsEos(PRTJSONTOKENIZER pTokenizer)
363{
364 return pTokenizer->achBuf[pTokenizer->offBuf] == '\0';
365}
366
367/**
368 * Skip one character in the input stream.
369 *
370 * @param pTokenizer The tokenizer state.
371 */
372DECLINLINE(void) rtJsonTokenizerSkipCh(PRTJSONTOKENIZER pTokenizer)
373{
374 rtJsonTokenizerSkip(pTokenizer, 1);
375 pTokenizer->Pos.iChStart++;
376 pTokenizer->Pos.iChEnd++;
377}
378
379/**
380 * Returns the next char in the input buffer without advancing it.
381 *
382 * @returns Next character in the input buffer.
383 * @param pTokenizer The tokenizer state.
384 */
385DECLINLINE(char) rtJsonTokenizerPeekCh(PRTJSONTOKENIZER pTokenizer)
386{
387 return !rtJsonTokenizerIsEos(pTokenizer)
388 ? pTokenizer->achBuf[pTokenizer->offBuf + 1] /** @todo Read out of bounds */
389 : '\0';
390}
391
392/**
393 * Returns the next character in the input buffer advancing the internal
394 * position.
395 *
396 * @returns Next character in the stream.
397 * @param pTokenizer The tokenizer state.
398 */
399DECLINLINE(char) rtJsonTokenizerGetCh(PRTJSONTOKENIZER pTokenizer)
400{
401 char ch;
402
403 if (!rtJsonTokenizerIsEos(pTokenizer))
404 ch = pTokenizer->achBuf[pTokenizer->offBuf];
405 else
406 ch = '\0';
407
408 return ch;
409}
410
411/**
412 * Sets a new line for the tokenizer.
413 *
414 * @param pTokenizer The tokenizer state.
415 * @param cSkip Amount of characters to skip making up the new line.
416 */
417DECLINLINE(void) rtJsonTokenizerNewLine(PRTJSONTOKENIZER pTokenizer, unsigned cSkip)
418{
419 rtJsonTokenizerSkip(pTokenizer, cSkip);
420 pTokenizer->Pos.iLine++;
421 pTokenizer->Pos.iChStart = 1;
422 pTokenizer->Pos.iChEnd = 1;
423}
424
425/**
426 * Checks whether the current position in the input stream is a new line
427 * and skips it.
428 *
429 * @returns Flag whether there was a new line at the current position
430 * in the input buffer.
431 * @param pTokenizer The tokenizer state.
432 */
433DECLINLINE(bool) rtJsonTokenizerIsSkipNewLine(PRTJSONTOKENIZER pTokenizer)
434{
435 bool fNewline = true;
436
437 if ( rtJsonTokenizerGetCh(pTokenizer) == '\r'
438 && rtJsonTokenizerPeekCh(pTokenizer) == '\n')
439 rtJsonTokenizerNewLine(pTokenizer, 2);
440 else if (rtJsonTokenizerGetCh(pTokenizer) == '\n')
441 rtJsonTokenizerNewLine(pTokenizer, 1);
442 else
443 fNewline = false;
444
445 return fNewline;
446}
447
448
449/**
450 * Skips over a multi line comment.
451 *
452 * @param pTokenizer The tokenizer state.
453 */
454DECLINLINE(void) rtJsonTokenizerSkipMultiLineComment(PRTJSONTOKENIZER pTokenizer)
455{
456 while (!( rtJsonTokenizerGetCh(pTokenizer) == '*'
457 && rtJsonTokenizerPeekCh(pTokenizer) == '/'))
458 {
459 if (!rtJsonTokenizerIsSkipNewLine(pTokenizer))
460 rtJsonTokenizerSkip(pTokenizer, 1);
461 }
462
463 rtJsonTokenizerSkip(pTokenizer, 2);
464}
465
466
467/**
468 * Skips over a single line comment.
469 *
470 * @param pTokenizer The tokenizer state.
471 */
472DECLINLINE(void) rtJsonTokenizerSkipSingleLineComment(PRTJSONTOKENIZER pTokenizer)
473{
474 while (!rtJsonTokenizerIsSkipNewLine(pTokenizer))
475 rtJsonTokenizerSkip(pTokenizer, 1);
476}
477
478
479/**
480 * Skips any comments which can occur in JSON5.
481 *
482 * @returns Flag whether a comment was encountered and skipped.
483 * @param pTokenizer The tokenizer state.
484 */
485DECLINLINE(bool) rtJsonTokenizerIsSkipComment(PRTJSONTOKENIZER pTokenizer)
486{
487 bool fComment = true;
488
489 if ( rtJsonTokenizerGetCh(pTokenizer) == '/'
490 && rtJsonTokenizerPeekCh(pTokenizer) == '*')
491 {
492 rtJsonTokenizerSkip(pTokenizer, 2);
493 rtJsonTokenizerSkipMultiLineComment(pTokenizer);
494 }
495 else if ( rtJsonTokenizerGetCh(pTokenizer) == '/'
496 && rtJsonTokenizerPeekCh(pTokenizer) == '/')
497 {
498 rtJsonTokenizerSkip(pTokenizer, 2);
499 rtJsonTokenizerSkipSingleLineComment(pTokenizer);
500 }
501 else
502 fComment = false;
503
504 return fComment;
505}
506
507
508/**
509 * Skip all whitespace starting from the current input buffer position.
510 * Skips all present comments too.
511 *
512 * @param pTokenizer The tokenizer state.
513 */
514DECLINLINE(void) rtJsonTokenizerSkipWhitespace(PRTJSONTOKENIZER pTokenizer)
515{
516 while (!rtJsonTokenizerIsEos(pTokenizer))
517 {
518 while ( rtJsonTokenizerGetCh(pTokenizer) == ' '
519 || rtJsonTokenizerGetCh(pTokenizer) == '\t')
520 rtJsonTokenizerSkipCh(pTokenizer);
521
522 if ( (pTokenizer->fFlags & RTJSON_PARSE_F_JSON5)
523 && rtJsonTokenizerIsSkipComment(pTokenizer))
524 continue;
525
526 if ( !rtJsonTokenizerIsEos(pTokenizer)
527 && !rtJsonTokenizerIsSkipNewLine(pTokenizer))
528 break; /* Skipped everything, next is some real content. */
529 }
530}
531
532
533/**
534 * Get an literal token from the tokenizer.
535 *
536 * @returns IPRT status code.
537 * @param pTokenizer The tokenizer state.
538 * @param pToken The uninitialized token.
539 */
540static int rtJsonTokenizerGetLiteral(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
541{
542 int rc = VINF_SUCCESS;
543 char ch = rtJsonTokenizerGetCh(pTokenizer);
544 size_t cchLiteral = 0;
545 char szLiteral[6]; /* false + 0 terminator as the lingest possible literal. */
546 RT_ZERO(szLiteral);
547
548 pToken->Pos = pTokenizer->Pos;
549
550 Assert(RT_C_IS_ALPHA(ch));
551
552 while ( RT_C_IS_ALPHA(ch)
553 && cchLiteral < RT_ELEMENTS(szLiteral) - 1)
554 {
555 szLiteral[cchLiteral] = ch;
556 cchLiteral++;
557 rtJsonTokenizerSkipCh(pTokenizer);
558 ch = rtJsonTokenizerGetCh(pTokenizer);
559 }
560
561 if (!RTStrNCmp(&szLiteral[0], "false", RT_ELEMENTS(szLiteral)))
562 pToken->enmClass = RTJSONTOKENCLASS_FALSE;
563 else if (!RTStrNCmp(&szLiteral[0], "true", RT_ELEMENTS(szLiteral)))
564 pToken->enmClass = RTJSONTOKENCLASS_TRUE;
565 else if (!RTStrNCmp(&szLiteral[0], "null", RT_ELEMENTS(szLiteral)))
566 pToken->enmClass = RTJSONTOKENCLASS_NULL;
567 else
568 {
569 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
570 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "malformed literal '%.6s' (line %zu col %zu)",
571 &szLiteral[0], pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
572 }
573
574 pToken->Pos.iChEnd += cchLiteral;
575 return rc;
576}
577
578
579/**
580 * Parses a hexdecimal number as allowed by JSON5.
581 *
582 * @returns IPRT status code.
583 * @param pTokenizer The tokenizer state.
584 * @param pToken The uninitialized token.
585 * @param fNegative Flag whether the number is negative.
586 */
587static int rtJsonTokenizer5ParseHex(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken, bool fNegative)
588{
589 int64_t i64 = 0;
590
591 /* Skip the 0x prefix. */
592 rtJsonTokenizerSkip(pTokenizer, 2);
593
594 char ch = rtJsonTokenizerGetCh(pTokenizer);
595 uint8_t cDigits = 0;
596 while ( RT_C_IS_DIGIT(ch)
597 || RT_C_IS_XDIGIT(ch))
598 {
599 uint8_t bHex = RT_C_IS_DIGIT(ch)
600 ? ch - '0'
601 : 0xa + (RT_C_TO_LOWER(ch) - 'a');
602
603 if (cDigits >= 16)
604 return RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "64-bit hexadecimal number is too large (line %zu col %zu)",
605 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
606
607 i64 <<= 4;
608 i64 |= bHex;
609 cDigits++;
610 rtJsonTokenizerSkipCh(pTokenizer);
611 ch = rtJsonTokenizerGetCh(pTokenizer);
612 }
613
614 /** @todo Check how -0xffff'ffff'ffff'ffff should be handled. */
615 if (fNegative)
616 i64 = -i64;
617 pToken->Class.Integer.i64Num = i64;
618 return VINF_SUCCESS;
619}
620
621
622/**
623 * Get a numerical constant from the tokenizer.
624 *
625 * @returns IPRT status code.
626 * @param pTokenizer The tokenizer state.
627 * @param pToken The uninitialized token.
628 */
629static int rtJsonTokenizerGetNumber(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
630{
631 size_t cchNum = 0;
632 char szTmp[128]; /* Everything larger is not possible to display in signed 64bit. */
633
634 pToken->enmClass = RTJSONTOKENCLASS_INTEGER;
635
636 char ch = rtJsonTokenizerGetCh(pTokenizer);
637 if (ch == '-')
638 {
639 szTmp[cchNum++] = '-';
640 rtJsonTokenizerSkipCh(pTokenizer);
641 ch = rtJsonTokenizerGetCh(pTokenizer);
642 }
643 else if ( ch == '+'
644 && (pTokenizer->fFlags & RTJSON_PARSE_F_JSON5))
645 {
646 /* JSON5 allows a positive sign. */
647 rtJsonTokenizerSkipCh(pTokenizer);
648 ch = rtJsonTokenizerGetCh(pTokenizer);
649 }
650
651 if ( ch == '0'
652 && ( rtJsonTokenizerPeekCh(pTokenizer) == 'x'
653 || rtJsonTokenizerPeekCh(pTokenizer) == 'X')
654 && (pTokenizer->fFlags & RTJSON_PARSE_F_JSON5))
655 /* If cchNum is == 1, we must've stored a negative sign. */
656 return rtJsonTokenizer5ParseHex(pTokenizer, pToken, cchNum == 1);
657
658 while ( RT_C_IS_DIGIT(ch)
659 && cchNum < sizeof(szTmp) - 1)
660 {
661 szTmp[cchNum] = ch;
662 cchNum++;
663 rtJsonTokenizerSkipCh(pTokenizer);
664 ch = rtJsonTokenizerGetCh(pTokenizer);
665 }
666
667 int rc = VINF_SUCCESS;
668 if (RT_C_IS_DIGIT(ch) && cchNum >= sizeof(szTmp) - 1)
669 rc = VERR_NUMBER_TOO_BIG;
670 else if (ch != '.')
671 {
672 szTmp[cchNum] = '\0';
673 rc = RTStrToInt64Ex(&szTmp[0], NULL, 10, &pToken->Class.Integer.i64Num);
674 Assert(RT_SUCCESS(rc) || rc == VWRN_NUMBER_TOO_BIG);
675 if (rc == VWRN_NUMBER_TOO_BIG)
676 rc = VERR_NUMBER_TOO_BIG;
677 }
678 else
679 {
680 /*
681 * A floating point value.
682 */
683 pToken->enmClass = RTJSONTOKENCLASS_NUMBER;
684 rtJsonTokenizerSkipCh(pTokenizer);
685 szTmp[cchNum++] = '.';
686
687 ch = rtJsonTokenizerGetCh(pTokenizer);
688 while ( RT_C_IS_DIGIT(ch)
689 && cchNum < sizeof(szTmp) - 1)
690 {
691 szTmp[cchNum++] = ch;
692 rtJsonTokenizerSkipCh(pTokenizer);
693 ch = rtJsonTokenizerGetCh(pTokenizer);
694 }
695 if ( (ch == 'e' || ch == 'E')
696 && cchNum < sizeof(szTmp) - 2)
697 {
698 szTmp[cchNum++] = 'e';
699 rtJsonTokenizerSkipCh(pTokenizer);
700 ch = rtJsonTokenizerGetCh(pTokenizer);
701 if (ch == '+' || ch == '-')
702 {
703 szTmp[cchNum++] = ch;
704 rtJsonTokenizerSkipCh(pTokenizer);
705 ch = rtJsonTokenizerGetCh(pTokenizer);
706 }
707 while ( RT_C_IS_DIGIT(ch)
708 && cchNum < sizeof(szTmp) - 1)
709 {
710 szTmp[cchNum++] = ch;
711 rtJsonTokenizerSkipCh(pTokenizer);
712 ch = rtJsonTokenizerGetCh(pTokenizer);
713 }
714 }
715 if (cchNum < sizeof(szTmp) - 1)
716 {
717 szTmp[cchNum] = '\0';
718
719 /** @todo Not sure if strtod does the 100% right thing here... */
720 errno = 0;
721 char *pszNext = NULL;
722 pToken->Class.rdNum = strtod(szTmp, &pszNext);
723 if (errno == 0)
724 {
725 rc = VINF_SUCCESS;
726 Assert(!pszNext || *pszNext == '\0');
727 }
728 else
729 rc = RTErrConvertFromErrno(errno);
730 }
731 }
732
733 return rc;
734}
735
736/**
737 * Parses a string constant.
738 *
739 * @returns IPRT status code.
740 * @param pTokenizer The tokenizer state.
741 * @param pToken The uninitialized token.
742 */
743static int rtJsonTokenizerGetString(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
744{
745 size_t cchStrMax = 64;
746 char *pszDecoded = (char *)RTStrAlloc(cchStrMax);
747 AssertReturn(pszDecoded, VERR_NO_STR_MEMORY);
748
749 char const chEnd = rtJsonTokenizerGetCh(pTokenizer);
750 Assert( chEnd == '\"'
751 || ( chEnd == '\''
752 && (pTokenizer->fFlags & RTJSON_PARSE_F_JSON5)));
753 rtJsonTokenizerSkipCh(pTokenizer); /* Skip delimiter */
754
755 pToken->enmClass = RTJSONTOKENCLASS_STRING;
756 pToken->Pos = pTokenizer->Pos;
757
758 size_t cchStr = 0;
759 char ch = rtJsonTokenizerGetCh(pTokenizer);
760 while ( ch != chEnd
761 && ch != '\0')
762 {
763 if (ch != '\\')
764 {
765 pszDecoded[cchStr++] = ch;
766 rtJsonTokenizerSkipCh(pTokenizer);
767 }
768 else
769 {
770 /* Escape sequence, check the next character */
771 rtJsonTokenizerSkipCh(pTokenizer);
772 char chNext = rtJsonTokenizerGetCh(pTokenizer);
773 switch (chNext)
774 {
775 case '\"':
776 pszDecoded[cchStr++] = '\"';
777 rtJsonTokenizerSkipCh(pTokenizer);
778 break;
779 case '\\':
780 pszDecoded[cchStr++] = '\\';
781 rtJsonTokenizerSkipCh(pTokenizer);
782 break;
783 case '/':
784 pszDecoded[cchStr++] = '/';
785 rtJsonTokenizerSkipCh(pTokenizer);
786 break;
787 case 'b':
788 pszDecoded[cchStr++] = '\b';
789 rtJsonTokenizerSkipCh(pTokenizer);
790 break;
791 case 'n':
792 pszDecoded[cchStr++] = '\n';
793 rtJsonTokenizerSkipCh(pTokenizer);
794 break;
795 case 'f':
796 pszDecoded[cchStr++] = '\f';
797 rtJsonTokenizerSkipCh(pTokenizer);
798 break;
799 case 'r':
800 pszDecoded[cchStr++] = '\r';
801 rtJsonTokenizerSkipCh(pTokenizer);
802 break;
803 case 't':
804 pszDecoded[cchStr++] = '\t';
805 rtJsonTokenizerSkipCh(pTokenizer);
806 break;
807 case 'u':
808 {
809 /* \uXXXX */
810 int rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
811 rtJsonTokenizerSkipCh(pTokenizer);
812 char chX1 = rtJsonTokenizerGetCh(pTokenizer);
813 if (RT_C_IS_XDIGIT(chX1))
814 {
815 rtJsonTokenizerSkipCh(pTokenizer);
816 char chX2 = rtJsonTokenizerGetCh(pTokenizer);
817 if (RT_C_IS_XDIGIT(chX2))
818 {
819 rtJsonTokenizerSkipCh(pTokenizer);
820 char chX3 = rtJsonTokenizerGetCh(pTokenizer);
821 if (RT_C_IS_XDIGIT(chX3))
822 {
823 rtJsonTokenizerSkipCh(pTokenizer);
824 char chX4 = rtJsonTokenizerGetCh(pTokenizer);
825 if (RT_C_IS_XDIGIT(chX4))
826 {
827 rtJsonTokenizerSkipCh(pTokenizer);
828
829 RTUNICP uc = ((RTUTF16)(chX1 <= '9' ? chX1 - '0' : (chX1 & 7) + 9) << 12)
830 | ((RTUTF16)(chX2 <= '9' ? chX2 - '0' : (chX2 & 7) + 9) << 8)
831 | ((RTUTF16)(chX3 <= '9' ? chX3 - '0' : (chX3 & 7) + 9) << 4)
832 | ((RTUTF16)(chX4 <= '9' ? chX4 - '0' : (chX4 & 7) + 9));
833 if ( !RTUtf16IsHighSurrogate((RTUTF16)uc)
834 && !RTUtf16IsLowSurrogate((RTUTF16)uc))
835 rc = VINF_SUCCESS;
836 else if (RTUtf16IsHighSurrogate((RTUTF16)uc))
837 {
838 /* The must be a low surrogate pair following the high one: */
839 rc = VINF_SUCCESS;
840 ch = rtJsonTokenizerGetCh(pTokenizer);
841 if (ch == '\\')
842 rtJsonTokenizerSkipCh(pTokenizer);
843 else
844 rc = VERR_JSON_MISSING_SURROGATE_PAIR;
845 ch = rtJsonTokenizerGetCh(pTokenizer);
846 if (ch == 'u')
847 rtJsonTokenizerSkipCh(pTokenizer);
848 else
849 rc = VERR_JSON_MISSING_SURROGATE_PAIR;
850 chX1 = rtJsonTokenizerGetCh(pTokenizer);
851 if (RT_C_IS_XDIGIT(chX1))
852 rtJsonTokenizerSkipCh(pTokenizer);
853 else if (RT_SUCCESS_NP(rc))
854 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
855 chX2 = rtJsonTokenizerGetCh(pTokenizer);
856 if (RT_C_IS_XDIGIT(chX2))
857 rtJsonTokenizerSkipCh(pTokenizer);
858 else if (RT_SUCCESS_NP(rc))
859 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
860 chX3 = rtJsonTokenizerGetCh(pTokenizer);
861 if (RT_C_IS_XDIGIT(chX3))
862 rtJsonTokenizerSkipCh(pTokenizer);
863 else if (RT_SUCCESS_NP(rc))
864 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
865 chX4 = rtJsonTokenizerGetCh(pTokenizer);
866 if (RT_C_IS_XDIGIT(chX4))
867 rtJsonTokenizerSkipCh(pTokenizer);
868 else if (RT_SUCCESS_NP(rc))
869 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
870 if (RT_SUCCESS(rc))
871 {
872 RTUTF16 wc2 = ((RTUTF16)(chX1 <= '9' ? chX1 - '0' : (chX1 & 7) + 9) << 12)
873 | ((RTUTF16)(chX2 <= '9' ? chX2 - '0' : (chX2 & 7) + 9) << 8)
874 | ((RTUTF16)(chX3 <= '9' ? chX3 - '0' : (chX3 & 7) + 9) << 4)
875 | ((RTUTF16)(chX4 <= '9' ? chX4 - '0' : (chX4 & 7) + 9));
876 if (RTUtf16IsLowSurrogate(wc2))
877 uc = 0x10000 + (((uc & 0x3ff) << 10) | (wc2 & 0x3ff));
878 else
879 rc = VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE;
880 }
881 }
882 else
883 rc = VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE;
884 if (RT_SUCCESS(rc))
885 {
886 if ( uc != 0
887 && uc != 0xfffe
888 && uc != 0xffff)
889 {
890 Assert(cchStr + RTStrCpSize(uc) < cchStrMax);
891 char *pszNext = RTStrPutCp(&pszDecoded[cchStr], uc);
892 Assert((size_t)(pszNext - &pszDecoded[cchStr]) == RTStrCpSize(uc));
893 cchStr += pszNext - &pszDecoded[cchStr];
894 break;
895 }
896 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_INVALID_CODEPOINT,
897 "Invalid \\u code point: %#x (line %zu col %zu)",
898 uc, pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
899 }
900 }
901 }
902 }
903 }
904 RTStrFree(pszDecoded);
905 if (rc == VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE)
906 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Invalid \\u escape sequence (line %zu col %zu)",
907 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
908 else if (rc == VERR_JSON_MISSING_SURROGATE_PAIR)
909 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Missing UTF-16 surrogate pair (line %zu col %zu)",
910 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
911 else if (rc == VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE)
912 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Invalid UTF-16 surrogate pair (line %zu col %zu)",
913 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
914 return rc;
915 }
916
917 default:
918 RTStrFree(pszDecoded);
919 return RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "bad escape sequence (line %zu col %zu)",
920 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
921 }
922 }
923
924
925 if (cchStr < cchStrMax - 4)
926 { /* likely */ }
927 else
928 {
929 /* Increase string space. */
930 size_t cchStrMaxNew = cchStrMax < _4K ? cchStrMax * 2 : cchStrMax + _4K;
931 int rc = RTStrRealloc(&pszDecoded, cchStrMaxNew);
932 if (RT_SUCCESS(rc))
933 cchStrMax = cchStrMaxNew;
934 else
935 {
936 RTStrFree(pszDecoded);
937 return rc;
938 }
939 }
940 ch = rtJsonTokenizerGetCh(pTokenizer);
941 }
942
943 if (ch == chEnd)
944 rtJsonTokenizerSkipCh(pTokenizer); /* Skip closing character */
945
946 Assert(cchStr < cchStrMax);
947 pszDecoded[cchStr] = '\0';
948 if (cchStrMax - cchStr >= cchStrMax / 2)
949 RTStrRealloc(&pszDecoded, cchStr + 1);
950 pToken->Class.String.pszStr = pszDecoded;
951
952 pToken->Pos.iChEnd = pTokenizer->Pos.iChEnd;
953 return VINF_SUCCESS;
954}
955
956
957/**
958 * Parses a JSON5 object key.
959 *
960 * @returns IPRT status code.
961 * @param pTokenizer The tokenizer state.
962 * @param pToken The uninitialized token.
963 */
964static int rtJsonTokenizerGetJson5ObjectKey(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
965{
966 size_t cchStrMax = 64;
967 char *pszDecoded = (char *)RTStrAlloc(cchStrMax);
968 AssertReturn(pszDecoded, VERR_NO_STR_MEMORY);
969
970 pToken->enmClass = RTJSONTOKENCLASS_OBJECT_KEY;
971 pToken->Pos = pTokenizer->Pos;
972
973 size_t cchStr = 0;
974 char ch = rtJsonTokenizerGetCh(pTokenizer);
975 while ( RT_C_IS_ALNUM(ch)
976 || ch == '\\'
977 || ch == '_'
978 || ch == '$')
979 {
980 if (ch != '\\')
981 {
982 pszDecoded[cchStr++] = ch;
983 rtJsonTokenizerSkipCh(pTokenizer);
984 }
985 else
986 {
987 /* Escape sequence, check the next character */
988 rtJsonTokenizerSkipCh(pTokenizer);
989 char chNext = rtJsonTokenizerGetCh(pTokenizer);
990 switch (chNext)
991 {
992 case 'u':
993 {
994 /* \uXXXX */
995 int rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
996 rtJsonTokenizerSkipCh(pTokenizer);
997 char chX1 = rtJsonTokenizerGetCh(pTokenizer);
998 if (RT_C_IS_XDIGIT(chX1))
999 {
1000 rtJsonTokenizerSkipCh(pTokenizer);
1001 char chX2 = rtJsonTokenizerGetCh(pTokenizer);
1002 if (RT_C_IS_XDIGIT(chX2))
1003 {
1004 rtJsonTokenizerSkipCh(pTokenizer);
1005 char chX3 = rtJsonTokenizerGetCh(pTokenizer);
1006 if (RT_C_IS_XDIGIT(chX3))
1007 {
1008 rtJsonTokenizerSkipCh(pTokenizer);
1009 char chX4 = rtJsonTokenizerGetCh(pTokenizer);
1010 if (RT_C_IS_XDIGIT(chX4))
1011 {
1012 rtJsonTokenizerSkipCh(pTokenizer);
1013
1014 RTUNICP uc = ((RTUTF16)(chX1 <= '9' ? chX1 - '0' : (chX1 & 7) + 9) << 12)
1015 | ((RTUTF16)(chX2 <= '9' ? chX2 - '0' : (chX2 & 7) + 9) << 8)
1016 | ((RTUTF16)(chX3 <= '9' ? chX3 - '0' : (chX3 & 7) + 9) << 4)
1017 | ((RTUTF16)(chX4 <= '9' ? chX4 - '0' : (chX4 & 7) + 9));
1018 if ( !RTUtf16IsHighSurrogate((RTUTF16)uc)
1019 && !RTUtf16IsLowSurrogate((RTUTF16)uc))
1020 rc = VINF_SUCCESS;
1021 else if (RTUtf16IsHighSurrogate((RTUTF16)uc))
1022 {
1023 /* The must be a low surrogate pair following the high one: */
1024 rc = VINF_SUCCESS;
1025 ch = rtJsonTokenizerGetCh(pTokenizer);
1026 if (ch == '\\')
1027 rtJsonTokenizerSkipCh(pTokenizer);
1028 else
1029 rc = VERR_JSON_MISSING_SURROGATE_PAIR;
1030 ch = rtJsonTokenizerGetCh(pTokenizer);
1031 if (ch == 'u')
1032 rtJsonTokenizerSkipCh(pTokenizer);
1033 else
1034 rc = VERR_JSON_MISSING_SURROGATE_PAIR;
1035 chX1 = rtJsonTokenizerGetCh(pTokenizer);
1036 if (RT_C_IS_XDIGIT(chX1))
1037 rtJsonTokenizerSkipCh(pTokenizer);
1038 else if (RT_SUCCESS_NP(rc))
1039 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
1040 chX2 = rtJsonTokenizerGetCh(pTokenizer);
1041 if (RT_C_IS_XDIGIT(chX2))
1042 rtJsonTokenizerSkipCh(pTokenizer);
1043 else if (RT_SUCCESS_NP(rc))
1044 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
1045 chX3 = rtJsonTokenizerGetCh(pTokenizer);
1046 if (RT_C_IS_XDIGIT(chX3))
1047 rtJsonTokenizerSkipCh(pTokenizer);
1048 else if (RT_SUCCESS_NP(rc))
1049 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
1050 chX4 = rtJsonTokenizerGetCh(pTokenizer);
1051 if (RT_C_IS_XDIGIT(chX4))
1052 rtJsonTokenizerSkipCh(pTokenizer);
1053 else if (RT_SUCCESS_NP(rc))
1054 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
1055 if (RT_SUCCESS(rc))
1056 {
1057 RTUTF16 wc2 = ((RTUTF16)(chX1 <= '9' ? chX1 - '0' : (chX1 & 7) + 9) << 12)
1058 | ((RTUTF16)(chX2 <= '9' ? chX2 - '0' : (chX2 & 7) + 9) << 8)
1059 | ((RTUTF16)(chX3 <= '9' ? chX3 - '0' : (chX3 & 7) + 9) << 4)
1060 | ((RTUTF16)(chX4 <= '9' ? chX4 - '0' : (chX4 & 7) + 9));
1061 if (RTUtf16IsLowSurrogate(wc2))
1062 uc = 0x10000 + (((uc & 0x3ff) << 10) | (wc2 & 0x3ff));
1063 else
1064 rc = VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE;
1065 }
1066 }
1067 else
1068 rc = VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE;
1069 if (RT_SUCCESS(rc))
1070 {
1071 if ( uc != 0
1072 && uc != 0xfffe
1073 && uc != 0xffff)
1074 {
1075 Assert(cchStr + RTStrCpSize(uc) < cchStrMax);
1076 char *pszNext = RTStrPutCp(&pszDecoded[cchStr], uc);
1077 Assert((size_t)(pszNext - &pszDecoded[cchStr]) == RTStrCpSize(uc));
1078 cchStr += pszNext - &pszDecoded[cchStr];
1079 break;
1080 }
1081 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_INVALID_CODEPOINT,
1082 "Invalid \\u code point: %#x (line %zu col %zu)",
1083 uc, pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1084 }
1085 }
1086 }
1087 }
1088 }
1089 RTStrFree(pszDecoded);
1090 if (rc == VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE)
1091 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Invalid \\u escape sequence (line %zu col %zu)",
1092 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1093 else if (rc == VERR_JSON_MISSING_SURROGATE_PAIR)
1094 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Missing UTF-16 surrogate pair (line %zu col %zu)",
1095 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1096 else if (rc == VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE)
1097 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Invalid UTF-16 surrogate pair (line %zu col %zu)",
1098 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1099 return rc;
1100 }
1101
1102 default:
1103 RTStrFree(pszDecoded);
1104 return RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "bad escape sequence (line %zu col %zu)",
1105 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1106 }
1107 }
1108
1109
1110 if (cchStr < cchStrMax - 4)
1111 { /* likely */ }
1112 else
1113 {
1114 /* Increase string space. */
1115 size_t cchStrMaxNew = cchStrMax < _4K ? cchStrMax * 2 : cchStrMax + _4K;
1116 int rc = RTStrRealloc(&pszDecoded, cchStrMaxNew);
1117 if (RT_SUCCESS(rc))
1118 cchStrMax = cchStrMaxNew;
1119 else
1120 {
1121 RTStrFree(pszDecoded);
1122 return rc;
1123 }
1124 }
1125 ch = rtJsonTokenizerGetCh(pTokenizer);
1126 }
1127
1128 Assert(cchStr < cchStrMax);
1129 pszDecoded[cchStr] = '\0';
1130 if (cchStrMax - cchStr >= cchStrMax / 2)
1131 RTStrRealloc(&pszDecoded, cchStr + 1);
1132 pToken->Class.ObjectKey.pszKey = pszDecoded;
1133
1134 pToken->Pos.iChEnd = pTokenizer->Pos.iChEnd;
1135 return VINF_SUCCESS;
1136}
1137
1138
1139/**
1140 * Get the end of stream token.
1141 *
1142 * @returns IPRT status code.
1143 * @param pTokenizer The tokenizer state.
1144 * @param pToken The uninitialized token.
1145 */
1146static int rtJsonTokenizerGetEos(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
1147{
1148 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\0');
1149
1150 pToken->enmClass = RTJSONTOKENCLASS_EOS;
1151 pToken->Pos = pTokenizer->Pos;
1152 return VINF_SUCCESS;
1153}
1154
1155
1156/**
1157 * Reads an object key token from the tokenizer stream.
1158 *
1159 * @returns IPRT status code.
1160 * @param pTokenizer The tokenizer to read from.
1161 * @param pToken Uninitialized token to fill the token data into.
1162 */
1163static int rtJsonTokenizerGetObjectKey(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
1164{
1165 int rc;
1166 char ch = rtJsonTokenizerGetCh(pTokenizer);
1167 if (ch == '\"')
1168 {
1169 rc = rtJsonTokenizerGetString(pTokenizer, pToken);
1170 if (RT_SUCCESS(rc))
1171 {
1172 pToken->enmClass = RTJSONTOKENCLASS_OBJECT_KEY;
1173 pToken->Class.ObjectKey.pszKey = pToken->Class.String.pszStr;
1174 }
1175 }
1176 else if ( pTokenizer->fFlags & RTJSON_PARSE_F_JSON5
1177 && ( ch == '$'
1178 || ch == '_'
1179 || RT_C_IS_ALNUM(ch)))
1180 rc = rtJsonTokenizerGetJson5ObjectKey(pTokenizer, pToken);
1181 else if (ch == '}')
1182 {
1183 /* We might encounter an end of object after a trailing ,. */
1184 pToken->enmClass = RTJSONTOKENCLASS_END_OBJECT;
1185 rtJsonTokenizerSkipCh(pTokenizer);
1186 rc = VINF_SUCCESS;
1187 }
1188 else
1189 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "bad object key (line %zu col %zu)",
1190 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1191
1192 if (RT_FAILURE(rc))
1193 pTokenizer->rcTok = rc;
1194
1195 return rc;
1196}
1197
1198
1199/**
1200 * Read the next token from the tokenizer stream.
1201 *
1202 * @returns IPRT status code.
1203 * @param pTokenizer The tokenizer to read from.
1204 * @param pToken Uninitialized token to fill the token data into.
1205 * @param fObjectKey Flag whether an object key is read.
1206 */
1207static int rtJsonTokenizerReadNextToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken, bool fObjectKey)
1208{
1209 int rc = VINF_SUCCESS;
1210
1211 /* Skip all eventually existing whitespace and newlines first. */
1212 rtJsonTokenizerSkipWhitespace(pTokenizer);
1213
1214 if (fObjectKey)
1215 return rtJsonTokenizerGetObjectKey(pTokenizer, pToken);
1216
1217 char ch = rtJsonTokenizerGetCh(pTokenizer);
1218 if (RT_C_IS_ALPHA(ch))
1219 rc = rtJsonTokenizerGetLiteral(pTokenizer, pToken);
1220 else if (RT_C_IS_DIGIT(ch) || ch == '-')
1221 rc = rtJsonTokenizerGetNumber(pTokenizer, pToken);
1222 else if ( ch == '\"'
1223 || ( ch == '\''
1224 && (pTokenizer->fFlags & RTJSON_PARSE_F_JSON5)))
1225 rc = rtJsonTokenizerGetString(pTokenizer, pToken);
1226 else if (ch == '\0')
1227 rc = rtJsonTokenizerGetEos(pTokenizer, pToken);
1228 else if (ch == '{')
1229 {
1230 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_OBJECT;
1231 rtJsonTokenizerSkipCh(pTokenizer);
1232 }
1233 else if (ch == '}')
1234 {
1235 pToken->enmClass = RTJSONTOKENCLASS_END_OBJECT;
1236 rtJsonTokenizerSkipCh(pTokenizer);
1237 }
1238 else if (ch == '[')
1239 {
1240 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_ARRAY;
1241 rtJsonTokenizerSkipCh(pTokenizer);
1242 }
1243 else if (ch == ']')
1244 {
1245 pToken->enmClass = RTJSONTOKENCLASS_END_ARRAY;
1246 rtJsonTokenizerSkipCh(pTokenizer);
1247 }
1248 else if (ch == ':')
1249 {
1250 pToken->enmClass = RTJSONTOKENCLASS_NAME_SEPARATOR;
1251 rtJsonTokenizerSkipCh(pTokenizer);
1252 }
1253 else if (ch == ',')
1254 {
1255 pToken->enmClass = RTJSONTOKENCLASS_VALUE_SEPARATOR;
1256 rtJsonTokenizerSkipCh(pTokenizer);
1257 }
1258 else
1259 {
1260 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
1261 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "bad token '%c' (line %zu col %zu)",
1262 ch, pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1263 }
1264
1265 if (RT_FAILURE(rc))
1266 pTokenizer->rcTok = rc;
1267
1268 return rc;
1269}
1270
1271/**
1272 * Create a new tokenizer.
1273 *
1274 * @returns IPRT status code.
1275 * @param pTokenizer The tokenizer state to initialize.
1276 * @param fFlags Combination of RTJSON_PARSE_F_XXX.
1277 * @param pfnRead Read callback for the input stream.
1278 * @param pvUser Opaque user data to pass to the callback.
1279 * @param pErrInfo Where to return extended error info.
1280 */
1281static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, uint32_t fFlags, PFNRTJSONTOKENIZERREAD pfnRead, void *pvUser,
1282 PRTERRINFO pErrInfo)
1283{
1284 pTokenizer->pfnRead = pfnRead;
1285 pTokenizer->pvUser = pvUser;
1286 pTokenizer->offInput = 0;
1287 pTokenizer->cbBuf = 0;
1288 pTokenizer->offBuf = 0;
1289 pTokenizer->Pos.iLine = 1;
1290 pTokenizer->Pos.iChStart = 1;
1291 pTokenizer->Pos.iChEnd = 1;
1292 pTokenizer->pTokenCurr = &pTokenizer->Token1;
1293 pTokenizer->rcTok = VINF_SUCCESS;
1294 pTokenizer->pErrInfo = pErrInfo;
1295 pTokenizer->fFlags = fFlags;
1296
1297 RT_ZERO(pTokenizer->achBuf);
1298
1299 /* Fill the input buffer. */
1300 int rc = rtJsonTokenizerRead(pTokenizer);
1301
1302 /* Fill the tokenizer with two first tokens. */
1303 if (RT_SUCCESS(rc))
1304 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr, false /* fObjectKey*/);
1305
1306 return rc;
1307}
1308
1309/**
1310 * Cleans up any resources still in control of the given token.
1311 *
1312 * @param pToken The toke nto clean up.
1313 */
1314static void rtJsonTokenizerTokenCleanup(PRTJSONTOKEN pToken)
1315{
1316 if ( pToken->enmClass == RTJSONTOKENCLASS_STRING
1317 && pToken->Class.String.pszStr)
1318 RTStrFree(pToken->Class.String.pszStr);
1319}
1320
1321/**
1322 * Destroys a given tokenizer state.
1323 *
1324 * @param pTokenizer The tokenizer to destroy.
1325 */
1326static void rtJsonTokenizerDestroy(PRTJSONTOKENIZER pTokenizer)
1327{
1328 if (pTokenizer->pTokenCurr)
1329 rtJsonTokenizerTokenCleanup(pTokenizer->pTokenCurr);
1330}
1331
1332/**
1333 * Get the current token in the input stream.
1334 *
1335 * @returns Pointer to the next token in the stream.
1336 * @param pTokenizer The tokenizer state.
1337 * @param fObjectKey Flag whether an object is read.
1338 * @param ppToken Where to store the pointer to the current token on success.
1339 */
1340DECLINLINE(int) rtJsonTokenizerGetToken(PRTJSONTOKENIZER pTokenizer, bool fObjectKey, PRTJSONTOKEN *ppToken)
1341{
1342 if (!pTokenizer->pTokenCurr)
1343 {
1344 rtJsonTokenizerReadNextToken(pTokenizer, &pTokenizer->Token1, fObjectKey);
1345 pTokenizer->pTokenCurr = &pTokenizer->Token1;
1346 }
1347
1348 if (RT_SUCCESS(pTokenizer->rcTok))
1349 {
1350 Assert(pTokenizer->pTokenCurr);
1351 *ppToken = pTokenizer->pTokenCurr;
1352 return VINF_SUCCESS;
1353 }
1354
1355 return pTokenizer->rcTok;
1356}
1357
1358/**
1359 * Consume the current token.
1360 *
1361 * @param pTokenizer The tokenizer state.
1362 */
1363static void rtJsonTokenizerConsume(PRTJSONTOKENIZER pTokenizer)
1364{
1365 pTokenizer->pTokenCurr = NULL;
1366}
1367
1368/**
1369 * Consumes the current token if it matches the given class returning an indicator.
1370 *
1371 * @returns true if the class matched and the token was consumed.
1372 * @retval false otherwise.
1373 * @param pTokenizer The tokenizer state.
1374 * @param enmClass The token class to match against.
1375 *
1376 * @note This will not work with object keys.
1377 */
1378static bool rtJsonTokenizerConsumeIfMatched(PRTJSONTOKENIZER pTokenizer, RTJSONTOKENCLASS enmClass)
1379{
1380 PRTJSONTOKEN pToken = NULL;
1381 int rc = rtJsonTokenizerGetToken(pTokenizer, false /*fObjectKey*/, &pToken);
1382 if (RT_SUCCESS(rc))
1383 {
1384 if (pToken->enmClass == enmClass)
1385 {
1386 rtJsonTokenizerConsume(pTokenizer);
1387 return true;
1388 }
1389 }
1390
1391 return false;
1392}
1393
1394/**
1395 * Destroys a given JSON value releasing the reference to all child values.
1396 *
1397 * @param pThis The JSON value to destroy.
1398 */
1399static void rtJsonValDestroy(PRTJSONVALINT pThis)
1400{
1401 switch (pThis->enmType)
1402 {
1403 case RTJSONVALTYPE_OBJECT:
1404 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
1405 {
1406 RTStrFree(pThis->Type.Object.papszNames[i]);
1407 RTJsonValueRelease(pThis->Type.Object.papValues[i]);
1408 }
1409 RTMemFree(pThis->Type.Object.papszNames);
1410 RTMemFree(pThis->Type.Object.papValues);
1411 break;
1412 case RTJSONVALTYPE_ARRAY:
1413 for (unsigned i = 0; i < pThis->Type.Array.cItems; i++)
1414 RTJsonValueRelease(pThis->Type.Array.papItems[i]);
1415 RTMemFree(pThis->Type.Array.papItems);
1416 break;
1417 case RTJSONVALTYPE_STRING:
1418 RTStrFree(pThis->Type.String.pszStr);
1419 break;
1420 case RTJSONVALTYPE_INTEGER:
1421 case RTJSONVALTYPE_NUMBER:
1422 case RTJSONVALTYPE_NULL:
1423 case RTJSONVALTYPE_TRUE:
1424 case RTJSONVALTYPE_FALSE:
1425 /* nothing to do. */
1426 break;
1427 default:
1428 AssertMsgFailed(("Invalid JSON value type: %u\n", pThis->enmType));
1429 }
1430 RTMemFree(pThis);
1431}
1432
1433/**
1434 * Creates a new JSON value with the given type.
1435 *
1436 * @returns Pointer to JSON value on success, NULL if out of memory.
1437 * @param enmType The JSON value type.
1438 */
1439static PRTJSONVALINT rtJsonValueCreate(RTJSONVALTYPE enmType)
1440{
1441 PRTJSONVALINT pThis = (PRTJSONVALINT)RTMemAllocZ(sizeof(RTJSONVALINT));
1442 if (RT_LIKELY(pThis))
1443 {
1444 pThis->enmType = enmType;
1445 pThis->cRefs = 1;
1446 }
1447
1448 return pThis;
1449}
1450
1451/**
1452 * Parses an JSON array.
1453 *
1454 * @returns IPRT status code.
1455 * @param pTokenizer The tokenizer to use.
1456 * @param pJsonVal The JSON array value to fill in.
1457 */
1458static int rtJsonParseArray(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal)
1459{
1460 int rc = VINF_SUCCESS;
1461 PRTJSONTOKEN pToken = NULL;
1462 uint32_t cItems = 0;
1463 uint32_t cItemsMax = 0;
1464 PRTJSONVALINT *papItems = NULL;
1465
1466 rc = rtJsonTokenizerGetToken(pTokenizer, false /*fObjectKey*/, &pToken);
1467 while ( RT_SUCCESS(rc)
1468 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY
1469 && pToken->enmClass != RTJSONTOKENCLASS_EOS)
1470 {
1471 PRTJSONVALINT pVal = NULL;
1472 rc = rtJsonParseValue(pTokenizer, pToken, &pVal);
1473 if (RT_SUCCESS(rc))
1474 {
1475 if (cItems == cItemsMax)
1476 {
1477 cItemsMax += 10;
1478 PRTJSONVALINT *papItemsNew = (PRTJSONVALINT *)RTMemRealloc(papItems, cItemsMax * sizeof(PRTJSONVALINT));
1479 if (RT_UNLIKELY(!papItemsNew))
1480 {
1481 rc = VERR_NO_MEMORY;
1482 break;
1483 }
1484 papItems = papItemsNew;
1485 }
1486
1487 Assert(cItems < cItemsMax);
1488 papItems[cItems] = pVal;
1489 cItems++;
1490 }
1491
1492 /* Skip value separator and continue with next token. */
1493 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
1494 rc = rtJsonTokenizerGetToken(pTokenizer, false /*fObjectKey*/, &pToken);
1495
1496 if ( RT_SUCCESS(rc)
1497 && !fSkippedSep
1498 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY)
1499 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of array (#1) (line %zu col %zu)",
1500 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1501 }
1502
1503 if (RT_SUCCESS(rc))
1504 {
1505 if (pToken->enmClass == RTJSONTOKENCLASS_END_ARRAY)
1506 {
1507 rtJsonTokenizerConsume(pTokenizer);
1508 pJsonVal->Type.Array.cItems = cItems;
1509 pJsonVal->Type.Array.papItems = papItems;
1510 }
1511 else
1512 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of array (#2) (line %zu col %zu)",
1513 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1514 }
1515
1516 if (RT_FAILURE(rc))
1517 {
1518 for (uint32_t i = 0; i < cItems; i++)
1519 RTJsonValueRelease(papItems[i]);
1520 RTMemFree(papItems);
1521 }
1522
1523 return rc;
1524}
1525
1526/**
1527 * Parses an JSON object.
1528 *
1529 * @returns IPRT status code.
1530 * @param pTokenizer The tokenizer to use.
1531 * @param pJsonVal The JSON object value to fill in.
1532 */
1533static int rtJsonParseObject(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal)
1534{
1535 int rc = VINF_SUCCESS;
1536 PRTJSONTOKEN pToken = NULL;
1537 uint32_t cMembers = 0;
1538 uint32_t cMembersMax = 0;
1539 PRTJSONVALINT *papValues = NULL;
1540 char **papszNames = NULL;
1541
1542 rc = rtJsonTokenizerGetToken(pTokenizer, true /*fObjectKey*/, &pToken);
1543 while ( RT_SUCCESS(rc)
1544 && pToken->enmClass == RTJSONTOKENCLASS_OBJECT_KEY)
1545 {
1546 char *pszName = pToken->Class.ObjectKey.pszKey; /* We can consume this string as it was allocated. */
1547 pToken->Class.ObjectKey.pszKey = NULL;
1548
1549 rtJsonTokenizerConsume(pTokenizer);
1550 if (rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_NAME_SEPARATOR))
1551 {
1552 PRTJSONVALINT pVal = NULL;
1553 rc = rtJsonTokenizerGetToken(pTokenizer, false /*fObjectKey*/, &pToken);
1554 if (RT_SUCCESS(rc))
1555 rc = rtJsonParseValue(pTokenizer, pToken, &pVal);
1556 if (RT_SUCCESS(rc))
1557 {
1558 if (cMembers == cMembersMax)
1559 {
1560 cMembersMax += 10;
1561 PRTJSONVALINT *papValuesNew = (PRTJSONVALINT *)RTMemRealloc(papValues, cMembersMax * sizeof(PRTJSONVALINT));
1562 char **papszNamesNew = (char **)RTMemRealloc(papszNames, cMembersMax * sizeof(char *));
1563 if (RT_UNLIKELY(!papValuesNew || !papszNamesNew))
1564 {
1565 if (papValuesNew)
1566 RTMemFree(papValuesNew);
1567 if (papszNamesNew)
1568 RTMemFree(papszNamesNew);
1569 RTStrFree(pszName);
1570 rc = VERR_NO_MEMORY;
1571 break;
1572 }
1573
1574 papValues = papValuesNew;
1575 papszNames = papszNamesNew;
1576 }
1577
1578 Assert(cMembers < cMembersMax);
1579 papszNames[cMembers] = pszName;
1580 papValues[cMembers] = pVal;
1581 cMembers++;
1582
1583 /* Skip value separator and continue with next token. */
1584 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
1585 rc = rtJsonTokenizerGetToken(pTokenizer, true /*fObjectKey*/, &pToken);
1586
1587 if ( RT_SUCCESS(rc)
1588 && !fSkippedSep
1589 && pToken->enmClass != RTJSONTOKENCLASS_END_OBJECT)
1590 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of object (#1) (line %zu col %zu)",
1591 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1592 }
1593 else
1594 RTStrFree(pszName);
1595 }
1596 else
1597 {
1598 RTStrFree(pszName);
1599 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected name separator (line %zu col %zu)",
1600 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1601 }
1602 }
1603
1604 if (RT_SUCCESS(rc))
1605 {
1606 if (pToken->enmClass == RTJSONTOKENCLASS_END_OBJECT)
1607 {
1608 rtJsonTokenizerConsume(pTokenizer);
1609 pJsonVal->Type.Object.cMembers = cMembers;
1610 pJsonVal->Type.Object.papValues = papValues;
1611 pJsonVal->Type.Object.papszNames = papszNames;
1612 }
1613 else
1614 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of object (#2) (line %zu col %zu)",
1615 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1616 }
1617
1618 if (RT_FAILURE(rc))
1619 {
1620 for (uint32_t i = 0; i < cMembers; i++)
1621 {
1622 RTJsonValueRelease(papValues[i]);
1623 RTStrFree(papszNames[i]);
1624 }
1625 RTMemFree(papValues);
1626 RTMemFree(papszNames);
1627 }
1628
1629 return rc;
1630}
1631
1632/**
1633 * Parses a single JSON value and returns it on success.
1634 *
1635 * @returns IPRT status code.
1636 * @param pTokenizer The tokenizer to use.
1637 * @param pToken The token to parse.
1638 * @param ppJsonVal Where to store the pointer to the JSON value on success.
1639 */
1640static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken, PRTJSONVALINT *ppJsonVal)
1641{
1642 int rc = VINF_SUCCESS;
1643 PRTJSONVALINT pVal = NULL;
1644
1645 switch (pToken->enmClass)
1646 {
1647 case RTJSONTOKENCLASS_BEGIN_ARRAY:
1648 rtJsonTokenizerConsume(pTokenizer);
1649 pVal = rtJsonValueCreate(RTJSONVALTYPE_ARRAY);
1650 if (RT_LIKELY(pVal))
1651 rc = rtJsonParseArray(pTokenizer, pVal);
1652 break;
1653 case RTJSONTOKENCLASS_BEGIN_OBJECT:
1654 rtJsonTokenizerConsume(pTokenizer);
1655 pVal = rtJsonValueCreate(RTJSONVALTYPE_OBJECT);
1656 if (RT_LIKELY(pVal))
1657 rc = rtJsonParseObject(pTokenizer, pVal);
1658 break;
1659 case RTJSONTOKENCLASS_STRING:
1660 pVal = rtJsonValueCreate(RTJSONVALTYPE_STRING);
1661 if (RT_LIKELY(pVal))
1662 pVal->Type.String.pszStr = pToken->Class.String.pszStr;
1663 rtJsonTokenizerConsume(pTokenizer);
1664 break;
1665 case RTJSONTOKENCLASS_INTEGER:
1666 pVal = rtJsonValueCreate(RTJSONVALTYPE_INTEGER);
1667 if (RT_LIKELY(pVal))
1668 pVal->Type.Integer.i64Num = pToken->Class.Integer.i64Num;
1669 rtJsonTokenizerConsume(pTokenizer);
1670 break;
1671 case RTJSONTOKENCLASS_NUMBER:
1672 pVal = rtJsonValueCreate(RTJSONVALTYPE_NUMBER);
1673 if (RT_LIKELY(pVal))
1674 pVal->Type.rdNum = pToken->Class.rdNum;
1675 rtJsonTokenizerConsume(pTokenizer);
1676 break;
1677 case RTJSONTOKENCLASS_NULL:
1678 rtJsonTokenizerConsume(pTokenizer);
1679 pVal = rtJsonValueCreate(RTJSONVALTYPE_NULL);
1680 break;
1681 case RTJSONTOKENCLASS_FALSE:
1682 rtJsonTokenizerConsume(pTokenizer);
1683 pVal = rtJsonValueCreate(RTJSONVALTYPE_FALSE);
1684 break;
1685 case RTJSONTOKENCLASS_TRUE:
1686 rtJsonTokenizerConsume(pTokenizer);
1687 pVal = rtJsonValueCreate(RTJSONVALTYPE_TRUE);
1688 break;
1689
1690 case RTJSONTOKENCLASS_INVALID:
1691 Assert(!pTokenizer->pErrInfo || RTErrInfoIsSet(pTokenizer->pErrInfo));
1692 rc = VERR_JSON_MALFORMED;
1693 break;
1694 case RTJSONTOKENCLASS_END_ARRAY:
1695 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected '}' (line %zu col %zu)",
1696 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1697 break;
1698 case RTJSONTOKENCLASS_END_OBJECT:
1699 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected ']' (line %zu col %zu)",
1700 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1701 break;
1702 case RTJSONTOKENCLASS_NAME_SEPARATOR:
1703 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected ':' (line %zu col %zu)",
1704 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1705 break;
1706 case RTJSONTOKENCLASS_VALUE_SEPARATOR:
1707 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected ',' (line %zu col %zu)",
1708 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1709 break;
1710 case RTJSONTOKENCLASS_EOS:
1711 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of object (#1) (line %zu col %zu)",
1712 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1713 break;
1714 default:
1715 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "Unexpected token class %d (line %zu col %zu)",
1716 pToken->enmClass, pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1717 break;
1718 }
1719
1720 if (RT_SUCCESS(rc))
1721 {
1722 if (pVal)
1723 *ppJsonVal = pVal;
1724 else
1725 rc = VERR_NO_MEMORY;
1726 }
1727 else if (pVal)
1728 rtJsonValDestroy(pVal);
1729
1730 return rc;
1731}
1732
1733/**
1734 * Entry point to parse a JSON document.
1735 *
1736 * @returns IPRT status code.
1737 * @param pTokenizer The tokenizer state.
1738 * @param ppJsonVal Where to store the root JSON value on success.
1739 */
1740static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal)
1741{
1742 PRTJSONTOKEN pToken = NULL;
1743 int rc = rtJsonTokenizerGetToken(pTokenizer, false /*fObjectKey*/, &pToken);
1744 if (RT_SUCCESS(rc))
1745 rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal);
1746
1747 return rc;
1748}
1749
1750/**
1751 * Read callback for RTJsonParseFromBuf().
1752 */
1753static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, size_t offInput,
1754 void *pvBuf, size_t cbBuf,
1755 size_t *pcbRead)
1756{
1757 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1758 size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0;
1759
1760 if (cbLeft)
1761 memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf));
1762
1763 *pcbRead = RT_MIN(cbLeft, cbBuf);
1764
1765 return VINF_SUCCESS;
1766}
1767
1768/**
1769 * Read callback for RTJsonParseFromString().
1770 */
1771static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, size_t offInput,
1772 void *pvBuf, size_t cbBuf,
1773 size_t *pcbRead)
1774{
1775 const char *pszStr = (const char *)pvUser;
1776 size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */
1777 size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0;
1778
1779 if (cbLeft)
1780 memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf));
1781
1782 *pcbRead = RT_MIN(cbLeft, cbBuf);
1783
1784 return VINF_SUCCESS;
1785}
1786
1787/**
1788 * Read callback for RTJsonParseFromFile().
1789 */
1790static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, size_t offInput,
1791 void *pvBuf, size_t cbBuf,
1792 size_t *pcbRead)
1793{
1794 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1795
1796 RT_NOREF_PV(offInput);
1797
1798 size_t cbRead = 0;
1799 int rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead);
1800 if (RT_SUCCESS(rc))
1801 *pcbRead = cbRead;
1802
1803 return rc;
1804}
1805
1806/**
1807 * Read callback for RTJsonParseFromVfsFile().
1808 */
1809static DECLCALLBACK(int) rtJsonTokenizerParseFromVfsFile(void *pvUser, size_t offInput,
1810 void *pvBuf, size_t cbBuf,
1811 size_t *pcbRead)
1812{
1813 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1814
1815 RT_NOREF_PV(offInput);
1816
1817 size_t cbRead = 0;
1818 int rc = RTVfsFileRead(pArgs->u.hVfsFile, pvBuf, cbBuf, &cbRead);
1819 if (RT_SUCCESS(rc))
1820 *pcbRead = cbRead;
1821
1822 return rc;
1823}
1824
1825RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, uint32_t fFlags, const uint8_t *pbBuf, size_t cbBuf, PRTERRINFO pErrInfo)
1826{
1827 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1828 AssertReturn(!(fFlags & ~RTJSON_PARSE_F_VALID), VERR_INVALID_PARAMETER);
1829 AssertPtrReturn(pbBuf, VERR_INVALID_POINTER);
1830 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
1831
1832 RTJSONTOKENIZER Tokenizer;
1833 RTJSONREADERARGS Args;
1834 Args.cbData = cbBuf;
1835 Args.u.pbBuf = pbBuf;
1836
1837 int rc = rtJsonTokenizerInit(&Tokenizer, fFlags, rtJsonTokenizerParseFromBuf, &Args, pErrInfo);
1838 if (RT_SUCCESS(rc))
1839 {
1840 rc = rtJsonParse(&Tokenizer, phJsonVal);
1841 rtJsonTokenizerDestroy(&Tokenizer);
1842 }
1843
1844 return rc;
1845}
1846
1847RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, uint32_t fFlags, const char *pszStr, PRTERRINFO pErrInfo)
1848{
1849 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1850 AssertReturn(!(fFlags & ~RTJSON_PARSE_F_VALID), VERR_INVALID_PARAMETER);
1851 AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
1852
1853 /** @todo r=bird: The rtJsonTokenizerParseFromString function does
1854 * strlen() on the whole pszStr for each read. For larger strings (
1855 * longer than sizeof(Tokenizer.achBuf)) it would be good to join
1856 * forces with RTJsonParseFromBuf. */
1857 RTJSONTOKENIZER Tokenizer;
1858 int rc = rtJsonTokenizerInit(&Tokenizer, fFlags, rtJsonTokenizerParseFromString, (void *)pszStr, pErrInfo);
1859 if (RT_SUCCESS(rc))
1860 {
1861 rc = rtJsonParse(&Tokenizer, phJsonVal);
1862 rtJsonTokenizerDestroy(&Tokenizer);
1863 }
1864
1865 return rc;
1866}
1867
1868RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
1869{
1870 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1871 AssertReturn(!(fFlags & ~RTJSON_PARSE_F_VALID), VERR_INVALID_PARAMETER);
1872 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1873
1874 int rc = VINF_SUCCESS;
1875 RTJSONREADERARGS Args;
1876
1877 Args.cbData = 0;
1878 rc = RTStrmOpen(pszFilename, "r", &Args.u.hStream);
1879 if (RT_SUCCESS(rc))
1880 {
1881 RTJSONTOKENIZER Tokenizer;
1882
1883 rc = rtJsonTokenizerInit(&Tokenizer, fFlags, rtJsonTokenizerParseFromFile, &Args, pErrInfo);
1884 if (RT_SUCCESS(rc))
1885 {
1886 rc = rtJsonParse(&Tokenizer, phJsonVal);
1887 rtJsonTokenizerDestroy(&Tokenizer);
1888 }
1889 RTStrmClose(Args.u.hStream);
1890 }
1891
1892 return rc;
1893}
1894
1895RTDECL(int) RTJsonParseFromVfsFile(PRTJSONVAL phJsonVal, uint32_t fFlags, RTVFSFILE hVfsFile, PRTERRINFO pErrInfo)
1896{
1897 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1898 AssertReturn(!(fFlags & ~RTJSON_PARSE_F_VALID), VERR_INVALID_PARAMETER);
1899 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_POINTER);
1900
1901 int rc = VINF_SUCCESS;
1902 RTJSONREADERARGS Args;
1903 RTJSONTOKENIZER Tokenizer;
1904
1905 Args.cbData = 0;
1906 Args.u.hVfsFile = hVfsFile;
1907 rc = rtJsonTokenizerInit(&Tokenizer, fFlags, rtJsonTokenizerParseFromVfsFile, &Args, pErrInfo);
1908 if (RT_SUCCESS(rc))
1909 {
1910 rc = rtJsonParse(&Tokenizer, phJsonVal);
1911 rtJsonTokenizerDestroy(&Tokenizer);
1912 }
1913
1914 return rc;
1915}
1916
1917RTDECL(uint32_t) RTJsonValueRetain(RTJSONVAL hJsonVal)
1918{
1919 PRTJSONVALINT pThis = hJsonVal;
1920 AssertPtrReturn(pThis, UINT32_MAX);
1921
1922 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1923 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1924 return cRefs;
1925}
1926
1927RTDECL(uint32_t) RTJsonValueRelease(RTJSONVAL hJsonVal)
1928{
1929 PRTJSONVALINT pThis = hJsonVal;
1930 if (pThis == NIL_RTJSONVAL)
1931 return 0;
1932 AssertPtrReturn(pThis, UINT32_MAX);
1933
1934 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1935 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1936 if (cRefs == 0)
1937 rtJsonValDestroy(pThis);
1938 return cRefs;
1939}
1940
1941RTDECL(RTJSONVALTYPE) RTJsonValueGetType(RTJSONVAL hJsonVal)
1942{
1943 PRTJSONVALINT pThis = hJsonVal;
1944 AssertPtrReturn(pThis, RTJSONVALTYPE_INVALID);
1945
1946 if (pThis == NIL_RTJSONVAL)
1947 return RTJSONVALTYPE_INVALID;
1948
1949 return pThis->enmType;
1950}
1951
1952
1953RTDECL(const char *) RTJsonValueTypeName(RTJSONVALTYPE enmType)
1954{
1955 switch (enmType)
1956 {
1957 case RTJSONVALTYPE_INVALID: return "invalid";
1958 case RTJSONVALTYPE_OBJECT: return "object";
1959 case RTJSONVALTYPE_ARRAY: return "array";
1960 case RTJSONVALTYPE_STRING: return "string";
1961 case RTJSONVALTYPE_INTEGER: return "integer";
1962 case RTJSONVALTYPE_NUMBER: return "number";
1963 case RTJSONVALTYPE_NULL: return "null";
1964 case RTJSONVALTYPE_TRUE: return "true";
1965 case RTJSONVALTYPE_FALSE: return "false";
1966 default: return "???";
1967 }
1968}
1969
1970
1971#define RTJSON_ASSERT_VALID_HANDLE_AND_TYPE_RETURN(pJson, enmExpectedType, ret) do { \
1972 AssertPtrReturn((pJson), (ret)); \
1973 AssertReturn((pJson) != NIL_RTJSONVAL, (ret)); \
1974 AssertReturn((pJson)->enmType == (enmExpectedType), (ret)); \
1975 } while (0)
1976
1977#define RTJSON_TYPECHECK_RETURN(pJson, enmExpectedType) do {\
1978 if ((pJson)->enmType == (enmExpectedType)) { /*likely*/ } \
1979 else { /*AssertFailed();*/ return VERR_JSON_VALUE_INVALID_TYPE; } \
1980 } while (0)
1981
1982
1983#define RTJSON_TYPECHECK_CONTAINER_RETURN(pJson) do { \
1984 if ( (pJson)->enmType == RTJSONVALTYPE_ARRAY \
1985 || (pJson)->enmType == RTJSONVALTYPE_OBJECT) \
1986 { /* likely */ } \
1987 else { /*AssertFailed();*/ return VERR_JSON_VALUE_INVALID_TYPE;} \
1988 } while (0)
1989
1990
1991RTDECL(const char *) RTJsonValueGetString(RTJSONVAL hJsonVal)
1992{
1993 PRTJSONVALINT pThis = hJsonVal;
1994 RTJSON_ASSERT_VALID_HANDLE_AND_TYPE_RETURN(pThis, RTJSONVALTYPE_STRING, NULL);
1995
1996 return pThis->Type.String.pszStr;
1997}
1998
1999
2000RTDECL(int) RTJsonValueQueryString(RTJSONVAL hJsonVal, const char **ppszStr)
2001{
2002 PRTJSONVALINT pThis = hJsonVal;
2003 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2004 AssertPtrReturn(ppszStr, VERR_INVALID_POINTER);
2005
2006 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_STRING);
2007 *ppszStr = pThis->Type.String.pszStr;
2008 return VINF_SUCCESS;
2009}
2010
2011RTDECL(int) RTJsonValueQueryInteger(RTJSONVAL hJsonVal, int64_t *pi64Num)
2012{
2013 PRTJSONVALINT pThis = hJsonVal;
2014 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2015 AssertPtrReturn(pi64Num, VERR_INVALID_POINTER);
2016
2017 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_INTEGER);
2018 *pi64Num = pThis->Type.Integer.i64Num;
2019 return VINF_SUCCESS;
2020}
2021
2022RTDECL(int) RTJsonValueQueryNumber(RTJSONVAL hJsonVal, double *prdNum)
2023{
2024 PRTJSONVALINT pThis = hJsonVal;
2025 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2026 AssertPtrReturn(prdNum, VERR_INVALID_POINTER);
2027
2028 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_NUMBER);
2029 *prdNum = pThis->Type.rdNum;
2030 return VINF_SUCCESS;
2031}
2032
2033RTDECL(int) RTJsonValueQueryByName(RTJSONVAL hJsonVal, const char *pszName, PRTJSONVAL phJsonVal)
2034{
2035 PRTJSONVALINT pThis = hJsonVal;
2036 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2037 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
2038 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
2039
2040 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_OBJECT);
2041
2042 int rc = VERR_NOT_FOUND;
2043 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
2044 {
2045 if (!RTStrCmp(pThis->Type.Object.papszNames[i], pszName))
2046 {
2047 RTJsonValueRetain(pThis->Type.Object.papValues[i]);
2048 *phJsonVal = pThis->Type.Object.papValues[i];
2049 rc = VINF_SUCCESS;
2050 break;
2051 }
2052 }
2053
2054 return rc;
2055}
2056
2057RTDECL(int) RTJsonValueQueryIntegerByName(RTJSONVAL hJsonVal, const char *pszName, int64_t *pi64Num)
2058{
2059 RTJSONVAL hJsonValNum = NIL_RTJSONVAL;
2060 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValNum);
2061 if (RT_SUCCESS(rc))
2062 {
2063 rc = RTJsonValueQueryInteger(hJsonValNum, pi64Num);
2064 RTJsonValueRelease(hJsonValNum);
2065 }
2066
2067 return rc;
2068}
2069
2070RTDECL(int) RTJsonValueQueryNumberByName(RTJSONVAL hJsonVal, const char *pszName, double *prdNum)
2071{
2072 RTJSONVAL hJsonValNum = NIL_RTJSONVAL;
2073 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValNum);
2074 if (RT_SUCCESS(rc))
2075 {
2076 rc = RTJsonValueQueryNumber(hJsonValNum, prdNum);
2077 RTJsonValueRelease(hJsonValNum);
2078 }
2079
2080 return rc;
2081}
2082
2083RTDECL(int) RTJsonValueQueryStringByName(RTJSONVAL hJsonVal, const char *pszName, char **ppszStr)
2084{
2085 RTJSONVAL hJsonValStr = NIL_RTJSONVAL;
2086 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValStr);
2087 if (RT_SUCCESS(rc))
2088 {
2089 const char *pszStr = NULL;
2090 rc = RTJsonValueQueryString(hJsonValStr, &pszStr);
2091 if (RT_SUCCESS(rc))
2092 {
2093 *ppszStr = RTStrDup(pszStr);
2094 if (!*ppszStr)
2095 rc = VERR_NO_STR_MEMORY;
2096 }
2097 RTJsonValueRelease(hJsonValStr);
2098 }
2099
2100 return rc;
2101}
2102
2103RTDECL(int) RTJsonValueQueryBooleanByName(RTJSONVAL hJsonVal, const char *pszName, bool *pfBoolean)
2104{
2105 AssertPtrReturn(pfBoolean, VERR_INVALID_POINTER);
2106
2107 RTJSONVAL hJsonValBool = NIL_RTJSONVAL;
2108 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValBool);
2109 if (RT_SUCCESS(rc))
2110 {
2111 RTJSONVALTYPE enmType = RTJsonValueGetType(hJsonValBool);
2112 if (enmType == RTJSONVALTYPE_TRUE)
2113 *pfBoolean = true;
2114 else if (enmType == RTJSONVALTYPE_FALSE)
2115 *pfBoolean = false;
2116 else
2117 rc = VERR_JSON_VALUE_INVALID_TYPE;
2118 RTJsonValueRelease(hJsonValBool);
2119 }
2120
2121 return rc;
2122}
2123
2124RTDECL(unsigned) RTJsonValueGetArraySize(RTJSONVAL hJsonVal)
2125{
2126 PRTJSONVALINT pThis = hJsonVal;
2127 RTJSON_ASSERT_VALID_HANDLE_AND_TYPE_RETURN(pThis, RTJSONVALTYPE_ARRAY, 0);
2128
2129 return pThis->Type.Array.cItems;
2130}
2131
2132RTDECL(int) RTJsonValueQueryArraySize(RTJSONVAL hJsonVal, unsigned *pcItems)
2133{
2134 PRTJSONVALINT pThis = hJsonVal;
2135 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2136 AssertPtrReturn(pcItems, VERR_INVALID_POINTER);
2137
2138 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
2139 *pcItems = pThis->Type.Array.cItems;
2140 return VINF_SUCCESS;
2141}
2142
2143RTDECL(int) RTJsonValueQueryByIndex(RTJSONVAL hJsonVal, unsigned idx, PRTJSONVAL phJsonVal)
2144{
2145 PRTJSONVALINT pThis = hJsonVal;
2146 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2147 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
2148
2149 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
2150 if (RT_UNLIKELY(idx >= pThis->Type.Array.cItems))
2151 return VERR_OUT_OF_RANGE;
2152
2153 RTJsonValueRetain(pThis->Type.Array.papItems[idx]);
2154 *phJsonVal = pThis->Type.Array.papItems[idx];
2155 return VINF_SUCCESS;
2156}
2157
2158static int rtJsonIteratorBeginWorker(PRTJSONVALINT pThis, PRTJSONIT phJsonIt)
2159{
2160 PRTJSONITINT pIt = (PRTJSONITINT)RTMemTmpAllocZ(sizeof(RTJSONITINT));
2161 if (pIt)
2162 {
2163 RTJsonValueRetain(pThis);
2164 pIt->pJsonVal = pThis;
2165 pIt->idxCur = 0;
2166
2167 *phJsonIt = pIt;
2168 return VINF_SUCCESS;
2169 }
2170 return VERR_NO_MEMORY;
2171}
2172
2173RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
2174{
2175 PRTJSONVALINT pThis = hJsonVal;
2176 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2177 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
2178 RTJSON_TYPECHECK_CONTAINER_RETURN(pThis);
2179
2180 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
2181}
2182
2183RTDECL(int) RTJsonIteratorBeginArray(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
2184{
2185 PRTJSONVALINT pThis = hJsonVal;
2186 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2187 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
2188 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
2189
2190 if (pThis->Type.Array.cItems > 0)
2191 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
2192 return VERR_JSON_IS_EMPTY;
2193}
2194
2195RTDECL(int) RTJsonIteratorBeginObject(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
2196{
2197 PRTJSONVALINT pThis = hJsonVal;
2198 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2199 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
2200 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_OBJECT);
2201
2202 if (pThis->Type.Object.cMembers > 0)
2203 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
2204 return VERR_JSON_IS_EMPTY;
2205}
2206
2207RTDECL(int) RTJsonIteratorQueryValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName)
2208{
2209 PRTJSONITINT pIt = hJsonIt;
2210 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
2211 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
2212 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
2213
2214 int rc = VINF_SUCCESS;
2215 PRTJSONVALINT pThis = pIt->pJsonVal;
2216 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
2217 {
2218 if (pIt->idxCur < pThis->Type.Array.cItems)
2219 {
2220 if (ppszName)
2221 *ppszName = NULL;
2222
2223 RTJsonValueRetain(pThis->Type.Array.papItems[pIt->idxCur]);
2224 *phJsonVal = pThis->Type.Array.papItems[pIt->idxCur];
2225 }
2226 else
2227 rc = VERR_JSON_ITERATOR_END;
2228 }
2229 else
2230 {
2231 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
2232
2233 if (pIt->idxCur < pThis->Type.Object.cMembers)
2234 {
2235 if (ppszName)
2236 *ppszName = pThis->Type.Object.papszNames[pIt->idxCur];
2237
2238 RTJsonValueRetain(pThis->Type.Object.papValues[pIt->idxCur]);
2239 *phJsonVal = pThis->Type.Object.papValues[pIt->idxCur];
2240 }
2241 else
2242 rc = VERR_JSON_ITERATOR_END;
2243 }
2244
2245 return rc;
2246}
2247
2248RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt)
2249{
2250 PRTJSONITINT pIt = hJsonIt;
2251 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
2252 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
2253
2254 int rc = VINF_SUCCESS;
2255 PRTJSONVALINT pThis = pIt->pJsonVal;
2256 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
2257 {
2258 if (pIt->idxCur < pThis->Type.Array.cItems)
2259 pIt->idxCur++;
2260
2261 if (pIt->idxCur == pThis->Type.Array.cItems)
2262 rc = VERR_JSON_ITERATOR_END;
2263 }
2264 else
2265 {
2266 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
2267
2268 if (pIt->idxCur < pThis->Type.Object.cMembers)
2269 pIt->idxCur++;
2270
2271 if (pIt->idxCur == pThis->Type.Object.cMembers)
2272 rc = VERR_JSON_ITERATOR_END;
2273 }
2274
2275 return rc;
2276}
2277
2278RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt)
2279{
2280 PRTJSONITINT pThis = hJsonIt;
2281 AssertPtrReturnVoid(pThis);
2282
2283 if (pThis == NIL_RTJSONIT)
2284 return;
2285
2286 RTJsonValueRelease(pThis->pJsonVal);
2287 RTMemTmpFree(pThis);
2288}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette