VirtualBox

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

Last change on this file since 87203 was 85121, checked in by vboxsync, 4 years ago

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

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