VirtualBox

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

Last change on this file since 74179 was 74179, checked in by vboxsync, 6 years ago

IPRT/json: Added \uXXXX and surrogate pair tests. Refuse to decode U+0000, U+FFFE and U+FFFF. bugref:9167

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