VirtualBox

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

Last change on this file since 69222 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.7 KB
Line 
1/* $Id: json.cpp 69111 2017-10-17 14:26:02Z 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/asm.h>
32#include <iprt/assert.h>
33#include <iprt/cdefs.h>
34#include <iprt/ctype.h>
35#include <iprt/json.h>
36#include <iprt/mem.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44
45/**
46 * JSON parser position information.
47 */
48typedef struct RTJSONPOS
49{
50 /** Line in the source. */
51 size_t iLine;
52 /** Current start character .*/
53 size_t iChStart;
54 /** Current end character. */
55 size_t iChEnd;
56} RTJSONPOS;
57/** Pointer to a position. */
58typedef RTJSONPOS *PRTJSONPOS;
59
60/**
61 * JSON token class.
62 */
63typedef enum RTJSONTOKENCLASS
64{
65 /** Invalid. */
66 RTJSONTOKENCLASS_INVALID = 0,
67 /** Array begin. */
68 RTJSONTOKENCLASS_BEGIN_ARRAY,
69 /** Object begin. */
70 RTJSONTOKENCLASS_BEGIN_OBJECT,
71 /** Array end. */
72 RTJSONTOKENCLASS_END_ARRAY,
73 /** Object end. */
74 RTJSONTOKENCLASS_END_OBJECT,
75 /** Separator for name/value pairs. */
76 RTJSONTOKENCLASS_NAME_SEPARATOR,
77 /** Value separator. */
78 RTJSONTOKENCLASS_VALUE_SEPARATOR,
79 /** String */
80 RTJSONTOKENCLASS_STRING,
81 /** Number. */
82 RTJSONTOKENCLASS_NUMBER,
83 /** null keyword. */
84 RTJSONTOKENCLASS_NULL,
85 /** false keyword. */
86 RTJSONTOKENCLASS_FALSE,
87 /** true keyword. */
88 RTJSONTOKENCLASS_TRUE,
89 /** End of stream */
90 RTJSONTOKENCLASS_EOS,
91 /** 32bit hack. */
92 RTJSONTOKENCLASS_32BIT_HACK = 0x7fffffff
93} RTJSONTOKENCLASS;
94/** Pointer to a token class. */
95typedef RTJSONTOKENCLASS *PRTJSONTOKENCLASS;
96
97/**
98 * JSON token.
99 */
100typedef struct RTJSONTOKEN
101{
102 /** Token class. */
103 RTJSONTOKENCLASS enmClass;
104 /** Token position in the source buffer. */
105 RTJSONPOS Pos;
106 /** Data based on the token class. */
107 union
108 {
109 /** String. */
110 struct
111 {
112 /** Pointer to the start of the string. */
113 char *pszStr;
114 } String;
115 /** Number. */
116 struct
117 {
118 int64_t i64Num;
119 } Number;
120 } Class;
121} RTJSONTOKEN;
122/** Pointer to a JSON token. */
123typedef RTJSONTOKEN *PRTJSONTOKEN;
124/** Pointer to a const script token. */
125typedef const RTJSONTOKEN *PCRTJSONTOKEN;
126
127/**
128 * Tokenizer read input callback.
129 *
130 * @returns IPRT status code.
131 * @param pvUser Opaque user data for the callee.
132 * @param offInput Start offset from the start of the input stream to read from.
133 * @param pvBuf Where to store the read data.
134 * @param cbBuf How much to read.
135 * @param pcbRead Where to store the amount of data read on succcess.
136 */
137typedef DECLCALLBACK(int) FNRTJSONTOKENIZERREAD(void *pvUser, size_t offInput, void *pvBuf, size_t cbBuf,
138 size_t *pcbRead);
139/** Pointer to a tokenizer read buffer callback. */
140typedef FNRTJSONTOKENIZERREAD *PFNRTJSONTOKENIZERREAD;
141
142/**
143 * Tokenizer state.
144 */
145typedef struct RTJSONTOKENIZER
146{
147 /** Read callback. */
148 PFNRTJSONTOKENIZERREAD pfnRead;
149 /** Opaque user data. */
150 void *pvUser;
151 /** Current offset into the input stream. */
152 size_t offInput;
153 /** Number of valid bytes in the input buffer. */
154 size_t cbBuf;
155 /* Current offset into the input buffer. */
156 size_t offBuf;
157 /** Input cache buffer. */
158 char achBuf[512];
159 /** Current position into the input stream. */
160 RTJSONPOS Pos;
161 /** Token 1. */
162 RTJSONTOKEN Token1;
163 /** Token 2. */
164 RTJSONTOKEN Token2;
165 /** Pointer to the current active token. */
166 PRTJSONTOKEN pTokenCurr;
167 /** The next token in the input stream (used for peeking). */
168 PRTJSONTOKEN pTokenNext;
169} RTJSONTOKENIZER;
170/** Pointer to a JSON tokenizer. */
171typedef RTJSONTOKENIZER *PRTJSONTOKENIZER;
172
173/** Pointer to the internal JSON value instance. */
174typedef struct RTJSONVALINT *PRTJSONVALINT;
175
176/**
177 * A JSON value.
178 */
179typedef struct RTJSONVALINT
180{
181 /** Type of the JSON value. */
182 RTJSONVALTYPE enmType;
183 /** Reference count for this JSON value. */
184 volatile uint32_t cRefs;
185 /** Type dependent data. */
186 union
187 {
188 /** String type*/
189 struct
190 {
191 /** Pointer to the string. */
192 char *pszStr;
193 } String;
194 /** Number type. */
195 struct
196 {
197 /** Signed 64-bit integer. */
198 int64_t i64Num;
199 } Number;
200 /** Array type. */
201 struct
202 {
203 /** Number of elements in the array. */
204 unsigned cItems;
205 /** Pointer to the array of items. */
206 PRTJSONVALINT *papItems;
207 } Array;
208 /** Object type. */
209 struct
210 {
211 /** Number of members. */
212 unsigned cMembers;
213 /** Pointer to the array holding the member names. */
214 char **papszNames;
215 /** Pointer to the array holding the values. */
216 PRTJSONVALINT *papValues;
217 } Object;
218 } Type;
219} RTJSONVALINT;
220
221/**
222 * A JSON iterator.
223 */
224typedef struct RTJSONITINT
225{
226 /** Referenced JSON value. */
227 PRTJSONVALINT pJsonVal;
228 /** Current index. */
229 unsigned idxCur;
230} RTJSONITINT;
231/** Pointer to the internal JSON iterator instance. */
232typedef RTJSONITINT *PRTJSONITINT;
233
234/**
235 * Passing arguments for the read callbacks.
236 */
237typedef struct RTJSONREADERARGS
238{
239 /** Buffer/File size */
240 size_t cbData;
241 /** Data specific for one callback. */
242 union
243 {
244 PRTSTREAM hStream;
245 const uint8_t *pbBuf;
246 } u;
247} RTJSONREADERARGS;
248/** Pointer to a readers argument. */
249typedef RTJSONREADERARGS *PRTJSONREADERARGS;
250
251
252/*********************************************************************************************************************************
253* Global variables *
254*********************************************************************************************************************************/
255
256static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken,
257 PRTJSONVALINT *ppJsonVal, PRTERRINFO pErrInfo);
258
259/**
260 * Fill the input buffer from the input stream.
261 *
262 * @returns IPRT status code.
263 * @param pTokenizer The tokenizer state.
264 */
265static int rtJsonTokenizerRead(PRTJSONTOKENIZER pTokenizer)
266{
267 size_t cbRead = 0;
268 int rc = pTokenizer->pfnRead(pTokenizer->pvUser, pTokenizer->offInput, &pTokenizer->achBuf[0],
269 sizeof(pTokenizer->achBuf), &cbRead);
270 if (RT_SUCCESS(rc))
271 {
272 pTokenizer->cbBuf = cbRead;
273 pTokenizer->offInput += cbRead;
274 pTokenizer->offBuf = 0;
275 /* Validate UTF-8 encoding. */
276 rc = RTStrValidateEncodingEx(&pTokenizer->achBuf[0], cbRead, 0 /* fFlags */);
277 /* If we read less than requested we reached the end and fill the remainder with terminators. */
278 if (cbRead < sizeof(pTokenizer->achBuf))
279 memset(&pTokenizer->achBuf[cbRead], 0, sizeof(pTokenizer->achBuf) - cbRead);
280 }
281
282 return rc;
283}
284
285/**
286 * Skips the given amount of characters in the input stream.
287 *
288 * @returns IPRT status code.
289 * @param pTokenizer The tokenizer state.
290 * @param cchSkip The amount of characters to skip.
291 */
292static int rtJsonTokenizerSkip(PRTJSONTOKENIZER pTokenizer, size_t cchSkip)
293{
294 int rc = VINF_SUCCESS;
295
296 /*
297 * In case we reached the end of the stream don't even attempt to read new data.
298 * Safety precaution for possible bugs in the parser causing out of bounds reads
299 */
300 if (pTokenizer->achBuf[pTokenizer->offBuf] == '\0')
301 return rc;
302
303 while ( cchSkip > 0
304 && pTokenizer->offBuf < pTokenizer->cbBuf
305 && RT_SUCCESS(rc))
306 {
307 size_t cchThisSkip = RT_MIN(cchSkip, pTokenizer->cbBuf - pTokenizer->offBuf);
308
309 pTokenizer->offBuf += cchThisSkip;
310 /* Read new data if required and we didn't reach the end yet. */
311 if ( pTokenizer->offBuf == pTokenizer->cbBuf
312 && pTokenizer->cbBuf == sizeof(pTokenizer->achBuf))
313 rc = rtJsonTokenizerRead(pTokenizer);
314
315 cchSkip -= cchThisSkip;
316 }
317
318 return rc;
319}
320
321
322/**
323 * Returns whether the tokenizer reached the end of the stream.
324 *
325 * @returns true if the tokenizer reached the end of stream marker
326 * false otherwise.
327 * @param pTokenizer The tokenizer state.
328 */
329DECLINLINE(bool) rtJsonTokenizerIsEos(PRTJSONTOKENIZER pTokenizer)
330{
331 return pTokenizer->achBuf[pTokenizer->offBuf] == '\0';
332}
333
334/**
335 * Skip one character in the input stream.
336 *
337 * @returns nothing.
338 * @param pTokenizer The tokenizer state.
339 */
340DECLINLINE(void) rtJsonTokenizerSkipCh(PRTJSONTOKENIZER pTokenizer)
341{
342 rtJsonTokenizerSkip(pTokenizer, 1);
343 pTokenizer->Pos.iChStart++;
344 pTokenizer->Pos.iChEnd++;
345}
346
347/**
348 * Returns the next char in the input buffer without advancing it.
349 *
350 * @returns Next character in the input buffer.
351 * @param pTokenizer The tokenizer state.
352 */
353DECLINLINE(char) rtJsonTokenizerPeekCh(PRTJSONTOKENIZER pTokenizer)
354{
355 return rtJsonTokenizerIsEos(pTokenizer)
356 ? '\0'
357 : pTokenizer->achBuf[pTokenizer->offBuf + 1]; /** @todo Read out of bounds */
358}
359
360/**
361 * Returns the next character in the input buffer advancing the internal
362 * position.
363 *
364 * @returns Next character in the stream.
365 * @param pTokenizer The tokenizer state.
366 */
367DECLINLINE(char) rtJsonTokenizerGetCh(PRTJSONTOKENIZER pTokenizer)
368{
369 char ch;
370
371 if (rtJsonTokenizerIsEos(pTokenizer))
372 ch = '\0';
373 else
374 ch = pTokenizer->achBuf[pTokenizer->offBuf];
375
376 return ch;
377}
378
379/**
380 * Sets a new line for the tokenizer.
381 *
382 * @returns nothing.
383 * @param pTokenizer The tokenizer state.
384 * @param cSkip Amount of characters to skip making up the new line.
385 */
386DECLINLINE(void) rtJsonTokenizerNewLine(PRTJSONTOKENIZER pTokenizer, unsigned cSkip)
387{
388 rtJsonTokenizerSkip(pTokenizer, cSkip);
389 pTokenizer->Pos.iLine++;
390 pTokenizer->Pos.iChStart = 1;
391 pTokenizer->Pos.iChEnd = 1;
392}
393
394/**
395 * Checks whether the current position in the input stream is a new line
396 * and skips it.
397 *
398 * @returns Flag whether there was a new line at the current position
399 * in the input buffer.
400 * @param pTokenizer The tokenizer state.
401 */
402DECLINLINE(bool) rtJsonTokenizerIsSkipNewLine(PRTJSONTOKENIZER pTokenizer)
403{
404 bool fNewline = true;
405
406 if ( rtJsonTokenizerGetCh(pTokenizer) == '\r'
407 && rtJsonTokenizerPeekCh(pTokenizer) == '\n')
408 rtJsonTokenizerNewLine(pTokenizer, 2);
409 else if (rtJsonTokenizerGetCh(pTokenizer) == '\n')
410 rtJsonTokenizerNewLine(pTokenizer, 1);
411 else
412 fNewline = false;
413
414 return fNewline;
415}
416
417/**
418 * Skip all whitespace starting from the current input buffer position.
419 * Skips all present comments too.
420 *
421 * @returns nothing.
422 * @param pTokenizer The tokenizer state.
423 */
424DECLINLINE(void) rtJsonTokenizerSkipWhitespace(PRTJSONTOKENIZER pTokenizer)
425{
426 while (!rtJsonTokenizerIsEos(pTokenizer))
427 {
428 while ( rtJsonTokenizerGetCh(pTokenizer) == ' '
429 || rtJsonTokenizerGetCh(pTokenizer) == '\t')
430 rtJsonTokenizerSkipCh(pTokenizer);
431
432 if ( !rtJsonTokenizerIsEos(pTokenizer)
433 && !rtJsonTokenizerIsSkipNewLine(pTokenizer))
434 break; /* Skipped everything, next is some real content. */
435 }
436}
437
438/**
439 * Get an literal token from the tokenizer.
440 *
441 * @returns IPRT status code.
442 * @param pTokenizer The tokenizer state.
443 * @param pToken The uninitialized token.
444 */
445static int rtJsonTokenizerGetLiteral(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
446{
447 int rc = VINF_SUCCESS;
448 char ch = rtJsonTokenizerGetCh(pTokenizer);
449 size_t cchLiteral = 0;
450 char szLiteral[6]; /* false + 0 terminator as the lingest possible literal. */
451 RT_ZERO(szLiteral);
452
453 pToken->Pos = pTokenizer->Pos;
454
455 Assert(RT_C_IS_ALPHA(ch));
456
457 while ( RT_C_IS_ALPHA(ch)
458 && cchLiteral < RT_ELEMENTS(szLiteral) - 1)
459 {
460 szLiteral[cchLiteral] = ch;
461 cchLiteral++;
462 rtJsonTokenizerSkipCh(pTokenizer);
463 ch = rtJsonTokenizerGetCh(pTokenizer);
464 }
465
466 if (!RTStrNCmp(&szLiteral[0], "false", RT_ELEMENTS(szLiteral)))
467 pToken->enmClass = RTJSONTOKENCLASS_FALSE;
468 else if (!RTStrNCmp(&szLiteral[0], "true", RT_ELEMENTS(szLiteral)))
469 pToken->enmClass = RTJSONTOKENCLASS_TRUE;
470 else if (!RTStrNCmp(&szLiteral[0], "null", RT_ELEMENTS(szLiteral)))
471 pToken->enmClass = RTJSONTOKENCLASS_NULL;
472 else
473 {
474 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
475 rc = VERR_JSON_MALFORMED;
476 }
477
478 pToken->Pos.iChEnd += cchLiteral;
479 return rc;
480}
481
482/**
483 * Get a numerical constant from the tokenizer.
484 *
485 * @returns IPRT status code.
486 * @param pTokenizer The tokenizer state.
487 * @param pToken The uninitialized token.
488 */
489static int rtJsonTokenizerGetNumber(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
490{
491 size_t cchNum = 0;
492 char szTmp[128]; /* Everything larger is not possible to display in signed 64bit. */
493
494 pToken->enmClass = RTJSONTOKENCLASS_NUMBER;
495
496 char ch = rtJsonTokenizerGetCh(pTokenizer);
497 while ( RT_C_IS_DIGIT(ch)
498 && cchNum < sizeof(szTmp) - 1)
499 {
500 szTmp[cchNum] = ch;
501 cchNum++;
502 rtJsonTokenizerSkipCh(pTokenizer);
503 ch = rtJsonTokenizerGetCh(pTokenizer);
504 }
505
506 int rc = VINF_SUCCESS;
507 if (RT_C_IS_DIGIT(ch) && cchNum >= sizeof(szTmp) - 1)
508 rc = VERR_NUMBER_TOO_BIG;
509 else
510 {
511 szTmp[cchNum] = '\0';
512 rc = RTStrToInt64Ex(&szTmp[0], NULL, 0, &pToken->Class.Number.i64Num);
513 Assert(RT_SUCCESS(rc) || rc == VWRN_NUMBER_TOO_BIG);
514 if (rc == VWRN_NUMBER_TOO_BIG)
515 rc = VERR_NUMBER_TOO_BIG;
516 }
517
518 return rc;
519}
520
521/**
522 * Parses a string constant.
523 *
524 * @returns IPRT status code.
525 * @param pTokenizer The tokenizer state.
526 * @param pToken The uninitialized token.
527 */
528static int rtJsonTokenizerGetString(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
529{
530 int rc = VINF_SUCCESS;
531 size_t cchStr = 0;
532 char szTmp[_4K];
533 RT_ZERO(szTmp);
534
535 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\"');
536 rtJsonTokenizerSkipCh(pTokenizer); /* Skip " */
537
538 pToken->enmClass = RTJSONTOKENCLASS_STRING;
539 pToken->Pos = pTokenizer->Pos;
540
541 char ch = rtJsonTokenizerGetCh(pTokenizer);
542 while ( ch != '\"'
543 && ch != '\0'
544 && cchStr < sizeof(szTmp) - 1)
545 {
546 if (ch == '\\')
547 {
548 /* Escape sequence, check the next character */
549 rtJsonTokenizerSkipCh(pTokenizer);
550 char chNext = rtJsonTokenizerGetCh(pTokenizer);
551 switch (chNext)
552 {
553 case '\"':
554 szTmp[cchStr] = '\"';
555 break;
556 case '\\':
557 szTmp[cchStr] = '\\';
558 break;
559 case '/':
560 szTmp[cchStr] = '/';
561 break;
562 case '\b':
563 szTmp[cchStr] = '\b';
564 break;
565 case '\n':
566 szTmp[cchStr] = '\n';
567 break;
568 case '\f':
569 szTmp[cchStr] = '\f';
570 break;
571 case '\r':
572 szTmp[cchStr] = '\r';
573 break;
574 case '\t':
575 szTmp[cchStr] = '\t';
576 break;
577 case 'u':
578 rc = VERR_NOT_SUPPORTED;
579 break;
580 default:
581 rc = VERR_JSON_MALFORMED;
582 }
583 }
584 else
585 szTmp[cchStr] = ch;
586 cchStr++;
587 rtJsonTokenizerSkipCh(pTokenizer);
588 ch = rtJsonTokenizerGetCh(pTokenizer);
589 }
590
591 if (rtJsonTokenizerGetCh(pTokenizer) == '\"')
592 rtJsonTokenizerSkipCh(pTokenizer); /* Skip closing " */
593
594 pToken->Class.String.pszStr = RTStrDupN(&szTmp[0], cchStr);
595 if (pToken->Class.String.pszStr)
596 pToken->Pos.iChEnd += cchStr;
597 else
598 rc = VERR_NO_STR_MEMORY;
599 return rc;
600}
601
602/**
603 * Get the end of stream token.
604 *
605 * @returns IPRT status code.
606 * @param pTokenizer The tokenizer state.
607 * @param pToken The uninitialized token.
608 */
609static int rtJsonTokenizerGetEos(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
610{
611 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\0');
612
613 pToken->enmClass = RTJSONTOKENCLASS_EOS;
614 pToken->Pos = pTokenizer->Pos;
615 return VINF_SUCCESS;
616}
617
618/**
619 * Read the next token from the tokenizer stream.
620 *
621 * @returns IPRT status code.
622 * @param pTokenizer The tokenizer to read from.
623 * @param pToken Uninitialized token to fill the token data into.
624 */
625static int rtJsonTokenizerReadNextToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
626{
627 int rc = VINF_SUCCESS;
628
629 /* Skip all eventually existing whitespace and newlines first. */
630 rtJsonTokenizerSkipWhitespace(pTokenizer);
631
632 char ch = rtJsonTokenizerGetCh(pTokenizer);
633 if (RT_C_IS_ALPHA(ch))
634 rc = rtJsonTokenizerGetLiteral(pTokenizer, pToken);
635 else if (RT_C_IS_DIGIT(ch))
636 rc = rtJsonTokenizerGetNumber(pTokenizer, pToken);
637 else if (ch == '\"')
638 rc = rtJsonTokenizerGetString(pTokenizer, pToken);
639 else if (ch == '\0')
640 rc = rtJsonTokenizerGetEos(pTokenizer, pToken);
641 else if (ch == '{')
642 {
643 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_OBJECT;
644 rtJsonTokenizerSkipCh(pTokenizer);
645 }
646 else if (ch == '}')
647 {
648 pToken->enmClass = RTJSONTOKENCLASS_END_OBJECT;
649 rtJsonTokenizerSkipCh(pTokenizer);
650 }
651 else if (ch == '[')
652 {
653 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_ARRAY;
654 rtJsonTokenizerSkipCh(pTokenizer);
655 }
656 else if (ch == ']')
657 {
658 pToken->enmClass = RTJSONTOKENCLASS_END_ARRAY;
659 rtJsonTokenizerSkipCh(pTokenizer);
660 }
661 else if (ch == ':')
662 {
663 pToken->enmClass = RTJSONTOKENCLASS_NAME_SEPARATOR;
664 rtJsonTokenizerSkipCh(pTokenizer);
665 }
666 else if (ch == ',')
667 {
668 pToken->enmClass = RTJSONTOKENCLASS_VALUE_SEPARATOR;
669 rtJsonTokenizerSkipCh(pTokenizer);
670 }
671 else
672 {
673 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
674 rc = VERR_JSON_MALFORMED;
675 }
676
677 return rc;
678}
679
680/**
681 * Create a new tokenizer.
682 *
683 * @returns IPRT status code.
684 * @param pTokenizer The tokenizer state to initialize.
685 * @param pfnRead Read callback for the input stream.
686 * @param pvUser Opaque user data to pass to the callback.
687 */
688static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, PFNRTJSONTOKENIZERREAD pfnRead, void *pvUser)
689{
690 pTokenizer->pfnRead = pfnRead;
691 pTokenizer->pvUser = pvUser;
692 pTokenizer->offInput = 0;
693 pTokenizer->cbBuf = 0;
694 pTokenizer->offBuf = 0;
695 pTokenizer->Pos.iLine = 1;
696 pTokenizer->Pos.iChStart = 1;
697 pTokenizer->Pos.iChEnd = 1;
698 pTokenizer->pTokenCurr = &pTokenizer->Token1;
699 pTokenizer->pTokenNext = &pTokenizer->Token2;
700
701 RT_ZERO(pTokenizer->achBuf);
702
703 /* Fill the input buffer. */
704 int rc = rtJsonTokenizerRead(pTokenizer);
705
706 /* Fill the tokenizer with two first tokens. */
707 if (RT_SUCCESS(rc))
708 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr);
709 if (RT_SUCCESS(rc))
710 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
711
712 return rc;
713}
714
715/**
716 * Destroys a given tokenizer state.
717 *
718 * @returns nothing.
719 * @param pTokenizer The tokenizer to destroy.
720 */
721static void rtJsonTokenizerDestroy(PRTJSONTOKENIZER pTokenizer)
722{
723 RT_NOREF_PV(pTokenizer);
724}
725
726/**
727 * Get the current token in the input stream.
728 *
729 * @returns Pointer to the next token in the stream.
730 * @param pTokenizer The tokenizer state.
731 * @param ppToken Where to store the pointer to the current token on success.
732 */
733DECLINLINE(int) rtJsonTokenizerGetToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN *ppToken)
734{
735 *ppToken = pTokenizer->pTokenCurr;
736 return VINF_SUCCESS;
737}
738
739/**
740 * Consume the current token advancing to the next in the stream.
741 *
742 * @returns nothing.
743 * @param pTokenizer The tokenizer state.
744 */
745static void rtJsonTokenizerConsume(PRTJSONTOKENIZER pTokenizer)
746{
747 PRTJSONTOKEN pTokenTmp = pTokenizer->pTokenCurr;
748
749 /* Switch next token to current token and read in the next token. */
750 pTokenizer->pTokenCurr = pTokenizer->pTokenNext;
751 pTokenizer->pTokenNext = pTokenTmp;
752 rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
753}
754
755/**
756 * Consumes the current token if it matches the given class returning an indicator.
757 *
758 * @returns true if the class matched and the token was consumed.
759 * @retval false otherwise.
760 * @param pTokenizer The tokenizer state.
761 * @param enmClass The token class to match against.
762 */
763static bool rtJsonTokenizerConsumeIfMatched(PRTJSONTOKENIZER pTokenizer, RTJSONTOKENCLASS enmClass)
764{
765 PRTJSONTOKEN pToken = NULL;
766 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
767 AssertRC(rc);
768
769 if (pToken->enmClass == enmClass)
770 {
771 rtJsonTokenizerConsume(pTokenizer);
772 return true;
773 }
774
775 return false;
776}
777
778/**
779 * Destroys a given JSON value releasing the reference to all child values.
780 *
781 * @returns nothing.
782 * @param pThis The JSON value to destroy.
783 */
784static void rtJsonValDestroy(PRTJSONVALINT pThis)
785{
786 switch (pThis->enmType)
787 {
788 case RTJSONVALTYPE_OBJECT:
789 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
790 {
791 RTStrFree(pThis->Type.Object.papszNames[i]);
792 RTJsonValueRelease(pThis->Type.Object.papValues[i]);
793 }
794 RTMemFree(pThis->Type.Object.papszNames);
795 RTMemFree(pThis->Type.Object.papValues);
796 break;
797 case RTJSONVALTYPE_ARRAY:
798 for (unsigned i = 0; i < pThis->Type.Array.cItems; i++)
799 RTJsonValueRelease(pThis->Type.Array.papItems[i]);
800 RTMemFree(pThis->Type.Array.papItems);
801 break;
802 case RTJSONVALTYPE_STRING:
803 RTStrFree(pThis->Type.String.pszStr);
804 break;
805 case RTJSONVALTYPE_NUMBER:
806 case RTJSONVALTYPE_NULL:
807 case RTJSONVALTYPE_TRUE:
808 case RTJSONVALTYPE_FALSE:
809 /* nothing to do. */
810 break;
811 default:
812 AssertMsgFailed(("Invalid JSON value type: %u\n", pThis->enmType));
813 }
814 RTMemFree(pThis);
815}
816
817/**
818 * Creates a new JSON value with the given type.
819 *
820 * @returns Pointer to JSON value on success, NULL if out of memory.
821 * @param enmType The JSON value type.
822 */
823static PRTJSONVALINT rtJsonValueCreate(RTJSONVALTYPE enmType)
824{
825 PRTJSONVALINT pThis = (PRTJSONVALINT)RTMemAllocZ(sizeof(RTJSONVALINT));
826 if (RT_LIKELY(pThis))
827 {
828 pThis->enmType = enmType;
829 pThis->cRefs = 1;
830 }
831
832 return pThis;
833}
834
835/**
836 * Parses an JSON array.
837 *
838 * @returns IPRT status code.
839 * @param pTokenizer The tokenizer to use.
840 * @param pJsonVal The JSON array value to fill in.
841 * @param pErrInfo Where to store extended error info. Optional.
842 */
843static int rtJsonParseArray(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
844{
845 int rc = VINF_SUCCESS;
846 PRTJSONTOKEN pToken = NULL;
847 uint32_t cItems = 0;
848 uint32_t cItemsMax = 0;
849 PRTJSONVALINT *papItems = NULL;
850
851 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
852 while ( RT_SUCCESS(rc)
853 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY
854 && pToken->enmClass != RTJSONTOKENCLASS_EOS)
855 {
856 PRTJSONVALINT pVal = NULL;
857 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
858 if (RT_SUCCESS(rc))
859 {
860 if (cItems == cItemsMax)
861 {
862 cItemsMax += 10;
863 PRTJSONVALINT *papItemsNew = (PRTJSONVALINT *)RTMemRealloc(papItems, cItemsMax * sizeof(PRTJSONVALINT));
864 if (RT_UNLIKELY(!papItemsNew))
865 {
866 rc = VERR_NO_MEMORY;
867 break;
868 }
869 papItems = papItemsNew;
870 }
871
872 Assert(cItems < cItemsMax);
873 papItems[cItems] = pVal;
874 cItems++;
875 }
876
877 /* Skip value separator and continue with next token. */
878 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
879 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
880
881 if ( RT_SUCCESS(rc)
882 && !fSkippedSep
883 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY)
884 rc = VERR_JSON_MALFORMED;
885 }
886
887 if (RT_SUCCESS(rc))
888 {
889 if (pToken->enmClass == RTJSONTOKENCLASS_END_ARRAY)
890 {
891 rtJsonTokenizerConsume(pTokenizer);
892 pJsonVal->Type.Array.cItems = cItems;
893 pJsonVal->Type.Array.papItems = papItems;
894 }
895 else
896 rc = VERR_JSON_MALFORMED;
897 }
898
899 if (RT_FAILURE(rc))
900 {
901 for (uint32_t i = 0; i < cItems; i++)
902 RTJsonValueRelease(papItems[i]);
903 RTMemFree(papItems);
904 }
905
906 return rc;
907}
908
909/**
910 * Parses an JSON object.
911 *
912 * @returns IPRT status code.
913 * @param pTokenizer The tokenizer to use.
914 * @param pJsonVal The JSON object value to fill in.
915 * @param pErrInfo Where to store extended error info. Optional.
916 */
917static int rtJsonParseObject(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
918{
919 int rc = VINF_SUCCESS;
920 PRTJSONTOKEN pToken = NULL;
921 uint32_t cMembers = 0;
922 uint32_t cMembersMax = 0;
923 PRTJSONVALINT *papValues = NULL;
924 char **papszNames = NULL;
925
926 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
927 while ( RT_SUCCESS(rc)
928 && pToken->enmClass == RTJSONTOKENCLASS_STRING)
929 {
930 char *pszName = pToken->Class.String.pszStr;
931
932 rtJsonTokenizerConsume(pTokenizer);
933 if (rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_NAME_SEPARATOR))
934 {
935 PRTJSONVALINT pVal = NULL;
936 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
937 if (RT_SUCCESS(rc))
938 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
939 if (RT_SUCCESS(rc))
940 {
941 if (cMembers == cMembersMax)
942 {
943 cMembersMax += 10;
944 PRTJSONVALINT *papValuesNew = (PRTJSONVALINT *)RTMemRealloc(papValues, cMembersMax * sizeof(PRTJSONVALINT));
945 char **papszNamesNew = (char **)RTMemRealloc(papValues, cMembersMax * sizeof(char *));
946 if (RT_UNLIKELY(!papValuesNew || !papszNamesNew))
947 {
948 rc = VERR_NO_MEMORY;
949 break;
950 }
951
952 papValues = papValuesNew;
953 papszNames = papszNamesNew;
954 }
955
956 Assert(cMembers < cMembersMax);
957 papszNames[cMembers] = pszName;
958 papValues[cMembers] = pVal;
959 cMembers++;
960
961 /* Skip value separator and continue with next token. */
962 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
963 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
964
965 if ( RT_SUCCESS(rc)
966 && !fSkippedSep
967 && pToken->enmClass != RTJSONTOKENCLASS_END_OBJECT)
968 rc = VERR_JSON_MALFORMED;
969 }
970 }
971 else
972 rc = VERR_JSON_MALFORMED;
973 }
974
975 if (RT_SUCCESS(rc))
976 {
977 if (pToken->enmClass == RTJSONTOKENCLASS_END_OBJECT)
978 {
979 rtJsonTokenizerConsume(pTokenizer);
980 pJsonVal->Type.Object.cMembers = cMembers;
981 pJsonVal->Type.Object.papValues = papValues;
982 pJsonVal->Type.Object.papszNames = papszNames;
983 }
984 else
985 rc = VERR_JSON_MALFORMED;
986 }
987
988 if (RT_FAILURE(rc))
989 {
990 for (uint32_t i = 0; i < cMembers; i++)
991 {
992 RTJsonValueRelease(papValues[i]);
993 RTStrFree(papszNames[i]);
994 }
995 RTMemFree(papValues);
996 RTMemFree(papszNames);
997 }
998
999 return rc;
1000}
1001
1002/**
1003 * Parses a single JSON value and returns it on success.
1004 *
1005 * @returns IPRT status code.
1006 * @param pTokenizer The tokenizer to use.
1007 * @param pToken The token to parse.
1008 * @param ppJsonVal Where to store the pointer to the JSON value on success.
1009 * @param pErrInfo Where to store extended error info. Optional.
1010 */
1011static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken,
1012 PRTJSONVALINT *ppJsonVal, PRTERRINFO pErrInfo)
1013{
1014 int rc = VINF_SUCCESS;
1015 PRTJSONVALINT pVal = NULL;
1016
1017 switch (pToken->enmClass)
1018 {
1019 case RTJSONTOKENCLASS_BEGIN_ARRAY:
1020 rtJsonTokenizerConsume(pTokenizer);
1021 pVal = rtJsonValueCreate(RTJSONVALTYPE_ARRAY);
1022 if (RT_LIKELY(pVal))
1023 rc = rtJsonParseArray(pTokenizer, pVal, pErrInfo);
1024 break;
1025 case RTJSONTOKENCLASS_BEGIN_OBJECT:
1026 rtJsonTokenizerConsume(pTokenizer);
1027 pVal = rtJsonValueCreate(RTJSONVALTYPE_OBJECT);
1028 if (RT_LIKELY(pVal))
1029 rc = rtJsonParseObject(pTokenizer, pVal, pErrInfo);
1030 break;
1031 case RTJSONTOKENCLASS_STRING:
1032 pVal = rtJsonValueCreate(RTJSONVALTYPE_STRING);
1033 if (RT_LIKELY(pVal))
1034 pVal->Type.String.pszStr = pToken->Class.String.pszStr;
1035 rtJsonTokenizerConsume(pTokenizer);
1036 break;
1037 case RTJSONTOKENCLASS_NUMBER:
1038 pVal = rtJsonValueCreate(RTJSONVALTYPE_NUMBER);
1039 if (RT_LIKELY(pVal))
1040 pVal->Type.Number.i64Num = pToken->Class.Number.i64Num;
1041 rtJsonTokenizerConsume(pTokenizer);
1042 break;
1043 case RTJSONTOKENCLASS_NULL:
1044 rtJsonTokenizerConsume(pTokenizer);
1045 pVal = rtJsonValueCreate(RTJSONVALTYPE_NULL);
1046 break;
1047 case RTJSONTOKENCLASS_FALSE:
1048 rtJsonTokenizerConsume(pTokenizer);
1049 pVal = rtJsonValueCreate(RTJSONVALTYPE_FALSE);
1050 break;
1051 case RTJSONTOKENCLASS_TRUE:
1052 rtJsonTokenizerConsume(pTokenizer);
1053 pVal = rtJsonValueCreate(RTJSONVALTYPE_TRUE);
1054 break;
1055 case RTJSONTOKENCLASS_END_ARRAY:
1056 case RTJSONTOKENCLASS_END_OBJECT:
1057 case RTJSONTOKENCLASS_NAME_SEPARATOR:
1058 case RTJSONTOKENCLASS_VALUE_SEPARATOR:
1059 case RTJSONTOKENCLASS_EOS:
1060 default:
1061 /** @todo Error info */
1062 rc = VERR_JSON_MALFORMED;
1063 break;
1064 }
1065
1066 if (RT_SUCCESS(rc))
1067 {
1068 if (pVal)
1069 *ppJsonVal = pVal;
1070 else
1071 rc = VERR_NO_MEMORY;
1072 }
1073 else if (pVal)
1074 rtJsonValDestroy(pVal);
1075
1076 return rc;
1077}
1078
1079/**
1080 * Entry point to parse a JSON document.
1081 *
1082 * @returns IPRT status code.
1083 * @param pTokenizer The tokenizer state.
1084 * @param ppJsonVal Where to store the root JSON value on success.
1085 * @param pErrInfo Where to store extended error info. Optional.
1086 */
1087static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal,
1088 PRTERRINFO pErrInfo)
1089{
1090 PRTJSONTOKEN pToken = NULL;
1091 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1092 if (RT_SUCCESS(rc))
1093 rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal, pErrInfo);
1094
1095 return rc;
1096}
1097
1098/**
1099 * Read callback for RTJsonParseFromBuf().
1100 */
1101static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, size_t offInput,
1102 void *pvBuf, size_t cbBuf,
1103 size_t *pcbRead)
1104{
1105 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1106 size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0;
1107
1108 if (cbLeft)
1109 memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf));
1110
1111 *pcbRead = RT_MIN(cbLeft, cbBuf);
1112
1113 return VINF_SUCCESS;
1114}
1115
1116/**
1117 * Read callback for RTJsonParseFromString().
1118 */
1119static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, size_t offInput,
1120 void *pvBuf, size_t cbBuf,
1121 size_t *pcbRead)
1122{
1123 const char *pszStr = (const char *)pvUser;
1124 size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */
1125 size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0;
1126
1127 if (cbLeft)
1128 memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf));
1129
1130 *pcbRead = RT_MIN(cbLeft, cbBuf);
1131
1132 return VINF_SUCCESS;
1133}
1134
1135/**
1136 * Read callback for RTJsonParseFromFile().
1137 */
1138static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, size_t offInput,
1139 void *pvBuf, size_t cbBuf,
1140 size_t *pcbRead)
1141{
1142 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1143
1144 RT_NOREF_PV(offInput);
1145
1146 size_t cbRead = 0;
1147 int rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead);
1148 if (RT_SUCCESS(rc))
1149 *pcbRead = cbRead;
1150
1151 return rc;
1152}
1153
1154RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf,
1155 PRTERRINFO pErrInfo)
1156{
1157 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1158 AssertPtrReturn(pbBuf, VERR_INVALID_POINTER);
1159 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
1160
1161 RTJSONTOKENIZER Tokenizer;
1162 RTJSONREADERARGS Args;
1163 Args.cbData = cbBuf;
1164 Args.u.pbBuf = pbBuf;
1165
1166 int rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromBuf, &Args);
1167 if (RT_SUCCESS(rc))
1168 {
1169 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1170 rtJsonTokenizerDestroy(&Tokenizer);
1171 }
1172
1173 return rc;
1174}
1175
1176RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo)
1177{
1178 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1179 AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
1180
1181 RTJSONTOKENIZER Tokenizer;
1182 int rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromString, (void *)pszStr);
1183 if (RT_SUCCESS(rc))
1184 {
1185 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1186 rtJsonTokenizerDestroy(&Tokenizer);
1187 }
1188
1189 return rc;
1190}
1191
1192RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo)
1193{
1194 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1195 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1196
1197 int rc = VINF_SUCCESS;
1198 RTJSONREADERARGS Args;
1199
1200 Args.cbData = 0;
1201 rc = RTStrmOpen(pszFilename, "r", &Args.u.hStream);
1202 if (RT_SUCCESS(rc))
1203 {
1204 RTJSONTOKENIZER Tokenizer;
1205
1206 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromFile, &Args);
1207 if (RT_SUCCESS(rc))
1208 {
1209 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1210 rtJsonTokenizerDestroy(&Tokenizer);
1211 }
1212 RTStrmClose(Args.u.hStream);
1213 }
1214
1215 return rc;
1216}
1217
1218RTDECL(uint32_t) RTJsonValueRetain(RTJSONVAL hJsonVal)
1219{
1220 PRTJSONVALINT pThis = hJsonVal;
1221 AssertPtrReturn(pThis, UINT32_MAX);
1222
1223 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1224 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1225 return cRefs;
1226}
1227
1228RTDECL(uint32_t) RTJsonValueRelease(RTJSONVAL hJsonVal)
1229{
1230 PRTJSONVALINT pThis = hJsonVal;
1231 if (pThis == NIL_RTJSONVAL)
1232 return 0;
1233 AssertPtrReturn(pThis, UINT32_MAX);
1234
1235 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1236 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1237 if (cRefs == 0)
1238 rtJsonValDestroy(pThis);
1239 return cRefs;
1240}
1241
1242RTDECL(RTJSONVALTYPE) RTJsonValueGetType(RTJSONVAL hJsonVal)
1243{
1244 PRTJSONVALINT pThis = hJsonVal;
1245 if (pThis == NIL_RTJSONVAL)
1246 return RTJSONVALTYPE_INVALID;
1247 AssertPtrReturn(pThis, RTJSONVALTYPE_INVALID);
1248
1249 return pThis->enmType;
1250}
1251
1252RTDECL(const char *) RTJsonValueGetString(RTJSONVAL hJsonVal)
1253{
1254 PRTJSONVALINT pThis = hJsonVal;
1255 AssertReturn(pThis != NIL_RTJSONVAL, NULL);
1256 AssertReturn(pThis->enmType == RTJSONVALTYPE_STRING, NULL);
1257
1258 return pThis->Type.String.pszStr;
1259}
1260
1261RTDECL(int) RTJsonValueQueryString(RTJSONVAL hJsonVal, const char **ppszStr)
1262{
1263 PRTJSONVALINT pThis = hJsonVal;
1264 AssertPtrReturn(ppszStr, VERR_INVALID_POINTER);
1265 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1266 AssertReturn(pThis->enmType == RTJSONVALTYPE_STRING, VERR_JSON_VALUE_INVALID_TYPE);
1267
1268 *ppszStr = pThis->Type.String.pszStr;
1269 return VINF_SUCCESS;
1270}
1271
1272RTDECL(int) RTJsonValueQueryInteger(RTJSONVAL hJsonVal, int64_t *pi64Num)
1273{
1274 PRTJSONVALINT pThis = hJsonVal;
1275 AssertPtrReturn(pi64Num, VERR_INVALID_POINTER);
1276 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1277 AssertReturn(pThis->enmType == RTJSONVALTYPE_NUMBER, VERR_JSON_VALUE_INVALID_TYPE);
1278
1279 *pi64Num = pThis->Type.Number.i64Num;
1280 return VINF_SUCCESS;
1281}
1282
1283RTDECL(int) RTJsonValueQueryByName(RTJSONVAL hJsonVal, const char *pszName, PRTJSONVAL phJsonVal)
1284{
1285 PRTJSONVALINT pThis = hJsonVal;
1286 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1287 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1288 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1289 AssertReturn(pThis->enmType == RTJSONVALTYPE_OBJECT, VERR_JSON_VALUE_INVALID_TYPE);
1290
1291 int rc = VERR_NOT_FOUND;
1292 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
1293 {
1294 if (!RTStrCmp(pThis->Type.Object.papszNames[i], pszName))
1295 {
1296 RTJsonValueRetain(pThis->Type.Object.papValues[i]);
1297 *phJsonVal = pThis->Type.Object.papValues[i];
1298 rc = VINF_SUCCESS;
1299 break;
1300 }
1301 }
1302
1303 return rc;
1304}
1305
1306RTDECL(int) RTJsonValueQueryIntegerByName(RTJSONVAL hJsonVal, const char *pszName, int64_t *pi64Num)
1307{
1308 RTJSONVAL hJsonValNum = NIL_RTJSONVAL;
1309 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValNum);
1310 if (RT_SUCCESS(rc))
1311 {
1312 rc = RTJsonValueQueryInteger(hJsonValNum, pi64Num);
1313 RTJsonValueRelease(hJsonValNum);
1314 }
1315
1316 return rc;
1317}
1318
1319RTDECL(int) RTJsonValueQueryStringByName(RTJSONVAL hJsonVal, const char *pszName, char **ppszStr)
1320{
1321 RTJSONVAL hJsonValStr = NIL_RTJSONVAL;
1322 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValStr);
1323 if (RT_SUCCESS(rc))
1324 {
1325 const char *pszStr = NULL;
1326 rc = RTJsonValueQueryString(hJsonValStr, &pszStr);
1327 if (RT_SUCCESS(rc))
1328 {
1329 *ppszStr = RTStrDup(pszStr);
1330 if (!*ppszStr)
1331 rc = VERR_NO_STR_MEMORY;
1332 }
1333 RTJsonValueRelease(hJsonValStr);
1334 }
1335
1336 return rc;
1337}
1338
1339RTDECL(int) RTJsonValueQueryBooleanByName(RTJSONVAL hJsonVal, const char *pszName, bool *pfBoolean)
1340{
1341 AssertPtrReturn(pfBoolean, VERR_INVALID_POINTER);
1342
1343 RTJSONVAL hJsonValBool = NIL_RTJSONVAL;
1344 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValBool);
1345 if (RT_SUCCESS(rc))
1346 {
1347 RTJSONVALTYPE enmType = RTJsonValueGetType(hJsonValBool);
1348 if (enmType == RTJSONVALTYPE_TRUE)
1349 *pfBoolean = true;
1350 else if (enmType == RTJSONVALTYPE_FALSE)
1351 *pfBoolean = false;
1352 else
1353 rc = VERR_JSON_VALUE_INVALID_TYPE;
1354 RTJsonValueRelease(hJsonValBool);
1355 }
1356
1357 return rc;
1358}
1359
1360RTDECL(unsigned) RTJsonValueGetArraySize(RTJSONVAL hJsonVal)
1361{
1362 PRTJSONVALINT pThis = hJsonVal;
1363 AssertReturn(pThis != NIL_RTJSONVAL, 0);
1364 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, 0);
1365
1366 return pThis->Type.Array.cItems;
1367}
1368
1369RTDECL(int) RTJsonValueQueryArraySize(RTJSONVAL hJsonVal, unsigned *pcItems)
1370{
1371 PRTJSONVALINT pThis = hJsonVal;
1372 AssertPtrReturn(pcItems, VERR_INVALID_POINTER);
1373 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1374 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, VERR_JSON_VALUE_INVALID_TYPE);
1375
1376 *pcItems = pThis->Type.Array.cItems;
1377 return VINF_SUCCESS;
1378}
1379
1380RTDECL(int) RTJsonValueQueryByIndex(RTJSONVAL hJsonVal, unsigned idx, PRTJSONVAL phJsonVal)
1381{
1382 PRTJSONVALINT pThis = hJsonVal;
1383 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1384 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1385 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, VERR_JSON_VALUE_INVALID_TYPE);
1386 AssertReturn(idx < pThis->Type.Array.cItems, VERR_OUT_OF_RANGE);
1387
1388 RTJsonValueRetain(pThis->Type.Array.papItems[idx]);
1389 *phJsonVal = pThis->Type.Array.papItems[idx];
1390 return VINF_SUCCESS;
1391}
1392
1393RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1394{
1395 PRTJSONVALINT pThis = hJsonVal;
1396 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1397 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1398 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY || pThis->enmType == RTJSONVALTYPE_OBJECT,
1399 VERR_JSON_VALUE_INVALID_TYPE);
1400
1401 PRTJSONITINT pIt = (PRTJSONITINT)RTMemTmpAllocZ(sizeof(RTJSONITINT));
1402 if (RT_UNLIKELY(!pIt))
1403 return VERR_NO_MEMORY;
1404
1405 RTJsonValueRetain(hJsonVal);
1406 pIt->pJsonVal = pThis;
1407 pIt->idxCur = 0;
1408 *phJsonIt = pIt;
1409
1410 return VINF_SUCCESS;
1411}
1412
1413RTDECL(int) RTJsonIteratorQueryValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName)
1414{
1415 PRTJSONITINT pIt = hJsonIt;
1416 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1417 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1418
1419 int rc = VINF_SUCCESS;
1420 PRTJSONVALINT pThis = pIt->pJsonVal;
1421 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1422 {
1423 if (pIt->idxCur < pThis->Type.Array.cItems)
1424 {
1425 if (ppszName)
1426 *ppszName = NULL;
1427
1428 RTJsonValueRetain(pThis->Type.Array.papItems[pIt->idxCur]);
1429 *phJsonVal = pThis->Type.Array.papItems[pIt->idxCur];
1430 }
1431 else
1432 rc = VERR_JSON_ITERATOR_END;
1433 }
1434 else
1435 {
1436 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1437
1438 if (pIt->idxCur < pThis->Type.Object.cMembers)
1439 {
1440 if (ppszName)
1441 *ppszName = pThis->Type.Object.papszNames[pIt->idxCur];
1442
1443 RTJsonValueRetain(pThis->Type.Object.papValues[pIt->idxCur]);
1444 *phJsonVal = pThis->Type.Object.papValues[pIt->idxCur];
1445 }
1446 else
1447 rc = VERR_JSON_ITERATOR_END;
1448 }
1449
1450 return rc;
1451}
1452
1453RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt)
1454{
1455 PRTJSONITINT pIt = hJsonIt;
1456 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1457
1458 int rc = VINF_SUCCESS;
1459 PRTJSONVALINT pThis = pIt->pJsonVal;
1460 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1461 {
1462 if (pIt->idxCur < pThis->Type.Array.cItems)
1463 pIt->idxCur++;
1464
1465 if (pIt->idxCur == pThis->Type.Object.cMembers)
1466 rc = VERR_JSON_ITERATOR_END;
1467 }
1468 else
1469 {
1470 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1471
1472 if (pIt->idxCur < pThis->Type.Object.cMembers)
1473 pIt->idxCur++;
1474
1475 if (pIt->idxCur == pThis->Type.Object.cMembers)
1476 rc = VERR_JSON_ITERATOR_END;
1477 }
1478
1479 return rc;
1480}
1481
1482RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt)
1483{
1484 PRTJSONITINT pThis = hJsonIt;
1485 if (pThis == NIL_RTJSONIT)
1486 return;
1487 AssertPtrReturnVoid(pThis);
1488
1489 RTJsonValueRelease(pThis->pJsonVal);
1490 RTMemTmpFree(pThis);
1491}
1492
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