VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.4 KB
Line 
1/* $Id: json.cpp 106061 2024-09-16 14:03:52Z 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.virtualbox.org.
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 /** End of stream */
109 RTJSONTOKENCLASS_EOS,
110 /** 32bit hack. */
111 RTJSONTOKENCLASS_32BIT_HACK = 0x7fffffff
112} RTJSONTOKENCLASS;
113/** Pointer to a token class. */
114typedef RTJSONTOKENCLASS *PRTJSONTOKENCLASS;
115
116/**
117 * JSON token.
118 */
119typedef struct RTJSONTOKEN
120{
121 /** Token class. */
122 RTJSONTOKENCLASS enmClass;
123 /** Token position in the source buffer. */
124 RTJSONPOS Pos;
125 /** Data based on the token class. */
126 union
127 {
128 /** String. */
129 struct
130 {
131 /** Pointer to the start of the string. */
132 char *pszStr;
133 } String;
134 /** Number. */
135 struct
136 {
137 int64_t i64Num;
138 } Integer;
139 /** Floating point number. */
140 double rdNum;
141 } Class;
142} RTJSONTOKEN;
143/** Pointer to a JSON token. */
144typedef RTJSONTOKEN *PRTJSONTOKEN;
145/** Pointer to a const script token. */
146typedef const RTJSONTOKEN *PCRTJSONTOKEN;
147
148/**
149 * Tokenizer read input callback.
150 *
151 * @returns IPRT status code.
152 * @param pvUser Opaque user data for the callee.
153 * @param offInput Start offset from the start of the input stream to read from.
154 * @param pvBuf Where to store the read data.
155 * @param cbBuf How much to read.
156 * @param pcbRead Where to store the amount of data read on success.
157 */
158typedef DECLCALLBACKTYPE(int, FNRTJSONTOKENIZERREAD,(void *pvUser, size_t offInput, void *pvBuf, size_t cbBuf,
159 size_t *pcbRead));
160/** Pointer to a tokenizer read buffer callback. */
161typedef FNRTJSONTOKENIZERREAD *PFNRTJSONTOKENIZERREAD;
162
163/**
164 * Tokenizer state.
165 */
166typedef struct RTJSONTOKENIZER
167{
168 /** Read callback. */
169 PFNRTJSONTOKENIZERREAD pfnRead;
170 /** Opaque user data. */
171 void *pvUser;
172 /** Current offset into the input stream. */
173 size_t offInput;
174 /** Number of valid bytes in the input buffer. */
175 size_t cbBuf;
176 /** Current offset into the input buffer. */
177 size_t offBuf;
178 /** Input cache buffer. */
179 char achBuf[512];
180 /** Current position into the input stream. */
181 RTJSONPOS Pos;
182 /** Token 1. */
183 RTJSONTOKEN Token1;
184 /** Token 2. */
185 RTJSONTOKEN Token2;
186 /** Pointer to the current active token. */
187 PRTJSONTOKEN pTokenCurr;
188 /** The next token in the input stream (used for peeking). */
189 PRTJSONTOKEN pTokenNext;
190 /** The tokenizer error state. */
191 int rcTok;
192 /** Where to return extended error information.*/
193 PRTERRINFO pErrInfo;
194} RTJSONTOKENIZER;
195/** Pointer to a JSON tokenizer. */
196typedef RTJSONTOKENIZER *PRTJSONTOKENIZER;
197
198/** Pointer to the internal JSON value instance. */
199typedef struct RTJSONVALINT *PRTJSONVALINT;
200
201/**
202 * A JSON value.
203 */
204typedef struct RTJSONVALINT
205{
206 /** Type of the JSON value. */
207 RTJSONVALTYPE enmType;
208 /** Reference count for this JSON value. */
209 volatile uint32_t cRefs;
210 /** Type dependent data. */
211 union
212 {
213 /** String type*/
214 struct
215 {
216 /** Pointer to the string. */
217 char *pszStr;
218 } String;
219 /** Number type. */
220 struct
221 {
222 /** Signed 64-bit integer. */
223 int64_t i64Num;
224 } Integer;
225 /** Floating point number . */
226 double rdNum;
227 /** Array type. */
228 struct
229 {
230 /** Number of elements in the array. */
231 unsigned cItems;
232 /** Pointer to the array of items. */
233 PRTJSONVALINT *papItems;
234 } Array;
235 /** Object type. */
236 struct
237 {
238 /** Number of members. */
239 unsigned cMembers;
240 /** Pointer to the array holding the member names. */
241 char **papszNames;
242 /** Pointer to the array holding the values. */
243 PRTJSONVALINT *papValues;
244 } Object;
245 } Type;
246} RTJSONVALINT;
247
248/**
249 * A JSON iterator.
250 */
251typedef struct RTJSONITINT
252{
253 /** Referenced JSON value. */
254 PRTJSONVALINT pJsonVal;
255 /** Current index. */
256 unsigned idxCur;
257} RTJSONITINT;
258/** Pointer to the internal JSON iterator instance. */
259typedef RTJSONITINT *PRTJSONITINT;
260
261/**
262 * Passing arguments for the read callbacks.
263 */
264typedef struct RTJSONREADERARGS
265{
266 /** Buffer/File size */
267 size_t cbData;
268 /** Data specific for one callback. */
269 union
270 {
271 PRTSTREAM hStream;
272 const uint8_t *pbBuf;
273 RTVFSFILE hVfsFile;
274 } u;
275} RTJSONREADERARGS;
276/** Pointer to a readers argument. */
277typedef RTJSONREADERARGS *PRTJSONREADERARGS;
278
279
280/*********************************************************************************************************************************
281* Internal Functions *
282*********************************************************************************************************************************/
283static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken, PRTJSONVALINT *ppJsonVal);
284
285
286/**
287 * Fill the input buffer from the input stream.
288 *
289 * @returns IPRT status code.
290 * @param pTokenizer The tokenizer state.
291 */
292static int rtJsonTokenizerRead(PRTJSONTOKENIZER pTokenizer)
293{
294 size_t cbRead = 0;
295 int rc = pTokenizer->pfnRead(pTokenizer->pvUser, pTokenizer->offInput, &pTokenizer->achBuf[0],
296 sizeof(pTokenizer->achBuf), &cbRead);
297 if (RT_SUCCESS(rc))
298 {
299 pTokenizer->cbBuf = cbRead;
300 pTokenizer->offInput += cbRead;
301 pTokenizer->offBuf = 0;
302 /* Validate UTF-8 encoding. */
303 rc = RTStrValidateEncodingEx(&pTokenizer->achBuf[0], cbRead, 0 /* fFlags */);
304 /* If we read less than requested we reached the end and fill the remainder with terminators. */
305 if (cbRead < sizeof(pTokenizer->achBuf))
306 memset(&pTokenizer->achBuf[cbRead], 0, sizeof(pTokenizer->achBuf) - cbRead);
307 }
308
309 return rc;
310}
311
312/**
313 * Skips the given amount of characters in the input stream.
314 *
315 * @returns IPRT status code.
316 * @param pTokenizer The tokenizer state.
317 * @param cchSkip The amount of characters to skip.
318 */
319static int rtJsonTokenizerSkip(PRTJSONTOKENIZER pTokenizer, size_t cchSkip)
320{
321 int rc = VINF_SUCCESS;
322
323 /*
324 * In case we reached the end of the stream don't even attempt to read new data.
325 * Safety precaution for possible bugs in the parser causing out of bounds reads
326 */
327 if (pTokenizer->achBuf[pTokenizer->offBuf] == '\0')
328 return rc;
329
330 while ( cchSkip > 0
331 && pTokenizer->offBuf < pTokenizer->cbBuf
332 && RT_SUCCESS(rc))
333 {
334 size_t cchThisSkip = RT_MIN(cchSkip, pTokenizer->cbBuf - pTokenizer->offBuf);
335
336 pTokenizer->offBuf += cchThisSkip;
337 /* Read new data if required and we didn't reach the end yet. */
338 if ( pTokenizer->offBuf == pTokenizer->cbBuf
339 && pTokenizer->cbBuf == sizeof(pTokenizer->achBuf))
340 rc = rtJsonTokenizerRead(pTokenizer);
341
342 cchSkip -= cchThisSkip;
343 }
344
345 return rc;
346}
347
348
349/**
350 * Returns whether the tokenizer reached the end of the stream.
351 *
352 * @returns true if the tokenizer reached the end of stream marker
353 * false otherwise.
354 * @param pTokenizer The tokenizer state.
355 */
356DECLINLINE(bool) rtJsonTokenizerIsEos(PRTJSONTOKENIZER pTokenizer)
357{
358 return pTokenizer->achBuf[pTokenizer->offBuf] == '\0';
359}
360
361/**
362 * Skip one character in the input stream.
363 *
364 * @param pTokenizer The tokenizer state.
365 */
366DECLINLINE(void) rtJsonTokenizerSkipCh(PRTJSONTOKENIZER pTokenizer)
367{
368 rtJsonTokenizerSkip(pTokenizer, 1);
369 pTokenizer->Pos.iChStart++;
370 pTokenizer->Pos.iChEnd++;
371}
372
373/**
374 * Returns the next char in the input buffer without advancing it.
375 *
376 * @returns Next character in the input buffer.
377 * @param pTokenizer The tokenizer state.
378 */
379DECLINLINE(char) rtJsonTokenizerPeekCh(PRTJSONTOKENIZER pTokenizer)
380{
381 return !rtJsonTokenizerIsEos(pTokenizer)
382 ? pTokenizer->achBuf[pTokenizer->offBuf + 1] /** @todo Read out of bounds */
383 : '\0';
384}
385
386/**
387 * Returns the next character in the input buffer advancing the internal
388 * position.
389 *
390 * @returns Next character in the stream.
391 * @param pTokenizer The tokenizer state.
392 */
393DECLINLINE(char) rtJsonTokenizerGetCh(PRTJSONTOKENIZER pTokenizer)
394{
395 char ch;
396
397 if (!rtJsonTokenizerIsEos(pTokenizer))
398 ch = pTokenizer->achBuf[pTokenizer->offBuf];
399 else
400 ch = '\0';
401
402 return ch;
403}
404
405/**
406 * Sets a new line for the tokenizer.
407 *
408 * @param pTokenizer The tokenizer state.
409 * @param cSkip Amount of characters to skip making up the new line.
410 */
411DECLINLINE(void) rtJsonTokenizerNewLine(PRTJSONTOKENIZER pTokenizer, unsigned cSkip)
412{
413 rtJsonTokenizerSkip(pTokenizer, cSkip);
414 pTokenizer->Pos.iLine++;
415 pTokenizer->Pos.iChStart = 1;
416 pTokenizer->Pos.iChEnd = 1;
417}
418
419/**
420 * Checks whether the current position in the input stream is a new line
421 * and skips it.
422 *
423 * @returns Flag whether there was a new line at the current position
424 * in the input buffer.
425 * @param pTokenizer The tokenizer state.
426 */
427DECLINLINE(bool) rtJsonTokenizerIsSkipNewLine(PRTJSONTOKENIZER pTokenizer)
428{
429 bool fNewline = true;
430
431 if ( rtJsonTokenizerGetCh(pTokenizer) == '\r'
432 && rtJsonTokenizerPeekCh(pTokenizer) == '\n')
433 rtJsonTokenizerNewLine(pTokenizer, 2);
434 else if (rtJsonTokenizerGetCh(pTokenizer) == '\n')
435 rtJsonTokenizerNewLine(pTokenizer, 1);
436 else
437 fNewline = false;
438
439 return fNewline;
440}
441
442/**
443 * Skip all whitespace starting from the current input buffer position.
444 * Skips all present comments too.
445 *
446 * @param pTokenizer The tokenizer state.
447 */
448DECLINLINE(void) rtJsonTokenizerSkipWhitespace(PRTJSONTOKENIZER pTokenizer)
449{
450 while (!rtJsonTokenizerIsEos(pTokenizer))
451 {
452 while ( rtJsonTokenizerGetCh(pTokenizer) == ' '
453 || rtJsonTokenizerGetCh(pTokenizer) == '\t')
454 rtJsonTokenizerSkipCh(pTokenizer);
455
456 if ( !rtJsonTokenizerIsEos(pTokenizer)
457 && !rtJsonTokenizerIsSkipNewLine(pTokenizer))
458 break; /* Skipped everything, next is some real content. */
459 }
460}
461
462/**
463 * Get an literal token from the tokenizer.
464 *
465 * @returns IPRT status code.
466 * @param pTokenizer The tokenizer state.
467 * @param pToken The uninitialized token.
468 */
469static int rtJsonTokenizerGetLiteral(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
470{
471 int rc = VINF_SUCCESS;
472 char ch = rtJsonTokenizerGetCh(pTokenizer);
473 size_t cchLiteral = 0;
474 char szLiteral[6]; /* false + 0 terminator as the lingest possible literal. */
475 RT_ZERO(szLiteral);
476
477 pToken->Pos = pTokenizer->Pos;
478
479 Assert(RT_C_IS_ALPHA(ch));
480
481 while ( RT_C_IS_ALPHA(ch)
482 && cchLiteral < RT_ELEMENTS(szLiteral) - 1)
483 {
484 szLiteral[cchLiteral] = ch;
485 cchLiteral++;
486 rtJsonTokenizerSkipCh(pTokenizer);
487 ch = rtJsonTokenizerGetCh(pTokenizer);
488 }
489
490 if (!RTStrNCmp(&szLiteral[0], "false", RT_ELEMENTS(szLiteral)))
491 pToken->enmClass = RTJSONTOKENCLASS_FALSE;
492 else if (!RTStrNCmp(&szLiteral[0], "true", RT_ELEMENTS(szLiteral)))
493 pToken->enmClass = RTJSONTOKENCLASS_TRUE;
494 else if (!RTStrNCmp(&szLiteral[0], "null", RT_ELEMENTS(szLiteral)))
495 pToken->enmClass = RTJSONTOKENCLASS_NULL;
496 else
497 {
498 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
499 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "malformed literal '%.6s' (line %zu col %zu)",
500 &szLiteral[0], pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
501 }
502
503 pToken->Pos.iChEnd += cchLiteral;
504 return rc;
505}
506
507/**
508 * Get a numerical constant from the tokenizer.
509 *
510 * @returns IPRT status code.
511 * @param pTokenizer The tokenizer state.
512 * @param pToken The uninitialized token.
513 */
514static int rtJsonTokenizerGetNumber(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
515{
516 size_t cchNum = 0;
517 char szTmp[128]; /* Everything larger is not possible to display in signed 64bit. */
518
519 pToken->enmClass = RTJSONTOKENCLASS_INTEGER;
520
521 char ch = rtJsonTokenizerGetCh(pTokenizer);
522 if (ch == '-')
523 {
524 szTmp[cchNum++] = '-';
525 rtJsonTokenizerSkipCh(pTokenizer);
526 ch = rtJsonTokenizerGetCh(pTokenizer);
527 }
528
529 while ( RT_C_IS_DIGIT(ch)
530 && cchNum < sizeof(szTmp) - 1)
531 {
532 szTmp[cchNum] = ch;
533 cchNum++;
534 rtJsonTokenizerSkipCh(pTokenizer);
535 ch = rtJsonTokenizerGetCh(pTokenizer);
536 }
537
538 int rc = VINF_SUCCESS;
539 if (RT_C_IS_DIGIT(ch) && cchNum >= sizeof(szTmp) - 1)
540 rc = VERR_NUMBER_TOO_BIG;
541 else if (ch != '.')
542 {
543 szTmp[cchNum] = '\0';
544 rc = RTStrToInt64Ex(&szTmp[0], NULL, 10, &pToken->Class.Integer.i64Num);
545 Assert(RT_SUCCESS(rc) || rc == VWRN_NUMBER_TOO_BIG);
546 if (rc == VWRN_NUMBER_TOO_BIG)
547 rc = VERR_NUMBER_TOO_BIG;
548 }
549 else
550 {
551 /*
552 * A floating point value.
553 */
554 pToken->enmClass = RTJSONTOKENCLASS_NUMBER;
555 rtJsonTokenizerSkipCh(pTokenizer);
556 szTmp[cchNum++] = '.';
557
558 ch = rtJsonTokenizerGetCh(pTokenizer);
559 while ( RT_C_IS_DIGIT(ch)
560 && cchNum < sizeof(szTmp) - 1)
561 {
562 szTmp[cchNum++] = ch;
563 rtJsonTokenizerSkipCh(pTokenizer);
564 ch = rtJsonTokenizerGetCh(pTokenizer);
565 }
566 if ( (ch == 'e' || ch == 'E')
567 && cchNum < sizeof(szTmp) - 2)
568 {
569 szTmp[cchNum++] = 'e';
570 rtJsonTokenizerSkipCh(pTokenizer);
571 ch = rtJsonTokenizerGetCh(pTokenizer);
572 if (ch == '+' || ch == '-')
573 {
574 szTmp[cchNum++] = ch;
575 rtJsonTokenizerSkipCh(pTokenizer);
576 ch = rtJsonTokenizerGetCh(pTokenizer);
577 }
578 while ( RT_C_IS_DIGIT(ch)
579 && cchNum < sizeof(szTmp) - 1)
580 {
581 szTmp[cchNum++] = ch;
582 rtJsonTokenizerSkipCh(pTokenizer);
583 ch = rtJsonTokenizerGetCh(pTokenizer);
584 }
585 }
586 if (cchNum < sizeof(szTmp) - 1)
587 {
588 szTmp[cchNum] = '\0';
589
590 /** @todo Not sure if strtod does the 100% right thing here... */
591 errno = 0;
592 char *pszNext = NULL;
593 pToken->Class.rdNum = strtod(szTmp, &pszNext);
594 if (errno == 0)
595 {
596 rc = VINF_SUCCESS;
597 Assert(!pszNext || *pszNext == '\0');
598 }
599 else
600 rc = RTErrConvertFromErrno(errno);
601 }
602 }
603
604 return rc;
605}
606
607/**
608 * Parses a string constant.
609 *
610 * @returns IPRT status code.
611 * @param pTokenizer The tokenizer state.
612 * @param pToken The uninitialized token.
613 */
614static int rtJsonTokenizerGetString(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
615{
616 size_t cchStrMax = 64;
617 char *pszDecoded = (char *)RTStrAlloc(cchStrMax);
618 AssertReturn(pszDecoded, VERR_NO_STR_MEMORY);
619
620 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\"');
621 rtJsonTokenizerSkipCh(pTokenizer); /* Skip " */
622
623 pToken->enmClass = RTJSONTOKENCLASS_STRING;
624 pToken->Pos = pTokenizer->Pos;
625
626 size_t cchStr = 0;
627 char ch = rtJsonTokenizerGetCh(pTokenizer);
628 while ( ch != '\"'
629 && ch != '\0')
630 {
631 if (ch != '\\')
632 {
633 pszDecoded[cchStr++] = ch;
634 rtJsonTokenizerSkipCh(pTokenizer);
635 }
636 else
637 {
638 /* Escape sequence, check the next character */
639 rtJsonTokenizerSkipCh(pTokenizer);
640 char chNext = rtJsonTokenizerGetCh(pTokenizer);
641 switch (chNext)
642 {
643 case '\"':
644 pszDecoded[cchStr++] = '\"';
645 rtJsonTokenizerSkipCh(pTokenizer);
646 break;
647 case '\\':
648 pszDecoded[cchStr++] = '\\';
649 rtJsonTokenizerSkipCh(pTokenizer);
650 break;
651 case '/':
652 pszDecoded[cchStr++] = '/';
653 rtJsonTokenizerSkipCh(pTokenizer);
654 break;
655 case 'b':
656 pszDecoded[cchStr++] = '\b';
657 rtJsonTokenizerSkipCh(pTokenizer);
658 break;
659 case 'n':
660 pszDecoded[cchStr++] = '\n';
661 rtJsonTokenizerSkipCh(pTokenizer);
662 break;
663 case 'f':
664 pszDecoded[cchStr++] = '\f';
665 rtJsonTokenizerSkipCh(pTokenizer);
666 break;
667 case 'r':
668 pszDecoded[cchStr++] = '\r';
669 rtJsonTokenizerSkipCh(pTokenizer);
670 break;
671 case 't':
672 pszDecoded[cchStr++] = '\t';
673 rtJsonTokenizerSkipCh(pTokenizer);
674 break;
675 case 'u':
676 {
677 /* \uXXXX */
678 int rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
679 rtJsonTokenizerSkipCh(pTokenizer);
680 char chX1 = rtJsonTokenizerGetCh(pTokenizer);
681 if (RT_C_IS_XDIGIT(chX1))
682 {
683 rtJsonTokenizerSkipCh(pTokenizer);
684 char chX2 = rtJsonTokenizerGetCh(pTokenizer);
685 if (RT_C_IS_XDIGIT(chX2))
686 {
687 rtJsonTokenizerSkipCh(pTokenizer);
688 char chX3 = rtJsonTokenizerGetCh(pTokenizer);
689 if (RT_C_IS_XDIGIT(chX3))
690 {
691 rtJsonTokenizerSkipCh(pTokenizer);
692 char chX4 = rtJsonTokenizerGetCh(pTokenizer);
693 if (RT_C_IS_XDIGIT(chX4))
694 {
695 rtJsonTokenizerSkipCh(pTokenizer);
696
697 RTUNICP uc = ((RTUTF16)(chX1 <= '9' ? chX1 - '0' : (chX1 & 7) + 9) << 12)
698 | ((RTUTF16)(chX2 <= '9' ? chX2 - '0' : (chX2 & 7) + 9) << 8)
699 | ((RTUTF16)(chX3 <= '9' ? chX3 - '0' : (chX3 & 7) + 9) << 4)
700 | ((RTUTF16)(chX4 <= '9' ? chX4 - '0' : (chX4 & 7) + 9));
701 if ( !RTUtf16IsHighSurrogate((RTUTF16)uc)
702 && !RTUtf16IsLowSurrogate((RTUTF16)uc))
703 rc = VINF_SUCCESS;
704 else if (RTUtf16IsHighSurrogate((RTUTF16)uc))
705 {
706 /* The must be a low surrogate pair following the high one: */
707 rc = VINF_SUCCESS;
708 ch = rtJsonTokenizerGetCh(pTokenizer);
709 if (ch == '\\')
710 rtJsonTokenizerSkipCh(pTokenizer);
711 else
712 rc = VERR_JSON_MISSING_SURROGATE_PAIR;
713 ch = rtJsonTokenizerGetCh(pTokenizer);
714 if (ch == 'u')
715 rtJsonTokenizerSkipCh(pTokenizer);
716 else
717 rc = VERR_JSON_MISSING_SURROGATE_PAIR;
718 chX1 = rtJsonTokenizerGetCh(pTokenizer);
719 if (RT_C_IS_XDIGIT(chX1))
720 rtJsonTokenizerSkipCh(pTokenizer);
721 else if (RT_SUCCESS_NP(rc))
722 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
723 chX2 = rtJsonTokenizerGetCh(pTokenizer);
724 if (RT_C_IS_XDIGIT(chX2))
725 rtJsonTokenizerSkipCh(pTokenizer);
726 else if (RT_SUCCESS_NP(rc))
727 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
728 chX3 = rtJsonTokenizerGetCh(pTokenizer);
729 if (RT_C_IS_XDIGIT(chX3))
730 rtJsonTokenizerSkipCh(pTokenizer);
731 else if (RT_SUCCESS_NP(rc))
732 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
733 chX4 = rtJsonTokenizerGetCh(pTokenizer);
734 if (RT_C_IS_XDIGIT(chX4))
735 rtJsonTokenizerSkipCh(pTokenizer);
736 else if (RT_SUCCESS_NP(rc))
737 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
738 if (RT_SUCCESS(rc))
739 {
740 RTUTF16 wc2 = ((RTUTF16)(chX1 <= '9' ? chX1 - '0' : (chX1 & 7) + 9) << 12)
741 | ((RTUTF16)(chX2 <= '9' ? chX2 - '0' : (chX2 & 7) + 9) << 8)
742 | ((RTUTF16)(chX3 <= '9' ? chX3 - '0' : (chX3 & 7) + 9) << 4)
743 | ((RTUTF16)(chX4 <= '9' ? chX4 - '0' : (chX4 & 7) + 9));
744 if (RTUtf16IsLowSurrogate(wc2))
745 uc = 0x10000 + (((uc & 0x3ff) << 10) | (wc2 & 0x3ff));
746 else
747 rc = VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE;
748 }
749 }
750 else
751 rc = VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE;
752 if (RT_SUCCESS(rc))
753 {
754 if ( uc != 0
755 && uc != 0xfffe
756 && uc != 0xffff)
757 {
758 Assert(cchStr + RTStrCpSize(uc) < cchStrMax);
759 char *pszNext = RTStrPutCp(&pszDecoded[cchStr], uc);
760 Assert((size_t)(pszNext - &pszDecoded[cchStr]) == RTStrCpSize(uc));
761 cchStr += pszNext - &pszDecoded[cchStr];
762 break;
763 }
764 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_INVALID_CODEPOINT,
765 "Invalid \\u code point: %#x (line %zu col %zu)",
766 uc, pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
767 }
768 }
769 }
770 }
771 }
772 RTStrFree(pszDecoded);
773 if (rc == VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE)
774 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Invalid \\u escape sequence (line %zu col %zu)",
775 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
776 else if (rc == VERR_JSON_MISSING_SURROGATE_PAIR)
777 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Missing UTF-16 surrogate pair (line %zu col %zu)",
778 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
779 else if (rc == VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE)
780 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Invalid UTF-16 surrogate pair (line %zu col %zu)",
781 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
782 return rc;
783 }
784
785 default:
786 RTStrFree(pszDecoded);
787 return RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "bad escape sequence (line %zu col %zu)",
788 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
789 }
790 }
791
792
793 if (cchStr < cchStrMax - 4)
794 { /* likely */ }
795 else
796 {
797 /* Increase string space. */
798 size_t cchStrMaxNew = cchStrMax < _4K ? cchStrMax * 2 : cchStrMax + _4K;
799 int rc = RTStrRealloc(&pszDecoded, cchStrMaxNew);
800 if (RT_SUCCESS(rc))
801 cchStrMax = cchStrMaxNew;
802 else
803 {
804 RTStrFree(pszDecoded);
805 return rc;
806 }
807 }
808 ch = rtJsonTokenizerGetCh(pTokenizer);
809 }
810
811 if (ch == '\"')
812 rtJsonTokenizerSkipCh(pTokenizer); /* Skip closing " */
813
814 Assert(cchStr < cchStrMax);
815 pszDecoded[cchStr] = '\0';
816 if (cchStrMax - cchStr >= cchStrMax / 2)
817 RTStrRealloc(&pszDecoded, cchStr + 1);
818 pToken->Class.String.pszStr = pszDecoded;
819
820 pToken->Pos.iChEnd = pTokenizer->Pos.iChEnd;
821 return VINF_SUCCESS;
822}
823
824/**
825 * Get the end of stream token.
826 *
827 * @returns IPRT status code.
828 * @param pTokenizer The tokenizer state.
829 * @param pToken The uninitialized token.
830 */
831static int rtJsonTokenizerGetEos(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
832{
833 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\0');
834
835 pToken->enmClass = RTJSONTOKENCLASS_EOS;
836 pToken->Pos = pTokenizer->Pos;
837 return VINF_SUCCESS;
838}
839
840/**
841 * Read the next token from the tokenizer stream.
842 *
843 * @returns IPRT status code.
844 * @param pTokenizer The tokenizer to read from.
845 * @param pToken Uninitialized token to fill the token data into.
846 */
847static int rtJsonTokenizerReadNextToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
848{
849 int rc = VINF_SUCCESS;
850
851 /* Skip all eventually existing whitespace and newlines first. */
852 rtJsonTokenizerSkipWhitespace(pTokenizer);
853
854 char ch = rtJsonTokenizerGetCh(pTokenizer);
855 if (RT_C_IS_ALPHA(ch))
856 rc = rtJsonTokenizerGetLiteral(pTokenizer, pToken);
857 else if (RT_C_IS_DIGIT(ch) || ch == '-')
858 rc = rtJsonTokenizerGetNumber(pTokenizer, pToken);
859 else if (ch == '\"')
860 rc = rtJsonTokenizerGetString(pTokenizer, pToken);
861 else if (ch == '\0')
862 rc = rtJsonTokenizerGetEos(pTokenizer, pToken);
863 else if (ch == '{')
864 {
865 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_OBJECT;
866 rtJsonTokenizerSkipCh(pTokenizer);
867 }
868 else if (ch == '}')
869 {
870 pToken->enmClass = RTJSONTOKENCLASS_END_OBJECT;
871 rtJsonTokenizerSkipCh(pTokenizer);
872 }
873 else if (ch == '[')
874 {
875 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_ARRAY;
876 rtJsonTokenizerSkipCh(pTokenizer);
877 }
878 else if (ch == ']')
879 {
880 pToken->enmClass = RTJSONTOKENCLASS_END_ARRAY;
881 rtJsonTokenizerSkipCh(pTokenizer);
882 }
883 else if (ch == ':')
884 {
885 pToken->enmClass = RTJSONTOKENCLASS_NAME_SEPARATOR;
886 rtJsonTokenizerSkipCh(pTokenizer);
887 }
888 else if (ch == ',')
889 {
890 pToken->enmClass = RTJSONTOKENCLASS_VALUE_SEPARATOR;
891 rtJsonTokenizerSkipCh(pTokenizer);
892 }
893 else
894 {
895 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
896 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "bad token '%c' (line %zu col %zu)",
897 ch, pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
898 }
899
900 if (RT_FAILURE(rc))
901 pTokenizer->rcTok = rc;
902
903 return rc;
904}
905
906/**
907 * Create a new tokenizer.
908 *
909 * @returns IPRT status code.
910 * @param pTokenizer The tokenizer state to initialize.
911 * @param pfnRead Read callback for the input stream.
912 * @param pvUser Opaque user data to pass to the callback.
913 * @param pErrInfo Where to return extended error info.
914 */
915static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, PFNRTJSONTOKENIZERREAD pfnRead, void *pvUser, PRTERRINFO pErrInfo)
916{
917 pTokenizer->pfnRead = pfnRead;
918 pTokenizer->pvUser = pvUser;
919 pTokenizer->offInput = 0;
920 pTokenizer->cbBuf = 0;
921 pTokenizer->offBuf = 0;
922 pTokenizer->Pos.iLine = 1;
923 pTokenizer->Pos.iChStart = 1;
924 pTokenizer->Pos.iChEnd = 1;
925 pTokenizer->pTokenCurr = &pTokenizer->Token1;
926 pTokenizer->pTokenNext = &pTokenizer->Token2;
927 pTokenizer->rcTok = VINF_SUCCESS;
928 pTokenizer->pErrInfo = pErrInfo;
929
930 RT_ZERO(pTokenizer->achBuf);
931
932 /* Fill the input buffer. */
933 int rc = rtJsonTokenizerRead(pTokenizer);
934
935 /* Fill the tokenizer with two first tokens. */
936 if (RT_SUCCESS(rc))
937 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr);
938 if (RT_SUCCESS(rc))
939 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
940
941 return rc;
942}
943
944/**
945 * Cleans up any resources still in control of the given token.
946 *
947 * @param pToken The toke nto clean up.
948 */
949static void rtJsonTokenizerTokenCleanup(PRTJSONTOKEN pToken)
950{
951 if ( pToken->enmClass == RTJSONTOKENCLASS_STRING
952 && pToken->Class.String.pszStr)
953 RTStrFree(pToken->Class.String.pszStr);
954}
955
956/**
957 * Destroys a given tokenizer state.
958 *
959 * @param pTokenizer The tokenizer to destroy.
960 */
961static void rtJsonTokenizerDestroy(PRTJSONTOKENIZER pTokenizer)
962{
963 rtJsonTokenizerTokenCleanup(pTokenizer->pTokenCurr);
964 rtJsonTokenizerTokenCleanup(pTokenizer->pTokenNext);
965}
966
967/**
968 * Get the current token in the input stream.
969 *
970 * @returns Pointer to the next token in the stream.
971 * @param pTokenizer The tokenizer state.
972 * @param ppToken Where to store the pointer to the current token on success.
973 */
974DECLINLINE(int) rtJsonTokenizerGetToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN *ppToken)
975{
976 if (RT_SUCCESS(pTokenizer->rcTok))
977 {
978 *ppToken = pTokenizer->pTokenCurr;
979 return VINF_SUCCESS;
980 }
981
982 return pTokenizer->rcTok;
983}
984
985/**
986 * Consume the current token advancing to the next in the stream.
987 *
988 * @param pTokenizer The tokenizer state.
989 */
990static void rtJsonTokenizerConsume(PRTJSONTOKENIZER pTokenizer)
991{
992 PRTJSONTOKEN pTokenTmp = pTokenizer->pTokenCurr;
993
994 /* Switch next token to current token and read in the next token. */
995 pTokenizer->pTokenCurr = pTokenizer->pTokenNext;
996 pTokenizer->pTokenNext = pTokenTmp;
997 rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
998}
999
1000/**
1001 * Consumes the current token if it matches the given class returning an indicator.
1002 *
1003 * @returns true if the class matched and the token was consumed.
1004 * @retval false otherwise.
1005 * @param pTokenizer The tokenizer state.
1006 * @param enmClass The token class to match against.
1007 */
1008static bool rtJsonTokenizerConsumeIfMatched(PRTJSONTOKENIZER pTokenizer, RTJSONTOKENCLASS enmClass)
1009{
1010 PRTJSONTOKEN pToken = NULL;
1011 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1012 if (RT_SUCCESS(rc))
1013 {
1014 if (pToken->enmClass == enmClass)
1015 {
1016 rtJsonTokenizerConsume(pTokenizer);
1017 return true;
1018 }
1019 }
1020
1021 return false;
1022}
1023
1024/**
1025 * Destroys a given JSON value releasing the reference to all child values.
1026 *
1027 * @param pThis The JSON value to destroy.
1028 */
1029static void rtJsonValDestroy(PRTJSONVALINT pThis)
1030{
1031 switch (pThis->enmType)
1032 {
1033 case RTJSONVALTYPE_OBJECT:
1034 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
1035 {
1036 RTStrFree(pThis->Type.Object.papszNames[i]);
1037 RTJsonValueRelease(pThis->Type.Object.papValues[i]);
1038 }
1039 RTMemFree(pThis->Type.Object.papszNames);
1040 RTMemFree(pThis->Type.Object.papValues);
1041 break;
1042 case RTJSONVALTYPE_ARRAY:
1043 for (unsigned i = 0; i < pThis->Type.Array.cItems; i++)
1044 RTJsonValueRelease(pThis->Type.Array.papItems[i]);
1045 RTMemFree(pThis->Type.Array.papItems);
1046 break;
1047 case RTJSONVALTYPE_STRING:
1048 RTStrFree(pThis->Type.String.pszStr);
1049 break;
1050 case RTJSONVALTYPE_INTEGER:
1051 case RTJSONVALTYPE_NUMBER:
1052 case RTJSONVALTYPE_NULL:
1053 case RTJSONVALTYPE_TRUE:
1054 case RTJSONVALTYPE_FALSE:
1055 /* nothing to do. */
1056 break;
1057 default:
1058 AssertMsgFailed(("Invalid JSON value type: %u\n", pThis->enmType));
1059 }
1060 RTMemFree(pThis);
1061}
1062
1063/**
1064 * Creates a new JSON value with the given type.
1065 *
1066 * @returns Pointer to JSON value on success, NULL if out of memory.
1067 * @param enmType The JSON value type.
1068 */
1069static PRTJSONVALINT rtJsonValueCreate(RTJSONVALTYPE enmType)
1070{
1071 PRTJSONVALINT pThis = (PRTJSONVALINT)RTMemAllocZ(sizeof(RTJSONVALINT));
1072 if (RT_LIKELY(pThis))
1073 {
1074 pThis->enmType = enmType;
1075 pThis->cRefs = 1;
1076 }
1077
1078 return pThis;
1079}
1080
1081/**
1082 * Parses an JSON array.
1083 *
1084 * @returns IPRT status code.
1085 * @param pTokenizer The tokenizer to use.
1086 * @param pJsonVal The JSON array value to fill in.
1087 */
1088static int rtJsonParseArray(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal)
1089{
1090 int rc = VINF_SUCCESS;
1091 PRTJSONTOKEN pToken = NULL;
1092 uint32_t cItems = 0;
1093 uint32_t cItemsMax = 0;
1094 PRTJSONVALINT *papItems = NULL;
1095
1096 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1097 while ( RT_SUCCESS(rc)
1098 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY
1099 && pToken->enmClass != RTJSONTOKENCLASS_EOS)
1100 {
1101 PRTJSONVALINT pVal = NULL;
1102 rc = rtJsonParseValue(pTokenizer, pToken, &pVal);
1103 if (RT_SUCCESS(rc))
1104 {
1105 if (cItems == cItemsMax)
1106 {
1107 cItemsMax += 10;
1108 PRTJSONVALINT *papItemsNew = (PRTJSONVALINT *)RTMemRealloc(papItems, cItemsMax * sizeof(PRTJSONVALINT));
1109 if (RT_UNLIKELY(!papItemsNew))
1110 {
1111 rc = VERR_NO_MEMORY;
1112 break;
1113 }
1114 papItems = papItemsNew;
1115 }
1116
1117 Assert(cItems < cItemsMax);
1118 papItems[cItems] = pVal;
1119 cItems++;
1120 }
1121
1122 /* Skip value separator and continue with next token. */
1123 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
1124 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1125
1126 if ( RT_SUCCESS(rc)
1127 && !fSkippedSep
1128 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY)
1129 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of array (#1) (line %zu col %zu)",
1130 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1131 }
1132
1133 if (RT_SUCCESS(rc))
1134 {
1135 if (pToken->enmClass == RTJSONTOKENCLASS_END_ARRAY)
1136 {
1137 rtJsonTokenizerConsume(pTokenizer);
1138 pJsonVal->Type.Array.cItems = cItems;
1139 pJsonVal->Type.Array.papItems = papItems;
1140 }
1141 else
1142 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of array (#2) (line %zu col %zu)",
1143 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1144 }
1145
1146 if (RT_FAILURE(rc))
1147 {
1148 for (uint32_t i = 0; i < cItems; i++)
1149 RTJsonValueRelease(papItems[i]);
1150 RTMemFree(papItems);
1151 }
1152
1153 return rc;
1154}
1155
1156/**
1157 * Parses an JSON object.
1158 *
1159 * @returns IPRT status code.
1160 * @param pTokenizer The tokenizer to use.
1161 * @param pJsonVal The JSON object value to fill in.
1162 */
1163static int rtJsonParseObject(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal)
1164{
1165 int rc = VINF_SUCCESS;
1166 PRTJSONTOKEN pToken = NULL;
1167 uint32_t cMembers = 0;
1168 uint32_t cMembersMax = 0;
1169 PRTJSONVALINT *papValues = NULL;
1170 char **papszNames = NULL;
1171
1172 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1173 while ( RT_SUCCESS(rc)
1174 && pToken->enmClass == RTJSONTOKENCLASS_STRING)
1175 {
1176 char *pszName = pToken->Class.String.pszStr; /* We can consume this string as it was allocated. */
1177 pToken->Class.String.pszStr = NULL;
1178
1179 rtJsonTokenizerConsume(pTokenizer);
1180 if (rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_NAME_SEPARATOR))
1181 {
1182 PRTJSONVALINT pVal = NULL;
1183 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1184 if (RT_SUCCESS(rc))
1185 rc = rtJsonParseValue(pTokenizer, pToken, &pVal);
1186 if (RT_SUCCESS(rc))
1187 {
1188 if (cMembers == cMembersMax)
1189 {
1190 cMembersMax += 10;
1191 PRTJSONVALINT *papValuesNew = (PRTJSONVALINT *)RTMemRealloc(papValues, cMembersMax * sizeof(PRTJSONVALINT));
1192 char **papszNamesNew = (char **)RTMemRealloc(papszNames, cMembersMax * sizeof(char *));
1193 if (RT_UNLIKELY(!papValuesNew || !papszNamesNew))
1194 {
1195 if (papValuesNew)
1196 RTMemFree(papValuesNew);
1197 if (papszNamesNew)
1198 RTMemFree(papszNamesNew);
1199 RTStrFree(pszName);
1200 rc = VERR_NO_MEMORY;
1201 break;
1202 }
1203
1204 papValues = papValuesNew;
1205 papszNames = papszNamesNew;
1206 }
1207
1208 Assert(cMembers < cMembersMax);
1209 papszNames[cMembers] = pszName;
1210 papValues[cMembers] = pVal;
1211 cMembers++;
1212
1213 /* Skip value separator and continue with next token. */
1214 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
1215 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1216
1217 if ( RT_SUCCESS(rc)
1218 && !fSkippedSep
1219 && pToken->enmClass != RTJSONTOKENCLASS_END_OBJECT)
1220 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of object (#1) (line %zu col %zu)",
1221 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1222 }
1223 else
1224 RTStrFree(pszName);
1225 }
1226 else
1227 {
1228 RTStrFree(pszName);
1229 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected name separator (line %zu col %zu)",
1230 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1231 }
1232 }
1233
1234 if (RT_SUCCESS(rc))
1235 {
1236 if (pToken->enmClass == RTJSONTOKENCLASS_END_OBJECT)
1237 {
1238 rtJsonTokenizerConsume(pTokenizer);
1239 pJsonVal->Type.Object.cMembers = cMembers;
1240 pJsonVal->Type.Object.papValues = papValues;
1241 pJsonVal->Type.Object.papszNames = papszNames;
1242 }
1243 else
1244 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of object (#2) (line %zu col %zu)",
1245 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1246 }
1247
1248 if (RT_FAILURE(rc))
1249 {
1250 for (uint32_t i = 0; i < cMembers; i++)
1251 {
1252 RTJsonValueRelease(papValues[i]);
1253 RTStrFree(papszNames[i]);
1254 }
1255 RTMemFree(papValues);
1256 RTMemFree(papszNames);
1257 }
1258
1259 return rc;
1260}
1261
1262/**
1263 * Parses a single JSON value and returns it on success.
1264 *
1265 * @returns IPRT status code.
1266 * @param pTokenizer The tokenizer to use.
1267 * @param pToken The token to parse.
1268 * @param ppJsonVal Where to store the pointer to the JSON value on success.
1269 */
1270static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken, PRTJSONVALINT *ppJsonVal)
1271{
1272 int rc = VINF_SUCCESS;
1273 PRTJSONVALINT pVal = NULL;
1274
1275 switch (pToken->enmClass)
1276 {
1277 case RTJSONTOKENCLASS_BEGIN_ARRAY:
1278 rtJsonTokenizerConsume(pTokenizer);
1279 pVal = rtJsonValueCreate(RTJSONVALTYPE_ARRAY);
1280 if (RT_LIKELY(pVal))
1281 rc = rtJsonParseArray(pTokenizer, pVal);
1282 break;
1283 case RTJSONTOKENCLASS_BEGIN_OBJECT:
1284 rtJsonTokenizerConsume(pTokenizer);
1285 pVal = rtJsonValueCreate(RTJSONVALTYPE_OBJECT);
1286 if (RT_LIKELY(pVal))
1287 rc = rtJsonParseObject(pTokenizer, pVal);
1288 break;
1289 case RTJSONTOKENCLASS_STRING:
1290 pVal = rtJsonValueCreate(RTJSONVALTYPE_STRING);
1291 if (RT_LIKELY(pVal))
1292 pVal->Type.String.pszStr = pToken->Class.String.pszStr;
1293 rtJsonTokenizerConsume(pTokenizer);
1294 break;
1295 case RTJSONTOKENCLASS_INTEGER:
1296 pVal = rtJsonValueCreate(RTJSONVALTYPE_INTEGER);
1297 if (RT_LIKELY(pVal))
1298 pVal->Type.Integer.i64Num = pToken->Class.Integer.i64Num;
1299 rtJsonTokenizerConsume(pTokenizer);
1300 break;
1301 case RTJSONTOKENCLASS_NUMBER:
1302 pVal = rtJsonValueCreate(RTJSONVALTYPE_NUMBER);
1303 if (RT_LIKELY(pVal))
1304 pVal->Type.rdNum = pToken->Class.rdNum;
1305 rtJsonTokenizerConsume(pTokenizer);
1306 break;
1307 case RTJSONTOKENCLASS_NULL:
1308 rtJsonTokenizerConsume(pTokenizer);
1309 pVal = rtJsonValueCreate(RTJSONVALTYPE_NULL);
1310 break;
1311 case RTJSONTOKENCLASS_FALSE:
1312 rtJsonTokenizerConsume(pTokenizer);
1313 pVal = rtJsonValueCreate(RTJSONVALTYPE_FALSE);
1314 break;
1315 case RTJSONTOKENCLASS_TRUE:
1316 rtJsonTokenizerConsume(pTokenizer);
1317 pVal = rtJsonValueCreate(RTJSONVALTYPE_TRUE);
1318 break;
1319
1320 case RTJSONTOKENCLASS_INVALID:
1321 Assert(!pTokenizer->pErrInfo || RTErrInfoIsSet(pTokenizer->pErrInfo));
1322 rc = VERR_JSON_MALFORMED;
1323 break;
1324 case RTJSONTOKENCLASS_END_ARRAY:
1325 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected '}' (line %zu col %zu)",
1326 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1327 break;
1328 case RTJSONTOKENCLASS_END_OBJECT:
1329 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected ']' (line %zu col %zu)",
1330 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1331 break;
1332 case RTJSONTOKENCLASS_NAME_SEPARATOR:
1333 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected ':' (line %zu col %zu)",
1334 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1335 break;
1336 case RTJSONTOKENCLASS_VALUE_SEPARATOR:
1337 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected ',' (line %zu col %zu)",
1338 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1339 break;
1340 case RTJSONTOKENCLASS_EOS:
1341 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of object (#1) (line %zu col %zu)",
1342 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1343 break;
1344 default:
1345 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "Unexpected token class %d (line %zu col %zu)",
1346 pToken->enmClass, pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1347 break;
1348 }
1349
1350 if (RT_SUCCESS(rc))
1351 {
1352 if (pVal)
1353 *ppJsonVal = pVal;
1354 else
1355 rc = VERR_NO_MEMORY;
1356 }
1357 else if (pVal)
1358 rtJsonValDestroy(pVal);
1359
1360 return rc;
1361}
1362
1363/**
1364 * Entry point to parse a JSON document.
1365 *
1366 * @returns IPRT status code.
1367 * @param pTokenizer The tokenizer state.
1368 * @param ppJsonVal Where to store the root JSON value on success.
1369 */
1370static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal)
1371{
1372 PRTJSONTOKEN pToken = NULL;
1373 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1374 if (RT_SUCCESS(rc))
1375 rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal);
1376
1377 return rc;
1378}
1379
1380/**
1381 * Read callback for RTJsonParseFromBuf().
1382 */
1383static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, size_t offInput,
1384 void *pvBuf, size_t cbBuf,
1385 size_t *pcbRead)
1386{
1387 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1388 size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0;
1389
1390 if (cbLeft)
1391 memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf));
1392
1393 *pcbRead = RT_MIN(cbLeft, cbBuf);
1394
1395 return VINF_SUCCESS;
1396}
1397
1398/**
1399 * Read callback for RTJsonParseFromString().
1400 */
1401static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, size_t offInput,
1402 void *pvBuf, size_t cbBuf,
1403 size_t *pcbRead)
1404{
1405 const char *pszStr = (const char *)pvUser;
1406 size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */
1407 size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0;
1408
1409 if (cbLeft)
1410 memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf));
1411
1412 *pcbRead = RT_MIN(cbLeft, cbBuf);
1413
1414 return VINF_SUCCESS;
1415}
1416
1417/**
1418 * Read callback for RTJsonParseFromFile().
1419 */
1420static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, size_t offInput,
1421 void *pvBuf, size_t cbBuf,
1422 size_t *pcbRead)
1423{
1424 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1425
1426 RT_NOREF_PV(offInput);
1427
1428 size_t cbRead = 0;
1429 int rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead);
1430 if (RT_SUCCESS(rc))
1431 *pcbRead = cbRead;
1432
1433 return rc;
1434}
1435
1436/**
1437 * Read callback for RTJsonParseFromVfsFile().
1438 */
1439static DECLCALLBACK(int) rtJsonTokenizerParseFromVfsFile(void *pvUser, size_t offInput,
1440 void *pvBuf, size_t cbBuf,
1441 size_t *pcbRead)
1442{
1443 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1444
1445 RT_NOREF_PV(offInput);
1446
1447 size_t cbRead = 0;
1448 int rc = RTVfsFileRead(pArgs->u.hVfsFile, pvBuf, cbBuf, &cbRead);
1449 if (RT_SUCCESS(rc))
1450 *pcbRead = cbRead;
1451
1452 return rc;
1453}
1454
1455RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf, PRTERRINFO pErrInfo)
1456{
1457 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1458 AssertPtrReturn(pbBuf, VERR_INVALID_POINTER);
1459 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
1460
1461 RTJSONTOKENIZER Tokenizer;
1462 RTJSONREADERARGS Args;
1463 Args.cbData = cbBuf;
1464 Args.u.pbBuf = pbBuf;
1465
1466 int rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromBuf, &Args, pErrInfo);
1467 if (RT_SUCCESS(rc))
1468 {
1469 rc = rtJsonParse(&Tokenizer, phJsonVal);
1470 rtJsonTokenizerDestroy(&Tokenizer);
1471 }
1472
1473 return rc;
1474}
1475
1476RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo)
1477{
1478 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1479 AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
1480
1481 /** @todo r=bird: The rtJsonTokenizerParseFromString function does
1482 * strlen() on the whole pszStr for each read. For larger strings (
1483 * longer than sizeof(Tokenizer.achBuf)) it would be good to join
1484 * forces with RTJsonParseFromBuf. */
1485 RTJSONTOKENIZER Tokenizer;
1486 int rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromString, (void *)pszStr, pErrInfo);
1487 if (RT_SUCCESS(rc))
1488 {
1489 rc = rtJsonParse(&Tokenizer, phJsonVal);
1490 rtJsonTokenizerDestroy(&Tokenizer);
1491 }
1492
1493 return rc;
1494}
1495
1496RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo)
1497{
1498 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1499 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1500
1501 int rc = VINF_SUCCESS;
1502 RTJSONREADERARGS Args;
1503
1504 Args.cbData = 0;
1505 rc = RTStrmOpen(pszFilename, "r", &Args.u.hStream);
1506 if (RT_SUCCESS(rc))
1507 {
1508 RTJSONTOKENIZER Tokenizer;
1509
1510 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromFile, &Args, pErrInfo);
1511 if (RT_SUCCESS(rc))
1512 {
1513 rc = rtJsonParse(&Tokenizer, phJsonVal);
1514 rtJsonTokenizerDestroy(&Tokenizer);
1515 }
1516 RTStrmClose(Args.u.hStream);
1517 }
1518
1519 return rc;
1520}
1521
1522RTDECL(int) RTJsonParseFromVfsFile(PRTJSONVAL phJsonVal, RTVFSFILE hVfsFile, PRTERRINFO pErrInfo)
1523{
1524 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1525 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_POINTER);
1526
1527 int rc = VINF_SUCCESS;
1528 RTJSONREADERARGS Args;
1529 RTJSONTOKENIZER Tokenizer;
1530
1531 Args.cbData = 0;
1532 Args.u.hVfsFile = hVfsFile;
1533 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromVfsFile, &Args, pErrInfo);
1534 if (RT_SUCCESS(rc))
1535 {
1536 rc = rtJsonParse(&Tokenizer, phJsonVal);
1537 rtJsonTokenizerDestroy(&Tokenizer);
1538 }
1539
1540 return rc;
1541}
1542
1543RTDECL(uint32_t) RTJsonValueRetain(RTJSONVAL hJsonVal)
1544{
1545 PRTJSONVALINT pThis = hJsonVal;
1546 AssertPtrReturn(pThis, UINT32_MAX);
1547
1548 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1549 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1550 return cRefs;
1551}
1552
1553RTDECL(uint32_t) RTJsonValueRelease(RTJSONVAL hJsonVal)
1554{
1555 PRTJSONVALINT pThis = hJsonVal;
1556 if (pThis == NIL_RTJSONVAL)
1557 return 0;
1558 AssertPtrReturn(pThis, UINT32_MAX);
1559
1560 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1561 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1562 if (cRefs == 0)
1563 rtJsonValDestroy(pThis);
1564 return cRefs;
1565}
1566
1567RTDECL(RTJSONVALTYPE) RTJsonValueGetType(RTJSONVAL hJsonVal)
1568{
1569 PRTJSONVALINT pThis = hJsonVal;
1570 AssertPtrReturn(pThis, RTJSONVALTYPE_INVALID);
1571
1572 if (pThis == NIL_RTJSONVAL)
1573 return RTJSONVALTYPE_INVALID;
1574
1575 return pThis->enmType;
1576}
1577
1578
1579RTDECL(const char *) RTJsonValueTypeName(RTJSONVALTYPE enmType)
1580{
1581 switch (enmType)
1582 {
1583 case RTJSONVALTYPE_INVALID: return "invalid";
1584 case RTJSONVALTYPE_OBJECT: return "object";
1585 case RTJSONVALTYPE_ARRAY: return "array";
1586 case RTJSONVALTYPE_STRING: return "string";
1587 case RTJSONVALTYPE_INTEGER: return "integer";
1588 case RTJSONVALTYPE_NUMBER: return "number";
1589 case RTJSONVALTYPE_NULL: return "null";
1590 case RTJSONVALTYPE_TRUE: return "true";
1591 case RTJSONVALTYPE_FALSE: return "false";
1592 default: return "???";
1593 }
1594}
1595
1596
1597#define RTJSON_ASSERT_VALID_HANDLE_AND_TYPE_RETURN(pJson, enmExpectedType, ret) do { \
1598 AssertPtrReturn((pJson), (ret)); \
1599 AssertReturn((pJson) != NIL_RTJSONVAL, (ret)); \
1600 AssertReturn((pJson)->enmType == (enmExpectedType), (ret)); \
1601 } while (0)
1602
1603#define RTJSON_TYPECHECK_RETURN(pJson, enmExpectedType) do {\
1604 if ((pJson)->enmType == (enmExpectedType)) { /*likely*/ } \
1605 else { /*AssertFailed();*/ return VERR_JSON_VALUE_INVALID_TYPE; } \
1606 } while (0)
1607
1608
1609#define RTJSON_TYPECHECK_CONTAINER_RETURN(pJson) do { \
1610 if ( (pJson)->enmType == RTJSONVALTYPE_ARRAY \
1611 || (pJson)->enmType == RTJSONVALTYPE_OBJECT) \
1612 { /* likely */ } \
1613 else { /*AssertFailed();*/ return VERR_JSON_VALUE_INVALID_TYPE;} \
1614 } while (0)
1615
1616
1617RTDECL(const char *) RTJsonValueGetString(RTJSONVAL hJsonVal)
1618{
1619 PRTJSONVALINT pThis = hJsonVal;
1620 RTJSON_ASSERT_VALID_HANDLE_AND_TYPE_RETURN(pThis, RTJSONVALTYPE_STRING, NULL);
1621
1622 return pThis->Type.String.pszStr;
1623}
1624
1625
1626RTDECL(int) RTJsonValueQueryString(RTJSONVAL hJsonVal, const char **ppszStr)
1627{
1628 PRTJSONVALINT pThis = hJsonVal;
1629 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1630 AssertPtrReturn(ppszStr, VERR_INVALID_POINTER);
1631
1632 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_STRING);
1633 *ppszStr = pThis->Type.String.pszStr;
1634 return VINF_SUCCESS;
1635}
1636
1637RTDECL(int) RTJsonValueQueryInteger(RTJSONVAL hJsonVal, int64_t *pi64Num)
1638{
1639 PRTJSONVALINT pThis = hJsonVal;
1640 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1641 AssertPtrReturn(pi64Num, VERR_INVALID_POINTER);
1642
1643 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_INTEGER);
1644 *pi64Num = pThis->Type.Integer.i64Num;
1645 return VINF_SUCCESS;
1646}
1647
1648RTDECL(int) RTJsonValueQueryNumber(RTJSONVAL hJsonVal, double *prdNum)
1649{
1650 PRTJSONVALINT pThis = hJsonVal;
1651 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1652 AssertPtrReturn(prdNum, VERR_INVALID_POINTER);
1653
1654 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_NUMBER);
1655 *prdNum = pThis->Type.rdNum;
1656 return VINF_SUCCESS;
1657}
1658
1659RTDECL(int) RTJsonValueQueryByName(RTJSONVAL hJsonVal, const char *pszName, PRTJSONVAL phJsonVal)
1660{
1661 PRTJSONVALINT pThis = hJsonVal;
1662 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1663 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1664 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1665
1666 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_OBJECT);
1667
1668 int rc = VERR_NOT_FOUND;
1669 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
1670 {
1671 if (!RTStrCmp(pThis->Type.Object.papszNames[i], pszName))
1672 {
1673 RTJsonValueRetain(pThis->Type.Object.papValues[i]);
1674 *phJsonVal = pThis->Type.Object.papValues[i];
1675 rc = VINF_SUCCESS;
1676 break;
1677 }
1678 }
1679
1680 return rc;
1681}
1682
1683RTDECL(int) RTJsonValueQueryIntegerByName(RTJSONVAL hJsonVal, const char *pszName, int64_t *pi64Num)
1684{
1685 RTJSONVAL hJsonValNum = NIL_RTJSONVAL;
1686 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValNum);
1687 if (RT_SUCCESS(rc))
1688 {
1689 rc = RTJsonValueQueryInteger(hJsonValNum, pi64Num);
1690 RTJsonValueRelease(hJsonValNum);
1691 }
1692
1693 return rc;
1694}
1695
1696RTDECL(int) RTJsonValueQueryNumberByName(RTJSONVAL hJsonVal, const char *pszName, double *prdNum)
1697{
1698 RTJSONVAL hJsonValNum = NIL_RTJSONVAL;
1699 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValNum);
1700 if (RT_SUCCESS(rc))
1701 {
1702 rc = RTJsonValueQueryNumber(hJsonValNum, prdNum);
1703 RTJsonValueRelease(hJsonValNum);
1704 }
1705
1706 return rc;
1707}
1708
1709RTDECL(int) RTJsonValueQueryStringByName(RTJSONVAL hJsonVal, const char *pszName, char **ppszStr)
1710{
1711 RTJSONVAL hJsonValStr = NIL_RTJSONVAL;
1712 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValStr);
1713 if (RT_SUCCESS(rc))
1714 {
1715 const char *pszStr = NULL;
1716 rc = RTJsonValueQueryString(hJsonValStr, &pszStr);
1717 if (RT_SUCCESS(rc))
1718 {
1719 *ppszStr = RTStrDup(pszStr);
1720 if (!*ppszStr)
1721 rc = VERR_NO_STR_MEMORY;
1722 }
1723 RTJsonValueRelease(hJsonValStr);
1724 }
1725
1726 return rc;
1727}
1728
1729RTDECL(int) RTJsonValueQueryBooleanByName(RTJSONVAL hJsonVal, const char *pszName, bool *pfBoolean)
1730{
1731 AssertPtrReturn(pfBoolean, VERR_INVALID_POINTER);
1732
1733 RTJSONVAL hJsonValBool = NIL_RTJSONVAL;
1734 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValBool);
1735 if (RT_SUCCESS(rc))
1736 {
1737 RTJSONVALTYPE enmType = RTJsonValueGetType(hJsonValBool);
1738 if (enmType == RTJSONVALTYPE_TRUE)
1739 *pfBoolean = true;
1740 else if (enmType == RTJSONVALTYPE_FALSE)
1741 *pfBoolean = false;
1742 else
1743 rc = VERR_JSON_VALUE_INVALID_TYPE;
1744 RTJsonValueRelease(hJsonValBool);
1745 }
1746
1747 return rc;
1748}
1749
1750RTDECL(unsigned) RTJsonValueGetArraySize(RTJSONVAL hJsonVal)
1751{
1752 PRTJSONVALINT pThis = hJsonVal;
1753 RTJSON_ASSERT_VALID_HANDLE_AND_TYPE_RETURN(pThis, RTJSONVALTYPE_ARRAY, 0);
1754
1755 return pThis->Type.Array.cItems;
1756}
1757
1758RTDECL(int) RTJsonValueQueryArraySize(RTJSONVAL hJsonVal, unsigned *pcItems)
1759{
1760 PRTJSONVALINT pThis = hJsonVal;
1761 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1762 AssertPtrReturn(pcItems, VERR_INVALID_POINTER);
1763
1764 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
1765 *pcItems = pThis->Type.Array.cItems;
1766 return VINF_SUCCESS;
1767}
1768
1769RTDECL(int) RTJsonValueQueryByIndex(RTJSONVAL hJsonVal, unsigned idx, PRTJSONVAL phJsonVal)
1770{
1771 PRTJSONVALINT pThis = hJsonVal;
1772 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1773 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1774
1775 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
1776 if (RT_UNLIKELY(idx >= pThis->Type.Array.cItems))
1777 return VERR_OUT_OF_RANGE;
1778
1779 RTJsonValueRetain(pThis->Type.Array.papItems[idx]);
1780 *phJsonVal = pThis->Type.Array.papItems[idx];
1781 return VINF_SUCCESS;
1782}
1783
1784static int rtJsonIteratorBeginWorker(PRTJSONVALINT pThis, PRTJSONIT phJsonIt)
1785{
1786 PRTJSONITINT pIt = (PRTJSONITINT)RTMemTmpAllocZ(sizeof(RTJSONITINT));
1787 if (pIt)
1788 {
1789 RTJsonValueRetain(pThis);
1790 pIt->pJsonVal = pThis;
1791 pIt->idxCur = 0;
1792
1793 *phJsonIt = pIt;
1794 return VINF_SUCCESS;
1795 }
1796 return VERR_NO_MEMORY;
1797}
1798
1799RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1800{
1801 PRTJSONVALINT pThis = hJsonVal;
1802 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1803 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1804 RTJSON_TYPECHECK_CONTAINER_RETURN(pThis);
1805
1806 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
1807}
1808
1809RTDECL(int) RTJsonIteratorBeginArray(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1810{
1811 PRTJSONVALINT pThis = hJsonVal;
1812 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1813 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1814 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
1815
1816 if (pThis->Type.Array.cItems > 0)
1817 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
1818 return VERR_JSON_IS_EMPTY;
1819}
1820
1821RTDECL(int) RTJsonIteratorBeginObject(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1822{
1823 PRTJSONVALINT pThis = hJsonVal;
1824 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1825 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1826 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_OBJECT);
1827
1828 if (pThis->Type.Object.cMembers > 0)
1829 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
1830 return VERR_JSON_IS_EMPTY;
1831}
1832
1833RTDECL(int) RTJsonIteratorQueryValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName)
1834{
1835 PRTJSONITINT pIt = hJsonIt;
1836 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
1837 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1838 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1839
1840 int rc = VINF_SUCCESS;
1841 PRTJSONVALINT pThis = pIt->pJsonVal;
1842 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1843 {
1844 if (pIt->idxCur < pThis->Type.Array.cItems)
1845 {
1846 if (ppszName)
1847 *ppszName = NULL;
1848
1849 RTJsonValueRetain(pThis->Type.Array.papItems[pIt->idxCur]);
1850 *phJsonVal = pThis->Type.Array.papItems[pIt->idxCur];
1851 }
1852 else
1853 rc = VERR_JSON_ITERATOR_END;
1854 }
1855 else
1856 {
1857 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1858
1859 if (pIt->idxCur < pThis->Type.Object.cMembers)
1860 {
1861 if (ppszName)
1862 *ppszName = pThis->Type.Object.papszNames[pIt->idxCur];
1863
1864 RTJsonValueRetain(pThis->Type.Object.papValues[pIt->idxCur]);
1865 *phJsonVal = pThis->Type.Object.papValues[pIt->idxCur];
1866 }
1867 else
1868 rc = VERR_JSON_ITERATOR_END;
1869 }
1870
1871 return rc;
1872}
1873
1874RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt)
1875{
1876 PRTJSONITINT pIt = hJsonIt;
1877 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
1878 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1879
1880 int rc = VINF_SUCCESS;
1881 PRTJSONVALINT pThis = pIt->pJsonVal;
1882 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1883 {
1884 if (pIt->idxCur < pThis->Type.Array.cItems)
1885 pIt->idxCur++;
1886
1887 if (pIt->idxCur == pThis->Type.Object.cMembers)
1888 rc = VERR_JSON_ITERATOR_END;
1889 }
1890 else
1891 {
1892 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1893
1894 if (pIt->idxCur < pThis->Type.Object.cMembers)
1895 pIt->idxCur++;
1896
1897 if (pIt->idxCur == pThis->Type.Object.cMembers)
1898 rc = VERR_JSON_ITERATOR_END;
1899 }
1900
1901 return rc;
1902}
1903
1904RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt)
1905{
1906 PRTJSONITINT pThis = hJsonIt;
1907 AssertPtrReturnVoid(pThis);
1908
1909 if (pThis == NIL_RTJSONIT)
1910 return;
1911
1912 RTJsonValueRelease(pThis->pJsonVal);
1913 RTMemTmpFree(pThis);
1914}
Note: See TracBrowser for help on using the repository browser.

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