VirtualBox

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

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

IPRT/json: Implemented handling of \uXXXX sequences. Reduced heap calls during string decoding. bugref:9167

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.7 KB
Line 
1/* $Id: json.cpp 74173 2018-09-10 09:39:10Z 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 ch = rtJsonTokenizerGetCh(pTokenizer);
698 if (ch == '\\')
699 rtJsonTokenizerSkipCh(pTokenizer);
700 else
701 rc = VERR_JSON_MISSING_SURROGATE_PAIR;
702 ch = rtJsonTokenizerGetCh(pTokenizer);
703 if (ch == 'u')
704 rtJsonTokenizerSkipCh(pTokenizer);
705 else
706 rc = VERR_JSON_MISSING_SURROGATE_PAIR;
707 chX1 = rtJsonTokenizerGetCh(pTokenizer);
708 if (RT_C_IS_XDIGIT(chX1))
709 rtJsonTokenizerSkipCh(pTokenizer);
710 else if (RT_SUCCESS_NP(rc))
711 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
712 chX2 = rtJsonTokenizerGetCh(pTokenizer);
713 if (RT_C_IS_XDIGIT(chX2))
714 rtJsonTokenizerSkipCh(pTokenizer);
715 else if (RT_SUCCESS_NP(rc))
716 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
717 chX3 = rtJsonTokenizerGetCh(pTokenizer);
718 if (RT_C_IS_XDIGIT(chX3))
719 rtJsonTokenizerSkipCh(pTokenizer);
720 else if (RT_SUCCESS_NP(rc))
721 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
722 chX4 = rtJsonTokenizerGetCh(pTokenizer);
723 if (RT_C_IS_XDIGIT(chX4))
724 rtJsonTokenizerSkipCh(pTokenizer);
725 else if (RT_SUCCESS_NP(rc))
726 rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
727 if (RT_SUCCESS(rc))
728 {
729 RTUTF16 wc2 = ((RTUTF16)(chX1 <= '9' ? chX1 - '0' : (chX1 & 7) + 9) << 12)
730 | ((RTUTF16)(chX2 <= '9' ? chX2 - '0' : (chX2 & 7) + 9) << 8)
731 | ((RTUTF16)(chX3 <= '9' ? chX3 - '0' : (chX3 & 7) + 9) << 4)
732 | ((RTUTF16)(chX4 <= '9' ? chX4 - '0' : (chX4 & 7) + 9));
733 if (RTUtf16IsLowSurrogate(wc2))
734 uc = 0x10000 + (((uc & 0x3ff) << 10) | (wc2 & 0x3ff));
735 else
736 rc = VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE;
737 }
738 }
739 else
740 rc = VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE;
741 if (RT_SUCCESS(rc))
742 {
743 Assert(cchStr + RTStrCpSize(uc) < cchStrMax);
744 char *pszNext = RTStrPutCp(&pszDecoded[cchStr], uc);
745 Assert((size_t)(pszNext - &pszDecoded[cchStr]) == RTStrCpSize(uc));
746 cchStr += pszNext - &pszDecoded[cchStr];
747 break;
748 }
749 }
750 }
751 }
752 }
753 RTStrFree(pszDecoded);
754 if (rc == VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE)
755 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Invalid \u escape sequence (line %zu col %zu)",
756 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
757 else if (rc == VERR_JSON_MISSING_SURROGATE_PAIR)
758 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Missing UTF-16 surrogate pair (line %zu col %zu)",
759 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
760 else
761 rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Invalid UTF-16 surrogate pair (line %zu col %zu)",
762 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
763 return rc;
764 }
765
766 default:
767 RTStrFree(pszDecoded);
768 return RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "bad escape sequence (line %zu col %zu)",
769 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
770 }
771 }
772
773
774 if (cchStr < cchStrMax - 4)
775 { /* likely */ }
776 else
777 {
778 /* Increase string space. */
779 size_t cchStrMaxNew = cchStrMax < _4K ? cchStrMax * 2 : cchStrMax + _4K;
780 int rc = RTStrRealloc(&pszDecoded, cchStrMaxNew);
781 if (RT_SUCCESS(rc))
782 cchStrMax = cchStrMaxNew;
783 else
784 {
785 RTStrFree(pszDecoded);
786 return rc;
787 }
788 }
789 ch = rtJsonTokenizerGetCh(pTokenizer);
790 }
791
792 if (ch == '\"')
793 rtJsonTokenizerSkipCh(pTokenizer); /* Skip closing " */
794
795 Assert(cchStr < cchStrMax);
796 pszDecoded[cchStr] = '\0';
797 if (cchStrMax - cchStr >= cchStrMax / 2)
798 RTStrRealloc(&pszDecoded, cchStr + 1);
799 pToken->Class.String.pszStr = pszDecoded;
800
801 pToken->Pos.iChEnd = pTokenizer->Pos.iChEnd;
802 return VINF_SUCCESS;
803}
804
805/**
806 * Get the end of stream token.
807 *
808 * @returns IPRT status code.
809 * @param pTokenizer The tokenizer state.
810 * @param pToken The uninitialized token.
811 */
812static int rtJsonTokenizerGetEos(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
813{
814 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\0');
815
816 pToken->enmClass = RTJSONTOKENCLASS_EOS;
817 pToken->Pos = pTokenizer->Pos;
818 return VINF_SUCCESS;
819}
820
821/**
822 * Read the next token from the tokenizer stream.
823 *
824 * @returns IPRT status code.
825 * @param pTokenizer The tokenizer to read from.
826 * @param pToken Uninitialized token to fill the token data into.
827 */
828static int rtJsonTokenizerReadNextToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
829{
830 int rc = VINF_SUCCESS;
831
832 /* Skip all eventually existing whitespace and newlines first. */
833 rtJsonTokenizerSkipWhitespace(pTokenizer);
834
835 char ch = rtJsonTokenizerGetCh(pTokenizer);
836 if (RT_C_IS_ALPHA(ch))
837 rc = rtJsonTokenizerGetLiteral(pTokenizer, pToken);
838 else if (RT_C_IS_DIGIT(ch) || ch == '-')
839 rc = rtJsonTokenizerGetNumber(pTokenizer, pToken);
840 else if (ch == '\"')
841 rc = rtJsonTokenizerGetString(pTokenizer, pToken);
842 else if (ch == '\0')
843 rc = rtJsonTokenizerGetEos(pTokenizer, pToken);
844 else if (ch == '{')
845 {
846 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_OBJECT;
847 rtJsonTokenizerSkipCh(pTokenizer);
848 }
849 else if (ch == '}')
850 {
851 pToken->enmClass = RTJSONTOKENCLASS_END_OBJECT;
852 rtJsonTokenizerSkipCh(pTokenizer);
853 }
854 else if (ch == '[')
855 {
856 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_ARRAY;
857 rtJsonTokenizerSkipCh(pTokenizer);
858 }
859 else if (ch == ']')
860 {
861 pToken->enmClass = RTJSONTOKENCLASS_END_ARRAY;
862 rtJsonTokenizerSkipCh(pTokenizer);
863 }
864 else if (ch == ':')
865 {
866 pToken->enmClass = RTJSONTOKENCLASS_NAME_SEPARATOR;
867 rtJsonTokenizerSkipCh(pTokenizer);
868 }
869 else if (ch == ',')
870 {
871 pToken->enmClass = RTJSONTOKENCLASS_VALUE_SEPARATOR;
872 rtJsonTokenizerSkipCh(pTokenizer);
873 }
874 else
875 {
876 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
877 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "bad token '%c' (line %zu col %zu)",
878 ch, pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
879 }
880
881 if (RT_FAILURE(rc))
882 pTokenizer->rcTok = rc;
883
884 return rc;
885}
886
887/**
888 * Create a new tokenizer.
889 *
890 * @returns IPRT status code.
891 * @param pTokenizer The tokenizer state to initialize.
892 * @param pfnRead Read callback for the input stream.
893 * @param pvUser Opaque user data to pass to the callback.
894 * @param pErrInfo Where to return extended error info.
895 */
896static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, PFNRTJSONTOKENIZERREAD pfnRead, void *pvUser, PRTERRINFO pErrInfo)
897{
898 pTokenizer->pfnRead = pfnRead;
899 pTokenizer->pvUser = pvUser;
900 pTokenizer->offInput = 0;
901 pTokenizer->cbBuf = 0;
902 pTokenizer->offBuf = 0;
903 pTokenizer->Pos.iLine = 1;
904 pTokenizer->Pos.iChStart = 1;
905 pTokenizer->Pos.iChEnd = 1;
906 pTokenizer->pTokenCurr = &pTokenizer->Token1;
907 pTokenizer->pTokenNext = &pTokenizer->Token2;
908 pTokenizer->rcTok = VINF_SUCCESS;
909 pTokenizer->pErrInfo = pErrInfo;
910
911 RT_ZERO(pTokenizer->achBuf);
912
913 /* Fill the input buffer. */
914 int rc = rtJsonTokenizerRead(pTokenizer);
915
916 /* Fill the tokenizer with two first tokens. */
917 if (RT_SUCCESS(rc))
918 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr);
919 if (RT_SUCCESS(rc))
920 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
921
922 return rc;
923}
924
925/**
926 * Destroys a given tokenizer state.
927 *
928 * @returns nothing.
929 * @param pTokenizer The tokenizer to destroy.
930 */
931static void rtJsonTokenizerDestroy(PRTJSONTOKENIZER pTokenizer)
932{
933 RT_NOREF_PV(pTokenizer);
934}
935
936/**
937 * Get the current token in the input stream.
938 *
939 * @returns Pointer to the next token in the stream.
940 * @param pTokenizer The tokenizer state.
941 * @param ppToken Where to store the pointer to the current token on success.
942 */
943DECLINLINE(int) rtJsonTokenizerGetToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN *ppToken)
944{
945 if (RT_SUCCESS(pTokenizer->rcTok))
946 {
947 *ppToken = pTokenizer->pTokenCurr;
948 return VINF_SUCCESS;
949 }
950
951 return pTokenizer->rcTok;
952}
953
954/**
955 * Consume the current token advancing to the next in the stream.
956 *
957 * @returns nothing.
958 * @param pTokenizer The tokenizer state.
959 */
960static void rtJsonTokenizerConsume(PRTJSONTOKENIZER pTokenizer)
961{
962 PRTJSONTOKEN pTokenTmp = pTokenizer->pTokenCurr;
963
964 /* Switch next token to current token and read in the next token. */
965 pTokenizer->pTokenCurr = pTokenizer->pTokenNext;
966 pTokenizer->pTokenNext = pTokenTmp;
967 rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
968}
969
970/**
971 * Consumes the current token if it matches the given class returning an indicator.
972 *
973 * @returns true if the class matched and the token was consumed.
974 * @retval false otherwise.
975 * @param pTokenizer The tokenizer state.
976 * @param enmClass The token class to match against.
977 */
978static bool rtJsonTokenizerConsumeIfMatched(PRTJSONTOKENIZER pTokenizer, RTJSONTOKENCLASS enmClass)
979{
980 PRTJSONTOKEN pToken = NULL;
981 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
982 if (RT_SUCCESS(rc))
983 {
984 if (pToken->enmClass == enmClass)
985 {
986 rtJsonTokenizerConsume(pTokenizer);
987 return true;
988 }
989 }
990
991 return false;
992}
993
994/**
995 * Destroys a given JSON value releasing the reference to all child values.
996 *
997 * @returns nothing.
998 * @param pThis The JSON value to destroy.
999 */
1000static void rtJsonValDestroy(PRTJSONVALINT pThis)
1001{
1002 switch (pThis->enmType)
1003 {
1004 case RTJSONVALTYPE_OBJECT:
1005 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
1006 {
1007 RTStrFree(pThis->Type.Object.papszNames[i]);
1008 RTJsonValueRelease(pThis->Type.Object.papValues[i]);
1009 }
1010 RTMemFree(pThis->Type.Object.papszNames);
1011 RTMemFree(pThis->Type.Object.papValues);
1012 break;
1013 case RTJSONVALTYPE_ARRAY:
1014 for (unsigned i = 0; i < pThis->Type.Array.cItems; i++)
1015 RTJsonValueRelease(pThis->Type.Array.papItems[i]);
1016 RTMemFree(pThis->Type.Array.papItems);
1017 break;
1018 case RTJSONVALTYPE_STRING:
1019 RTStrFree(pThis->Type.String.pszStr);
1020 break;
1021 case RTJSONVALTYPE_INTEGER:
1022 case RTJSONVALTYPE_NUMBER:
1023 case RTJSONVALTYPE_NULL:
1024 case RTJSONVALTYPE_TRUE:
1025 case RTJSONVALTYPE_FALSE:
1026 /* nothing to do. */
1027 break;
1028 default:
1029 AssertMsgFailed(("Invalid JSON value type: %u\n", pThis->enmType));
1030 }
1031 RTMemFree(pThis);
1032}
1033
1034/**
1035 * Creates a new JSON value with the given type.
1036 *
1037 * @returns Pointer to JSON value on success, NULL if out of memory.
1038 * @param enmType The JSON value type.
1039 */
1040static PRTJSONVALINT rtJsonValueCreate(RTJSONVALTYPE enmType)
1041{
1042 PRTJSONVALINT pThis = (PRTJSONVALINT)RTMemAllocZ(sizeof(RTJSONVALINT));
1043 if (RT_LIKELY(pThis))
1044 {
1045 pThis->enmType = enmType;
1046 pThis->cRefs = 1;
1047 }
1048
1049 return pThis;
1050}
1051
1052/**
1053 * Parses an JSON array.
1054 *
1055 * @returns IPRT status code.
1056 * @param pTokenizer The tokenizer to use.
1057 * @param pJsonVal The JSON array value to fill in.
1058 */
1059static int rtJsonParseArray(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal)
1060{
1061 int rc = VINF_SUCCESS;
1062 PRTJSONTOKEN pToken = NULL;
1063 uint32_t cItems = 0;
1064 uint32_t cItemsMax = 0;
1065 PRTJSONVALINT *papItems = NULL;
1066
1067 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1068 while ( RT_SUCCESS(rc)
1069 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY
1070 && pToken->enmClass != RTJSONTOKENCLASS_EOS)
1071 {
1072 PRTJSONVALINT pVal = NULL;
1073 rc = rtJsonParseValue(pTokenizer, pToken, &pVal);
1074 if (RT_SUCCESS(rc))
1075 {
1076 if (cItems == cItemsMax)
1077 {
1078 cItemsMax += 10;
1079 PRTJSONVALINT *papItemsNew = (PRTJSONVALINT *)RTMemRealloc(papItems, cItemsMax * sizeof(PRTJSONVALINT));
1080 if (RT_UNLIKELY(!papItemsNew))
1081 {
1082 rc = VERR_NO_MEMORY;
1083 break;
1084 }
1085 papItems = papItemsNew;
1086 }
1087
1088 Assert(cItems < cItemsMax);
1089 papItems[cItems] = pVal;
1090 cItems++;
1091 }
1092
1093 /* Skip value separator and continue with next token. */
1094 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
1095 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1096
1097 if ( RT_SUCCESS(rc)
1098 && !fSkippedSep
1099 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY)
1100 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of array (#1) (line %zu col %zu)",
1101 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1102 }
1103
1104 if (RT_SUCCESS(rc))
1105 {
1106 if (pToken->enmClass == RTJSONTOKENCLASS_END_ARRAY)
1107 {
1108 rtJsonTokenizerConsume(pTokenizer);
1109 pJsonVal->Type.Array.cItems = cItems;
1110 pJsonVal->Type.Array.papItems = papItems;
1111 }
1112 else
1113 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of array (#2) (line %zu col %zu)",
1114 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1115 }
1116
1117 if (RT_FAILURE(rc))
1118 {
1119 for (uint32_t i = 0; i < cItems; i++)
1120 RTJsonValueRelease(papItems[i]);
1121 RTMemFree(papItems);
1122 }
1123
1124 return rc;
1125}
1126
1127/**
1128 * Parses an JSON object.
1129 *
1130 * @returns IPRT status code.
1131 * @param pTokenizer The tokenizer to use.
1132 * @param pJsonVal The JSON object value to fill in.
1133 */
1134static int rtJsonParseObject(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal)
1135{
1136 int rc = VINF_SUCCESS;
1137 PRTJSONTOKEN pToken = NULL;
1138 uint32_t cMembers = 0;
1139 uint32_t cMembersMax = 0;
1140 PRTJSONVALINT *papValues = NULL;
1141 char **papszNames = NULL;
1142
1143 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1144 while ( RT_SUCCESS(rc)
1145 && pToken->enmClass == RTJSONTOKENCLASS_STRING)
1146 {
1147 char *pszName = pToken->Class.String.pszStr; /* We can consume this string as it was allocated. */
1148
1149 rtJsonTokenizerConsume(pTokenizer);
1150 if (rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_NAME_SEPARATOR))
1151 {
1152 PRTJSONVALINT pVal = NULL;
1153 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1154 if (RT_SUCCESS(rc))
1155 rc = rtJsonParseValue(pTokenizer, pToken, &pVal);
1156 if (RT_SUCCESS(rc))
1157 {
1158 if (cMembers == cMembersMax)
1159 {
1160 cMembersMax += 10;
1161 PRTJSONVALINT *papValuesNew = (PRTJSONVALINT *)RTMemRealloc(papValues, cMembersMax * sizeof(PRTJSONVALINT));
1162 char **papszNamesNew = (char **)RTMemRealloc(papszNames, cMembersMax * sizeof(char *));
1163 if (RT_UNLIKELY(!papValuesNew || !papszNamesNew))
1164 {
1165 if (papValuesNew)
1166 RTMemFree(papValuesNew);
1167 if (papszNamesNew)
1168 RTMemFree(papszNamesNew);
1169 rc = VERR_NO_MEMORY;
1170 break;
1171 }
1172
1173 papValues = papValuesNew;
1174 papszNames = papszNamesNew;
1175 }
1176
1177 Assert(cMembers < cMembersMax);
1178 papszNames[cMembers] = pszName;
1179 papValues[cMembers] = pVal;
1180 cMembers++;
1181
1182 /* Skip value separator and continue with next token. */
1183 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
1184 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1185
1186 if ( RT_SUCCESS(rc)
1187 && !fSkippedSep
1188 && pToken->enmClass != RTJSONTOKENCLASS_END_OBJECT)
1189 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of object (#1) (line %zu col %zu)",
1190 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1191 }
1192 }
1193 else
1194 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected name separator (line %zu col %zu)",
1195 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1196 }
1197
1198 if (RT_SUCCESS(rc))
1199 {
1200 if (pToken->enmClass == RTJSONTOKENCLASS_END_OBJECT)
1201 {
1202 rtJsonTokenizerConsume(pTokenizer);
1203 pJsonVal->Type.Object.cMembers = cMembers;
1204 pJsonVal->Type.Object.papValues = papValues;
1205 pJsonVal->Type.Object.papszNames = papszNames;
1206 }
1207 else
1208 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of object (#2) (line %zu col %zu)",
1209 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1210 }
1211
1212 if (RT_FAILURE(rc))
1213 {
1214 for (uint32_t i = 0; i < cMembers; i++)
1215 {
1216 RTJsonValueRelease(papValues[i]);
1217 RTStrFree(papszNames[i]);
1218 }
1219 RTMemFree(papValues);
1220 RTMemFree(papszNames);
1221 }
1222
1223 return rc;
1224}
1225
1226/**
1227 * Parses a single JSON value and returns it on success.
1228 *
1229 * @returns IPRT status code.
1230 * @param pTokenizer The tokenizer to use.
1231 * @param pToken The token to parse.
1232 * @param ppJsonVal Where to store the pointer to the JSON value on success.
1233 */
1234static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken, PRTJSONVALINT *ppJsonVal)
1235{
1236 int rc = VINF_SUCCESS;
1237 PRTJSONVALINT pVal = NULL;
1238
1239 switch (pToken->enmClass)
1240 {
1241 case RTJSONTOKENCLASS_BEGIN_ARRAY:
1242 rtJsonTokenizerConsume(pTokenizer);
1243 pVal = rtJsonValueCreate(RTJSONVALTYPE_ARRAY);
1244 if (RT_LIKELY(pVal))
1245 rc = rtJsonParseArray(pTokenizer, pVal);
1246 break;
1247 case RTJSONTOKENCLASS_BEGIN_OBJECT:
1248 rtJsonTokenizerConsume(pTokenizer);
1249 pVal = rtJsonValueCreate(RTJSONVALTYPE_OBJECT);
1250 if (RT_LIKELY(pVal))
1251 rc = rtJsonParseObject(pTokenizer, pVal);
1252 break;
1253 case RTJSONTOKENCLASS_STRING:
1254 pVal = rtJsonValueCreate(RTJSONVALTYPE_STRING);
1255 if (RT_LIKELY(pVal))
1256 pVal->Type.String.pszStr = pToken->Class.String.pszStr;
1257 rtJsonTokenizerConsume(pTokenizer);
1258 break;
1259 case RTJSONTOKENCLASS_INTEGER:
1260 pVal = rtJsonValueCreate(RTJSONVALTYPE_INTEGER);
1261 if (RT_LIKELY(pVal))
1262 pVal->Type.Integer.i64Num = pToken->Class.Integer.i64Num;
1263 rtJsonTokenizerConsume(pTokenizer);
1264 break;
1265 case RTJSONTOKENCLASS_NUMBER:
1266 pVal = rtJsonValueCreate(RTJSONVALTYPE_NUMBER);
1267 if (RT_LIKELY(pVal))
1268 pVal->Type.rdNum = pToken->Class.rdNum;
1269 rtJsonTokenizerConsume(pTokenizer);
1270 break;
1271 case RTJSONTOKENCLASS_NULL:
1272 rtJsonTokenizerConsume(pTokenizer);
1273 pVal = rtJsonValueCreate(RTJSONVALTYPE_NULL);
1274 break;
1275 case RTJSONTOKENCLASS_FALSE:
1276 rtJsonTokenizerConsume(pTokenizer);
1277 pVal = rtJsonValueCreate(RTJSONVALTYPE_FALSE);
1278 break;
1279 case RTJSONTOKENCLASS_TRUE:
1280 rtJsonTokenizerConsume(pTokenizer);
1281 pVal = rtJsonValueCreate(RTJSONVALTYPE_TRUE);
1282 break;
1283
1284 case RTJSONTOKENCLASS_INVALID:
1285 Assert(!pTokenizer->pErrInfo || RTErrInfoIsSet(pTokenizer->pErrInfo));
1286 rc = VERR_JSON_MALFORMED;
1287 break;
1288 case RTJSONTOKENCLASS_END_ARRAY:
1289 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected '}' (line %zu col %zu)",
1290 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1291 break;
1292 case RTJSONTOKENCLASS_END_OBJECT:
1293 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected ']' (line %zu col %zu)",
1294 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1295 break;
1296 case RTJSONTOKENCLASS_NAME_SEPARATOR:
1297 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected ':' (line %zu col %zu)",
1298 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1299 break;
1300 case RTJSONTOKENCLASS_VALUE_SEPARATOR:
1301 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "unexpected ',' (line %zu col %zu)",
1302 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1303 break;
1304 case RTJSONTOKENCLASS_EOS:
1305 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "expected end of object (#1) (line %zu col %zu)",
1306 pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1307 break;
1308 default:
1309 rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "Unexpected token class %d (line %zu col %zu)",
1310 pToken->enmClass, pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
1311 break;
1312 }
1313
1314 if (RT_SUCCESS(rc))
1315 {
1316 if (pVal)
1317 *ppJsonVal = pVal;
1318 else
1319 rc = VERR_NO_MEMORY;
1320 }
1321 else if (pVal)
1322 rtJsonValDestroy(pVal);
1323
1324 return rc;
1325}
1326
1327/**
1328 * Entry point to parse a JSON document.
1329 *
1330 * @returns IPRT status code.
1331 * @param pTokenizer The tokenizer state.
1332 * @param ppJsonVal Where to store the root JSON value on success.
1333 */
1334static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal)
1335{
1336 PRTJSONTOKEN pToken = NULL;
1337 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1338 if (RT_SUCCESS(rc))
1339 rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal);
1340
1341 return rc;
1342}
1343
1344/**
1345 * Read callback for RTJsonParseFromBuf().
1346 */
1347static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, size_t offInput,
1348 void *pvBuf, size_t cbBuf,
1349 size_t *pcbRead)
1350{
1351 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1352 size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0;
1353
1354 if (cbLeft)
1355 memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf));
1356
1357 *pcbRead = RT_MIN(cbLeft, cbBuf);
1358
1359 return VINF_SUCCESS;
1360}
1361
1362/**
1363 * Read callback for RTJsonParseFromString().
1364 */
1365static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, size_t offInput,
1366 void *pvBuf, size_t cbBuf,
1367 size_t *pcbRead)
1368{
1369 const char *pszStr = (const char *)pvUser;
1370 size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */
1371 size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0;
1372
1373 if (cbLeft)
1374 memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf));
1375
1376 *pcbRead = RT_MIN(cbLeft, cbBuf);
1377
1378 return VINF_SUCCESS;
1379}
1380
1381/**
1382 * Read callback for RTJsonParseFromFile().
1383 */
1384static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, size_t offInput,
1385 void *pvBuf, size_t cbBuf,
1386 size_t *pcbRead)
1387{
1388 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1389
1390 RT_NOREF_PV(offInput);
1391
1392 size_t cbRead = 0;
1393 int rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead);
1394 if (RT_SUCCESS(rc))
1395 *pcbRead = cbRead;
1396
1397 return rc;
1398}
1399
1400RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf, PRTERRINFO pErrInfo)
1401{
1402 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1403 AssertPtrReturn(pbBuf, VERR_INVALID_POINTER);
1404 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
1405
1406 RTJSONTOKENIZER Tokenizer;
1407 RTJSONREADERARGS Args;
1408 Args.cbData = cbBuf;
1409 Args.u.pbBuf = pbBuf;
1410
1411 int rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromBuf, &Args, pErrInfo);
1412 if (RT_SUCCESS(rc))
1413 {
1414 rc = rtJsonParse(&Tokenizer, phJsonVal);
1415 rtJsonTokenizerDestroy(&Tokenizer);
1416 }
1417
1418 return rc;
1419}
1420
1421RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo)
1422{
1423 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1424 AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
1425
1426 /** @todo r=bird: The rtJsonTokenizerParseFromString function does
1427 * strlen() on the whole pszStr for each read. For larger strings (
1428 * longer than sizeof(Tokenizer.achBuf)) it would be good to join
1429 * forces with RTJsonParseFromBuf. */
1430 RTJSONTOKENIZER Tokenizer;
1431 int rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromString, (void *)pszStr, pErrInfo);
1432 if (RT_SUCCESS(rc))
1433 {
1434 rc = rtJsonParse(&Tokenizer, phJsonVal);
1435 rtJsonTokenizerDestroy(&Tokenizer);
1436 }
1437
1438 return rc;
1439}
1440
1441RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo)
1442{
1443 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1444 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1445
1446 int rc = VINF_SUCCESS;
1447 RTJSONREADERARGS Args;
1448
1449 Args.cbData = 0;
1450 rc = RTStrmOpen(pszFilename, "r", &Args.u.hStream);
1451 if (RT_SUCCESS(rc))
1452 {
1453 RTJSONTOKENIZER Tokenizer;
1454
1455 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromFile, &Args, pErrInfo);
1456 if (RT_SUCCESS(rc))
1457 {
1458 rc = rtJsonParse(&Tokenizer, phJsonVal);
1459 rtJsonTokenizerDestroy(&Tokenizer);
1460 }
1461 RTStrmClose(Args.u.hStream);
1462 }
1463
1464 return rc;
1465}
1466
1467RTDECL(uint32_t) RTJsonValueRetain(RTJSONVAL hJsonVal)
1468{
1469 PRTJSONVALINT pThis = hJsonVal;
1470 AssertPtrReturn(pThis, UINT32_MAX);
1471
1472 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1473 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1474 return cRefs;
1475}
1476
1477RTDECL(uint32_t) RTJsonValueRelease(RTJSONVAL hJsonVal)
1478{
1479 PRTJSONVALINT pThis = hJsonVal;
1480 if (pThis == NIL_RTJSONVAL)
1481 return 0;
1482 AssertPtrReturn(pThis, UINT32_MAX);
1483
1484 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1485 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1486 if (cRefs == 0)
1487 rtJsonValDestroy(pThis);
1488 return cRefs;
1489}
1490
1491RTDECL(RTJSONVALTYPE) RTJsonValueGetType(RTJSONVAL hJsonVal)
1492{
1493 PRTJSONVALINT pThis = hJsonVal;
1494 AssertPtrReturn(pThis, RTJSONVALTYPE_INVALID);
1495
1496 if (pThis == NIL_RTJSONVAL)
1497 return RTJSONVALTYPE_INVALID;
1498
1499 return pThis->enmType;
1500}
1501
1502
1503RTDECL(const char *) RTJsonValueTypeName(RTJSONVALTYPE enmType)
1504{
1505 switch (enmType)
1506 {
1507 case RTJSONVALTYPE_INVALID: return "invalid";
1508 case RTJSONVALTYPE_OBJECT: return "object";
1509 case RTJSONVALTYPE_ARRAY: return "array";
1510 case RTJSONVALTYPE_STRING: return "string";
1511 case RTJSONVALTYPE_INTEGER: return "integer";
1512 case RTJSONVALTYPE_NUMBER: return "number";
1513 case RTJSONVALTYPE_NULL: return "null";
1514 case RTJSONVALTYPE_TRUE: return "true";
1515 case RTJSONVALTYPE_FALSE: return "false";
1516 default: return "???";
1517 }
1518}
1519
1520
1521#define RTJSON_ASSERT_VALID_HANDLE_AND_TYPE_RETURN(pJson, enmExpectedType, ret) do { \
1522 AssertPtrReturn((pJson), (ret)); \
1523 AssertReturn((pJson) != NIL_RTJSONVAL, (ret)); \
1524 AssertReturn((pJson)->enmType == (enmExpectedType), (ret)); \
1525 } while (0)
1526
1527#define RTJSON_TYPECHECK_RETURN(pJson, enmExpectedType) do {\
1528 if ((pJson)->enmType == (enmExpectedType)) { /*likely*/ } \
1529 else { /*AssertFailed();*/ return VERR_JSON_VALUE_INVALID_TYPE; } \
1530 } while (0)
1531
1532
1533#define RTJSON_TYPECHECK_CONTAINER_RETURN(pJson) do { \
1534 if ( (pJson)->enmType == RTJSONVALTYPE_ARRAY \
1535 || (pJson)->enmType == RTJSONVALTYPE_OBJECT) \
1536 { /* likely */ } \
1537 else { /*AssertFailed();*/ return VERR_JSON_VALUE_INVALID_TYPE;} \
1538 } while (0)
1539
1540
1541RTDECL(const char *) RTJsonValueGetString(RTJSONVAL hJsonVal)
1542{
1543 PRTJSONVALINT pThis = hJsonVal;
1544 RTJSON_ASSERT_VALID_HANDLE_AND_TYPE_RETURN(pThis, RTJSONVALTYPE_STRING, NULL);
1545
1546 return pThis->Type.String.pszStr;
1547}
1548
1549
1550RTDECL(int) RTJsonValueQueryString(RTJSONVAL hJsonVal, const char **ppszStr)
1551{
1552 PRTJSONVALINT pThis = hJsonVal;
1553 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1554 AssertPtrReturn(ppszStr, VERR_INVALID_POINTER);
1555
1556 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_STRING);
1557 *ppszStr = pThis->Type.String.pszStr;
1558 return VINF_SUCCESS;
1559}
1560
1561RTDECL(int) RTJsonValueQueryInteger(RTJSONVAL hJsonVal, int64_t *pi64Num)
1562{
1563 PRTJSONVALINT pThis = hJsonVal;
1564 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1565 AssertPtrReturn(pi64Num, VERR_INVALID_POINTER);
1566
1567 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_INTEGER);
1568 *pi64Num = pThis->Type.Integer.i64Num;
1569 return VINF_SUCCESS;
1570}
1571
1572RTDECL(int) RTJsonValueQueryNumber(RTJSONVAL hJsonVal, double *prdNum)
1573{
1574 PRTJSONVALINT pThis = hJsonVal;
1575 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1576 AssertPtrReturn(prdNum, VERR_INVALID_POINTER);
1577
1578 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_NUMBER);
1579 *prdNum = pThis->Type.rdNum;
1580 return VINF_SUCCESS;
1581}
1582
1583RTDECL(int) RTJsonValueQueryByName(RTJSONVAL hJsonVal, const char *pszName, PRTJSONVAL phJsonVal)
1584{
1585 PRTJSONVALINT pThis = hJsonVal;
1586 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1587 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1588 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1589
1590 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_OBJECT);
1591
1592 int rc = VERR_NOT_FOUND;
1593 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
1594 {
1595 if (!RTStrCmp(pThis->Type.Object.papszNames[i], pszName))
1596 {
1597 RTJsonValueRetain(pThis->Type.Object.papValues[i]);
1598 *phJsonVal = pThis->Type.Object.papValues[i];
1599 rc = VINF_SUCCESS;
1600 break;
1601 }
1602 }
1603
1604 return rc;
1605}
1606
1607RTDECL(int) RTJsonValueQueryIntegerByName(RTJSONVAL hJsonVal, const char *pszName, int64_t *pi64Num)
1608{
1609 RTJSONVAL hJsonValNum = NIL_RTJSONVAL;
1610 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValNum);
1611 if (RT_SUCCESS(rc))
1612 {
1613 rc = RTJsonValueQueryInteger(hJsonValNum, pi64Num);
1614 RTJsonValueRelease(hJsonValNum);
1615 }
1616
1617 return rc;
1618}
1619
1620RTDECL(int) RTJsonValueQueryNumberByName(RTJSONVAL hJsonVal, const char *pszName, double *prdNum)
1621{
1622 RTJSONVAL hJsonValNum = NIL_RTJSONVAL;
1623 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValNum);
1624 if (RT_SUCCESS(rc))
1625 {
1626 rc = RTJsonValueQueryNumber(hJsonValNum, prdNum);
1627 RTJsonValueRelease(hJsonValNum);
1628 }
1629
1630 return rc;
1631}
1632
1633RTDECL(int) RTJsonValueQueryStringByName(RTJSONVAL hJsonVal, const char *pszName, char **ppszStr)
1634{
1635 RTJSONVAL hJsonValStr = NIL_RTJSONVAL;
1636 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValStr);
1637 if (RT_SUCCESS(rc))
1638 {
1639 const char *pszStr = NULL;
1640 rc = RTJsonValueQueryString(hJsonValStr, &pszStr);
1641 if (RT_SUCCESS(rc))
1642 {
1643 *ppszStr = RTStrDup(pszStr);
1644 if (!*ppszStr)
1645 rc = VERR_NO_STR_MEMORY;
1646 }
1647 RTJsonValueRelease(hJsonValStr);
1648 }
1649
1650 return rc;
1651}
1652
1653RTDECL(int) RTJsonValueQueryBooleanByName(RTJSONVAL hJsonVal, const char *pszName, bool *pfBoolean)
1654{
1655 AssertPtrReturn(pfBoolean, VERR_INVALID_POINTER);
1656
1657 RTJSONVAL hJsonValBool = NIL_RTJSONVAL;
1658 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValBool);
1659 if (RT_SUCCESS(rc))
1660 {
1661 RTJSONVALTYPE enmType = RTJsonValueGetType(hJsonValBool);
1662 if (enmType == RTJSONVALTYPE_TRUE)
1663 *pfBoolean = true;
1664 else if (enmType == RTJSONVALTYPE_FALSE)
1665 *pfBoolean = false;
1666 else
1667 rc = VERR_JSON_VALUE_INVALID_TYPE;
1668 RTJsonValueRelease(hJsonValBool);
1669 }
1670
1671 return rc;
1672}
1673
1674RTDECL(unsigned) RTJsonValueGetArraySize(RTJSONVAL hJsonVal)
1675{
1676 PRTJSONVALINT pThis = hJsonVal;
1677 RTJSON_ASSERT_VALID_HANDLE_AND_TYPE_RETURN(pThis, RTJSONVALTYPE_ARRAY, 0);
1678
1679 return pThis->Type.Array.cItems;
1680}
1681
1682RTDECL(int) RTJsonValueQueryArraySize(RTJSONVAL hJsonVal, unsigned *pcItems)
1683{
1684 PRTJSONVALINT pThis = hJsonVal;
1685 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1686 AssertPtrReturn(pcItems, VERR_INVALID_POINTER);
1687
1688 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
1689 *pcItems = pThis->Type.Array.cItems;
1690 return VINF_SUCCESS;
1691}
1692
1693RTDECL(int) RTJsonValueQueryByIndex(RTJSONVAL hJsonVal, unsigned idx, PRTJSONVAL phJsonVal)
1694{
1695 PRTJSONVALINT pThis = hJsonVal;
1696 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1697 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1698
1699 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
1700 if (RT_UNLIKELY(idx >= pThis->Type.Array.cItems))
1701 return VERR_OUT_OF_RANGE;
1702
1703 RTJsonValueRetain(pThis->Type.Array.papItems[idx]);
1704 *phJsonVal = pThis->Type.Array.papItems[idx];
1705 return VINF_SUCCESS;
1706}
1707
1708static int rtJsonIteratorBeginWorker(PRTJSONVALINT pThis, PRTJSONIT phJsonIt)
1709{
1710 PRTJSONITINT pIt = (PRTJSONITINT)RTMemTmpAllocZ(sizeof(RTJSONITINT));
1711 if (pIt)
1712 {
1713 RTJsonValueRetain(pThis);
1714 pIt->pJsonVal = pThis;
1715 pIt->idxCur = 0;
1716
1717 *phJsonIt = pIt;
1718 return VINF_SUCCESS;
1719 }
1720 return VERR_NO_MEMORY;
1721}
1722
1723RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1724{
1725 PRTJSONVALINT pThis = hJsonVal;
1726 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1727 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1728 RTJSON_TYPECHECK_CONTAINER_RETURN(pThis);
1729
1730 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
1731}
1732
1733RTDECL(int) RTJsonIteratorBeginArray(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1734{
1735 PRTJSONVALINT pThis = hJsonVal;
1736 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1737 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1738 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
1739
1740 if (pThis->Type.Array.cItems > 0)
1741 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
1742 return VERR_JSON_IS_EMPTY;
1743}
1744
1745RTDECL(int) RTJsonIteratorBeginObject(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1746{
1747 PRTJSONVALINT pThis = hJsonVal;
1748 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1749 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1750 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_OBJECT);
1751
1752 if (pThis->Type.Object.cMembers > 0)
1753 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
1754 return VERR_JSON_IS_EMPTY;
1755}
1756
1757RTDECL(int) RTJsonIteratorQueryValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName)
1758{
1759 PRTJSONITINT pIt = hJsonIt;
1760 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
1761 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1762 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1763
1764 int rc = VINF_SUCCESS;
1765 PRTJSONVALINT pThis = pIt->pJsonVal;
1766 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1767 {
1768 if (pIt->idxCur < pThis->Type.Array.cItems)
1769 {
1770 if (ppszName)
1771 *ppszName = NULL;
1772
1773 RTJsonValueRetain(pThis->Type.Array.papItems[pIt->idxCur]);
1774 *phJsonVal = pThis->Type.Array.papItems[pIt->idxCur];
1775 }
1776 else
1777 rc = VERR_JSON_ITERATOR_END;
1778 }
1779 else
1780 {
1781 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1782
1783 if (pIt->idxCur < pThis->Type.Object.cMembers)
1784 {
1785 if (ppszName)
1786 *ppszName = pThis->Type.Object.papszNames[pIt->idxCur];
1787
1788 RTJsonValueRetain(pThis->Type.Object.papValues[pIt->idxCur]);
1789 *phJsonVal = pThis->Type.Object.papValues[pIt->idxCur];
1790 }
1791 else
1792 rc = VERR_JSON_ITERATOR_END;
1793 }
1794
1795 return rc;
1796}
1797
1798RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt)
1799{
1800 PRTJSONITINT pIt = hJsonIt;
1801 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
1802 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1803
1804 int rc = VINF_SUCCESS;
1805 PRTJSONVALINT pThis = pIt->pJsonVal;
1806 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1807 {
1808 if (pIt->idxCur < pThis->Type.Array.cItems)
1809 pIt->idxCur++;
1810
1811 if (pIt->idxCur == pThis->Type.Object.cMembers)
1812 rc = VERR_JSON_ITERATOR_END;
1813 }
1814 else
1815 {
1816 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1817
1818 if (pIt->idxCur < pThis->Type.Object.cMembers)
1819 pIt->idxCur++;
1820
1821 if (pIt->idxCur == pThis->Type.Object.cMembers)
1822 rc = VERR_JSON_ITERATOR_END;
1823 }
1824
1825 return rc;
1826}
1827
1828RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt)
1829{
1830 PRTJSONITINT pThis = hJsonIt;
1831 AssertPtrReturnVoid(pThis);
1832
1833 if (pThis == NIL_RTJSONIT)
1834 return;
1835
1836 RTJsonValueRelease(pThis->pJsonVal);
1837 RTMemTmpFree(pThis);
1838}
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