VirtualBox

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

Last change on this file since 62559 was 62461, checked in by vboxsync, 8 years ago

IPRT: scm

  • 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 62461 2016-07-22 16:21:26Z vboxsync $ */
2/** @file
3 * IPRT JSON parser API (JSON).
4 */
5
6/*
7 * Copyright (C) 2016 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 {
435 break; /* Skipped everything, next is some real content. */
436 }
437 }
438}
439
440/**
441 * Get an literal token from the tokenizer.
442 *
443 * @returns IPRT status code.
444 * @param pTokenizer The tokenizer state.
445 * @param pToken The uninitialized token.
446 */
447static int rtJsonTokenizerGetLiteral(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
448{
449 int rc = VINF_SUCCESS;
450 char ch = rtJsonTokenizerGetCh(pTokenizer);
451 size_t cchLiteral = 0;
452 char szLiteral[6]; /* false + 0 terminator as the lingest possible literal. */
453 RT_ZERO(szLiteral);
454
455 pToken->Pos = pTokenizer->Pos;
456
457 Assert(RT_C_IS_ALPHA(ch));
458
459 while ( RT_C_IS_ALPHA(ch)
460 && cchLiteral < RT_ELEMENTS(szLiteral) - 1)
461 {
462 szLiteral[cchLiteral] = ch;
463 cchLiteral++;
464 rtJsonTokenizerSkipCh(pTokenizer);
465 ch = rtJsonTokenizerGetCh(pTokenizer);
466 }
467
468 if (!RTStrNCmp(&szLiteral[0], "false", RT_ELEMENTS(szLiteral)))
469 pToken->enmClass = RTJSONTOKENCLASS_FALSE;
470 else if (!RTStrNCmp(&szLiteral[0], "true", RT_ELEMENTS(szLiteral)))
471 pToken->enmClass = RTJSONTOKENCLASS_TRUE;
472 else if (!RTStrNCmp(&szLiteral[0], "null", RT_ELEMENTS(szLiteral)))
473 pToken->enmClass = RTJSONTOKENCLASS_NULL;
474 else
475 {
476 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
477 rc = VERR_JSON_MALFORMED;
478 }
479
480 pToken->Pos.iChEnd += cchLiteral;
481 return rc;
482}
483
484/**
485 * Get a numerical constant from the tokenizer.
486 *
487 * @returns IPRT status code.
488 * @param pTokenizer The tokenizer state.
489 * @param pToken The uninitialized token.
490 */
491static int rtJsonTokenizerGetNumber(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
492{
493 size_t cchNum = 0;
494 char szTmp[128]; /* Everything larger is not possible to display in signed 64bit. */
495
496 pToken->enmClass = RTJSONTOKENCLASS_NUMBER;
497
498 char ch = rtJsonTokenizerGetCh(pTokenizer);
499 while ( RT_C_IS_DIGIT(ch)
500 && cchNum < sizeof(szTmp) - 1)
501 {
502 szTmp[cchNum] = ch;
503 cchNum++;
504 rtJsonTokenizerSkipCh(pTokenizer);
505 ch = rtJsonTokenizerGetCh(pTokenizer);
506 }
507
508 int rc = VINF_SUCCESS;
509 if (RT_C_IS_DIGIT(ch) && cchNum >= sizeof(szTmp) - 1)
510 rc = VERR_NUMBER_TOO_BIG;
511 else
512 {
513 szTmp[cchNum] = '\0';
514 rc = RTStrToInt64Ex(&szTmp[0], NULL, 0, &pToken->Class.Number.i64Num);
515 Assert(RT_SUCCESS(rc) || rc == VWRN_NUMBER_TOO_BIG);
516 if (rc == VWRN_NUMBER_TOO_BIG)
517 rc = VERR_NUMBER_TOO_BIG;
518 }
519
520 return rc;
521}
522
523/**
524 * Parses a string constant.
525 *
526 * @returns IPRT status code.
527 * @param pTokenizer The tokenizer state.
528 * @param pToken The uninitialized token.
529 */
530static int rtJsonTokenizerGetString(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
531{
532 int rc = VINF_SUCCESS;
533 size_t cchStr = 0;
534 char szTmp[_4K];
535 RT_ZERO(szTmp);
536
537 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\"');
538 rtJsonTokenizerSkipCh(pTokenizer); /* Skip " */
539
540 pToken->enmClass = RTJSONTOKENCLASS_STRING;
541 pToken->Pos = pTokenizer->Pos;
542
543 char ch = rtJsonTokenizerGetCh(pTokenizer);
544 while ( ch != '\"'
545 && ch != '\0'
546 && cchStr < sizeof(szTmp) - 1)
547 {
548 if (ch == '\\')
549 {
550 /* Escape sequence, check the next character */
551 rtJsonTokenizerSkipCh(pTokenizer);
552 char chNext = rtJsonTokenizerGetCh(pTokenizer);
553 switch (chNext)
554 {
555 case '\"':
556 szTmp[cchStr] = '\"';
557 break;
558 case '\\':
559 szTmp[cchStr] = '\\';
560 break;
561 case '/':
562 szTmp[cchStr] = '/';
563 break;
564 case '\b':
565 szTmp[cchStr] = '\b';
566 break;
567 case '\n':
568 szTmp[cchStr] = '\n';
569 break;
570 case '\f':
571 szTmp[cchStr] = '\f';
572 break;
573 case '\r':
574 szTmp[cchStr] = '\r';
575 break;
576 case '\t':
577 szTmp[cchStr] = '\t';
578 break;
579 case 'u':
580 rc = VERR_NOT_SUPPORTED;
581 break;
582 default:
583 rc = VERR_JSON_MALFORMED;
584 }
585 }
586 else
587 szTmp[cchStr] = ch;
588 cchStr++;
589 rtJsonTokenizerSkipCh(pTokenizer);
590 ch = rtJsonTokenizerGetCh(pTokenizer);
591 }
592
593 if (rtJsonTokenizerGetCh(pTokenizer) == '\"')
594 rtJsonTokenizerSkipCh(pTokenizer); /* Skip closing " */
595
596 pToken->Class.String.pszStr = RTStrDupN(&szTmp[0], cchStr);
597 if (pToken->Class.String.pszStr)
598 pToken->Pos.iChEnd += cchStr;
599 else
600 rc = VERR_NO_STR_MEMORY;
601 return rc;
602}
603
604/**
605 * Get the end of stream token.
606 *
607 * @returns IPRT status code.
608 * @param pTokenizer The tokenizer state.
609 * @param pToken The uninitialized token.
610 */
611static int rtJsonTokenizerGetEos(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
612{
613 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\0');
614
615 pToken->enmClass = RTJSONTOKENCLASS_EOS;
616 pToken->Pos = pTokenizer->Pos;
617 return VINF_SUCCESS;
618}
619
620/**
621 * Read the next token from the tokenizer stream.
622 *
623 * @returns IPRT status code.
624 * @param pTokenizer The tokenizer to read from.
625 * @param pToken Uninitialized token to fill the token data into.
626 */
627static int rtJsonTokenizerReadNextToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
628{
629 int rc = VINF_SUCCESS;
630
631 /* Skip all eventually existing whitespace and newlines first. */
632 rtJsonTokenizerSkipWhitespace(pTokenizer);
633
634 char ch = rtJsonTokenizerGetCh(pTokenizer);
635 if (RT_C_IS_ALPHA(ch))
636 rc = rtJsonTokenizerGetLiteral(pTokenizer, pToken);
637 else if (RT_C_IS_DIGIT(ch))
638 rc = rtJsonTokenizerGetNumber(pTokenizer, pToken);
639 else if (ch == '\"')
640 rc = rtJsonTokenizerGetString(pTokenizer, pToken);
641 else if (ch == '\0')
642 rc = rtJsonTokenizerGetEos(pTokenizer, pToken);
643 else if (ch == '{')
644 {
645 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_OBJECT;
646 rtJsonTokenizerSkipCh(pTokenizer);
647 }
648 else if (ch == '}')
649 {
650 pToken->enmClass = RTJSONTOKENCLASS_END_OBJECT;
651 rtJsonTokenizerSkipCh(pTokenizer);
652 }
653 else if (ch == '[')
654 {
655 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_ARRAY;
656 rtJsonTokenizerSkipCh(pTokenizer);
657 }
658 else if (ch == ']')
659 {
660 pToken->enmClass = RTJSONTOKENCLASS_END_ARRAY;
661 rtJsonTokenizerSkipCh(pTokenizer);
662 }
663 else if (ch == ':')
664 {
665 pToken->enmClass = RTJSONTOKENCLASS_NAME_SEPARATOR;
666 rtJsonTokenizerSkipCh(pTokenizer);
667 }
668 else if (ch == ',')
669 {
670 pToken->enmClass = RTJSONTOKENCLASS_VALUE_SEPARATOR;
671 rtJsonTokenizerSkipCh(pTokenizer);
672 }
673 else
674 {
675 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
676 rc = VERR_JSON_MALFORMED;
677 }
678
679 return rc;
680}
681
682/**
683 * Create a new tokenizer.
684 *
685 * @returns IPRT status code.
686 * @param pTokenizer The tokenizer state to initialize.
687 * @param pfnRead Read callback for the input stream.
688 * @param pvUser Opaque user data to pass to the callback.
689 */
690static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, PFNRTJSONTOKENIZERREAD pfnRead, void *pvUser)
691{
692 pTokenizer->pfnRead = pfnRead;
693 pTokenizer->pvUser = pvUser;
694 pTokenizer->offInput = 0;
695 pTokenizer->cbBuf = 0;
696 pTokenizer->offBuf = 0;
697 pTokenizer->Pos.iLine = 1;
698 pTokenizer->Pos.iChStart = 1;
699 pTokenizer->Pos.iChEnd = 1;
700 pTokenizer->pTokenCurr = &pTokenizer->Token1;
701 pTokenizer->pTokenNext = &pTokenizer->Token2;
702
703 RT_ZERO(pTokenizer->achBuf);
704
705 /* Fill the input buffer. */
706 int rc = rtJsonTokenizerRead(pTokenizer);
707
708 /* Fill the tokenizer with two first tokens. */
709 if (RT_SUCCESS(rc))
710 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr);
711 if (RT_SUCCESS(rc))
712 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
713
714 return rc;
715}
716
717/**
718 * Destroys a given tokenizer state.
719 *
720 * @returns nothing.
721 * @param pTokenizer The tokenizer to destroy.
722 */
723static void rtJsonTokenizerDestroy(PRTJSONTOKENIZER pTokenizer)
724{
725
726}
727
728/**
729 * Get the current token in the input stream.
730 *
731 * @returns Pointer to the next token in the stream.
732 * @param pTokenizer The tokenizer state.
733 * @param ppToken Where to store the pointer to the current token on success.
734 */
735DECLINLINE(int) rtJsonTokenizerGetToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN *ppToken)
736{
737 *ppToken = pTokenizer->pTokenCurr;
738 return VINF_SUCCESS;
739}
740
741/**
742 * Consume the current token advancing to the next in the stream.
743 *
744 * @returns nothing.
745 * @param pTokenizer The tokenizer state.
746 */
747static void rtJsonTokenizerConsume(PRTJSONTOKENIZER pTokenizer)
748{
749 PRTJSONTOKEN pTokenTmp = pTokenizer->pTokenCurr;
750
751 /* Switch next token to current token and read in the next token. */
752 pTokenizer->pTokenCurr = pTokenizer->pTokenNext;
753 pTokenizer->pTokenNext = pTokenTmp;
754 rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
755}
756
757/**
758 * Consumes the current token if it matches the given class returning an indicator.
759 *
760 * @returns true if the class matched and the token was consumed.
761 * @retval false otherwise.
762 * @param pTokenizer The tokenizer state.
763 * @param enmClass The token class to match against.
764 */
765static bool rtJsonTokenizerConsumeIfMatched(PRTJSONTOKENIZER pTokenizer, RTJSONTOKENCLASS enmClass)
766{
767 PRTJSONTOKEN pToken = NULL;
768 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
769 AssertRC(rc);
770
771 if (pToken->enmClass == enmClass)
772 {
773 rtJsonTokenizerConsume(pTokenizer);
774 return true;
775 }
776
777 return false;
778}
779
780/**
781 * Destroys a given JSON value releasing the reference to all child values.
782 *
783 * @returns nothing.
784 * @param pThis The JSON value to destroy.
785 */
786static void rtJsonValDestroy(PRTJSONVALINT pThis)
787{
788 switch (pThis->enmType)
789 {
790 case RTJSONVALTYPE_OBJECT:
791 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
792 {
793 RTStrFree(pThis->Type.Object.papszNames[i]);
794 RTJsonValueRelease(pThis->Type.Object.papValues[i]);
795 }
796 RTMemFree(pThis->Type.Object.papszNames);
797 RTMemFree(pThis->Type.Object.papValues);
798 break;
799 case RTJSONVALTYPE_ARRAY:
800 for (unsigned i = 0; i < pThis->Type.Array.cItems; i++)
801 RTJsonValueRelease(pThis->Type.Array.papItems[i]);
802 RTMemFree(pThis->Type.Array.papItems);
803 break;
804 case RTJSONVALTYPE_STRING:
805 RTStrFree(pThis->Type.String.pszStr);
806 break;
807 case RTJSONVALTYPE_NUMBER:
808 case RTJSONVALTYPE_NULL:
809 case RTJSONVALTYPE_TRUE:
810 case RTJSONVALTYPE_FALSE:
811 /* nothing to do. */
812 break;
813 default:
814 AssertMsgFailed(("Invalid JSON value type: %u\n", pThis->enmType));
815 }
816 RTMemFree(pThis);
817}
818
819/**
820 * Creates a new JSON value with the given type.
821 *
822 * @returns Pointer to JSON value on success, NULL if out of memory.
823 * @param enmType The JSON value type.
824 */
825static PRTJSONVALINT rtJsonValueCreate(RTJSONVALTYPE enmType)
826{
827 PRTJSONVALINT pThis = (PRTJSONVALINT)RTMemAllocZ(sizeof(RTJSONVALINT));
828 if (RT_LIKELY(pThis))
829 {
830 pThis->enmType = enmType;
831 pThis->cRefs = 1;
832 }
833
834 return pThis;
835}
836
837/**
838 * Parses an JSON array.
839 *
840 * @returns IPRT status code.
841 * @param pTokenizer The tokenizer to use.
842 * @param pJsonVal The JSON array value to fill in.
843 * @param pErrInfo Where to store extended error info. Optional.
844 */
845static int rtJsonParseArray(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
846{
847 int rc = VINF_SUCCESS;
848 PRTJSONTOKEN pToken = NULL;
849 uint32_t cItems = 0;
850 uint32_t cItemsMax = 0;
851 PRTJSONVALINT *papItems = NULL;
852
853 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
854 while ( RT_SUCCESS(rc)
855 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY
856 && pToken->enmClass != RTJSONTOKENCLASS_EOS)
857 {
858 PRTJSONVALINT pVal = NULL;
859 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
860 if (RT_SUCCESS(rc))
861 {
862 if (cItems == cItemsMax)
863 {
864 cItemsMax += 10;
865 PRTJSONVALINT *papItemsNew = (PRTJSONVALINT *)RTMemRealloc(papItems, cItemsMax * sizeof(PRTJSONVALINT));
866 if (RT_UNLIKELY(!papItemsNew))
867 {
868 rc = VERR_NO_MEMORY;
869 break;
870 }
871 papItems = papItemsNew;
872 }
873
874 Assert(cItems < cItemsMax);
875 papItems[cItems] = pVal;
876 cItems++;
877 }
878
879 /* Skip value separator and continue with next token. */
880 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
881 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
882
883 if ( RT_SUCCESS(rc)
884 && !fSkippedSep
885 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY)
886 rc = VERR_JSON_MALFORMED;
887 }
888
889 if (RT_SUCCESS(rc))
890 {
891 if (pToken->enmClass == RTJSONTOKENCLASS_END_ARRAY)
892 {
893 rtJsonTokenizerConsume(pTokenizer);
894 pJsonVal->Type.Array.cItems = cItems;
895 pJsonVal->Type.Array.papItems = papItems;
896 }
897 else
898 rc = VERR_JSON_MALFORMED;
899 }
900
901 if (RT_FAILURE(rc))
902 {
903 for (uint32_t i = 0; i < cItems; i++)
904 RTJsonValueRelease(papItems[i]);
905 RTMemFree(papItems);
906 }
907
908 return rc;
909}
910
911/**
912 * Parses an JSON object.
913 *
914 * @returns IPRT status code.
915 * @param pTokenizer The tokenizer to use.
916 * @param pJsonVal The JSON object value to fill in.
917 * @param pErrInfo Where to store extended error info. Optional.
918 */
919static int rtJsonParseObject(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
920{
921 int rc = VINF_SUCCESS;
922 PRTJSONTOKEN pToken = NULL;
923 uint32_t cMembers = 0;
924 uint32_t cMembersMax = 0;
925 PRTJSONVALINT *papValues = NULL;
926 char **papszNames = NULL;
927
928 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
929 while ( RT_SUCCESS(rc)
930 && pToken->enmClass == RTJSONTOKENCLASS_STRING)
931 {
932 char *pszName = pToken->Class.String.pszStr;
933
934 rtJsonTokenizerConsume(pTokenizer);
935 if (rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_NAME_SEPARATOR))
936 {
937 PRTJSONVALINT pVal = NULL;
938 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
939 if (RT_SUCCESS(rc))
940 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
941 if (RT_SUCCESS(rc))
942 {
943 if (cMembers == cMembersMax)
944 {
945 cMembersMax += 10;
946 PRTJSONVALINT *papValuesNew = (PRTJSONVALINT *)RTMemRealloc(papValues, cMembersMax * sizeof(PRTJSONVALINT));
947 char **papszNamesNew = (char **)RTMemRealloc(papValues, cMembersMax * sizeof(char *));
948 if (RT_UNLIKELY(!papValuesNew || !papszNamesNew))
949 {
950 rc = VERR_NO_MEMORY;
951 break;
952 }
953
954 papValues = papValuesNew;
955 papszNames = papszNamesNew;
956 }
957
958 Assert(cMembers < cMembersMax);
959 papszNames[cMembers] = pszName;
960 papValues[cMembers] = pVal;
961 cMembers++;
962
963 /* Skip value separator and continue with next token. */
964 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
965 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
966
967 if ( RT_SUCCESS(rc)
968 && !fSkippedSep
969 && pToken->enmClass != RTJSONTOKENCLASS_END_OBJECT)
970 rc = VERR_JSON_MALFORMED;
971 }
972 }
973 else
974 rc = VERR_JSON_MALFORMED;
975 }
976
977 if (RT_SUCCESS(rc))
978 {
979 if (pToken->enmClass == RTJSONTOKENCLASS_END_OBJECT)
980 {
981 rtJsonTokenizerConsume(pTokenizer);
982 pJsonVal->Type.Object.cMembers = cMembers;
983 pJsonVal->Type.Object.papValues = papValues;
984 pJsonVal->Type.Object.papszNames = papszNames;
985 }
986 else
987 rc = VERR_JSON_MALFORMED;
988 }
989
990 if (RT_FAILURE(rc))
991 {
992 for (uint32_t i = 0; i < cMembers; i++)
993 {
994 RTJsonValueRelease(papValues[i]);
995 RTStrFree(papszNames[i]);
996 }
997 RTMemFree(papValues);
998 RTMemFree(papszNames);
999 }
1000
1001 return rc;
1002}
1003
1004/**
1005 * Parses a single JSON value and returns it on success.
1006 *
1007 * @returns IPRT status code.
1008 * @param pTokenizer The tokenizer to use.
1009 * @param pToken The token to parse.
1010 * @param ppJsonVal Where to store the pointer to the JSON value on success.
1011 * @param pErrInfo Where to store extended error info. Optional.
1012 */
1013static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken,
1014 PRTJSONVALINT *ppJsonVal, PRTERRINFO pErrInfo)
1015{
1016 int rc = VINF_SUCCESS;
1017 PRTJSONVALINT pVal = NULL;
1018
1019 switch (pToken->enmClass)
1020 {
1021 case RTJSONTOKENCLASS_BEGIN_ARRAY:
1022 rtJsonTokenizerConsume(pTokenizer);
1023 pVal = rtJsonValueCreate(RTJSONVALTYPE_ARRAY);
1024 if (RT_LIKELY(pVal))
1025 rc = rtJsonParseArray(pTokenizer, pVal, pErrInfo);
1026 break;
1027 case RTJSONTOKENCLASS_BEGIN_OBJECT:
1028 rtJsonTokenizerConsume(pTokenizer);
1029 pVal = rtJsonValueCreate(RTJSONVALTYPE_OBJECT);
1030 if (RT_LIKELY(pVal))
1031 rc = rtJsonParseObject(pTokenizer, pVal, pErrInfo);
1032 break;
1033 case RTJSONTOKENCLASS_STRING:
1034 pVal = rtJsonValueCreate(RTJSONVALTYPE_STRING);
1035 if (RT_LIKELY(pVal))
1036 pVal->Type.String.pszStr = pToken->Class.String.pszStr;
1037 rtJsonTokenizerConsume(pTokenizer);
1038 break;
1039 case RTJSONTOKENCLASS_NUMBER:
1040 pVal = rtJsonValueCreate(RTJSONVALTYPE_NUMBER);
1041 if (RT_LIKELY(pVal))
1042 pVal->Type.Number.i64Num = pToken->Class.Number.i64Num;
1043 rtJsonTokenizerConsume(pTokenizer);
1044 break;
1045 case RTJSONTOKENCLASS_NULL:
1046 rtJsonTokenizerConsume(pTokenizer);
1047 pVal = rtJsonValueCreate(RTJSONVALTYPE_NULL);
1048 break;
1049 case RTJSONTOKENCLASS_FALSE:
1050 rtJsonTokenizerConsume(pTokenizer);
1051 pVal = rtJsonValueCreate(RTJSONVALTYPE_FALSE);
1052 break;
1053 case RTJSONTOKENCLASS_TRUE:
1054 rtJsonTokenizerConsume(pTokenizer);
1055 pVal = rtJsonValueCreate(RTJSONVALTYPE_TRUE);
1056 break;
1057 case RTJSONTOKENCLASS_END_ARRAY:
1058 case RTJSONTOKENCLASS_END_OBJECT:
1059 case RTJSONTOKENCLASS_NAME_SEPARATOR:
1060 case RTJSONTOKENCLASS_VALUE_SEPARATOR:
1061 case RTJSONTOKENCLASS_EOS:
1062 default:
1063 /** @todo: Error info */
1064 rc = VERR_JSON_MALFORMED;
1065 break;
1066 }
1067
1068 if (RT_SUCCESS(rc))
1069 {
1070 if (pVal)
1071 *ppJsonVal = pVal;
1072 else
1073 rc = VERR_NO_MEMORY;
1074 }
1075 else if (pVal)
1076 rtJsonValDestroy(pVal);
1077
1078 return rc;
1079}
1080
1081/**
1082 * Entry point to parse a JSON document.
1083 *
1084 * @returns IPRT status code.
1085 * @param pTokenizer The tokenizer state.
1086 * @param ppJsonVal Where to store the root JSON value on success.
1087 * @param pErrInfo Where to store extended error info. Optional.
1088 */
1089static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal,
1090 PRTERRINFO pErrInfo)
1091{
1092 PRTJSONTOKEN pToken = NULL;
1093 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1094 if (RT_SUCCESS(rc))
1095 rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal, pErrInfo);
1096
1097 return rc;
1098}
1099
1100/**
1101 * Read callback for RTJsonParseFromBuf().
1102 */
1103static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, size_t offInput,
1104 void *pvBuf, size_t cbBuf,
1105 size_t *pcbRead)
1106{
1107 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1108 size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0;
1109
1110 if (cbLeft)
1111 memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf));
1112
1113 *pcbRead = RT_MIN(cbLeft, cbBuf);
1114
1115 return VINF_SUCCESS;
1116}
1117
1118/**
1119 * Read callback for RTJsonParseFromString().
1120 */
1121static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, size_t offInput,
1122 void *pvBuf, size_t cbBuf,
1123 size_t *pcbRead)
1124{
1125 const char *pszStr = (const char *)pvUser;
1126 size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */
1127 size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0;
1128
1129 if (cbLeft)
1130 memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf));
1131
1132 *pcbRead = RT_MIN(cbLeft, cbBuf);
1133
1134 return VINF_SUCCESS;
1135}
1136
1137/**
1138 * Read callback for RTJsonParseFromFile().
1139 */
1140static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, size_t offInput,
1141 void *pvBuf, size_t cbBuf,
1142 size_t *pcbRead)
1143{
1144 int rc = VINF_SUCCESS;
1145 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1146 size_t cbRead = 0;
1147
1148 rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead);
1149 if (RT_SUCCESS(rc))
1150 *pcbRead = cbRead;
1151
1152 return rc;
1153}
1154
1155RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf,
1156 PRTERRINFO pErrInfo)
1157{
1158 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1159 AssertPtrReturn(pbBuf, VERR_INVALID_POINTER);
1160 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
1161
1162 int rc = VINF_SUCCESS;
1163 RTJSONREADERARGS Args;
1164 RTJSONTOKENIZER Tokenizer;
1165
1166 Args.cbData = cbBuf;
1167 Args.u.pbBuf = pbBuf;
1168
1169 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromBuf, &Args);
1170 if (RT_SUCCESS(rc))
1171 {
1172 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1173 rtJsonTokenizerDestroy(&Tokenizer);
1174 }
1175
1176 return rc;
1177}
1178
1179RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo)
1180{
1181 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1182 AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
1183
1184 int rc = VINF_SUCCESS;
1185 RTJSONTOKENIZER Tokenizer;
1186
1187 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromString, (void *)pszStr);
1188 if (RT_SUCCESS(rc))
1189 {
1190 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1191 rtJsonTokenizerDestroy(&Tokenizer);
1192 }
1193
1194 return rc;
1195}
1196
1197RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo)
1198{
1199 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1200 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1201
1202 int rc = VINF_SUCCESS;
1203 RTJSONREADERARGS Args;
1204
1205 Args.cbData = 0;
1206 rc = RTStrmOpen(pszFilename, "r", &Args.u.hStream);
1207 if (RT_SUCCESS(rc))
1208 {
1209 RTJSONTOKENIZER Tokenizer;
1210
1211 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromFile, &Args);
1212 if (RT_SUCCESS(rc))
1213 {
1214 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1215 rtJsonTokenizerDestroy(&Tokenizer);
1216 }
1217 RTStrmClose(Args.u.hStream);
1218 }
1219
1220 return rc;
1221}
1222
1223RTDECL(uint32_t) RTJsonValueRetain(RTJSONVAL hJsonVal)
1224{
1225 PRTJSONVALINT pThis = hJsonVal;
1226 AssertPtrReturn(pThis, UINT32_MAX);
1227
1228 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1229 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1230 return cRefs;
1231}
1232
1233RTDECL(uint32_t) RTJsonValueRelease(RTJSONVAL hJsonVal)
1234{
1235 PRTJSONVALINT pThis = hJsonVal;
1236 if (pThis == NIL_RTJSONVAL)
1237 return 0;
1238 AssertPtrReturn(pThis, UINT32_MAX);
1239
1240 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1241 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1242 if (cRefs == 0)
1243 rtJsonValDestroy(pThis);
1244 return cRefs;
1245}
1246
1247RTDECL(RTJSONVALTYPE) RTJsonValueGetType(RTJSONVAL hJsonVal)
1248{
1249 PRTJSONVALINT pThis = hJsonVal;
1250 if (pThis == NIL_RTJSONVAL)
1251 return RTJSONVALTYPE_INVALID;
1252 AssertPtrReturn(pThis, RTJSONVALTYPE_INVALID);
1253
1254 return pThis->enmType;
1255}
1256
1257RTDECL(const char *) RTJsonValueGetString(RTJSONVAL hJsonVal)
1258{
1259 PRTJSONVALINT pThis = hJsonVal;
1260 AssertReturn(pThis != NIL_RTJSONVAL, NULL);
1261 AssertReturn(pThis->enmType == RTJSONVALTYPE_STRING, NULL);
1262
1263 return pThis->Type.String.pszStr;
1264}
1265
1266RTDECL(int) RTJsonValueQueryString(RTJSONVAL hJsonVal, const char **ppszStr)
1267{
1268 PRTJSONVALINT pThis = hJsonVal;
1269 AssertPtrReturn(ppszStr, VERR_INVALID_POINTER);
1270 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1271 AssertReturn(pThis->enmType == RTJSONVALTYPE_STRING, VERR_JSON_VALUE_INVALID_TYPE);
1272
1273 *ppszStr = pThis->Type.String.pszStr;
1274 return VINF_SUCCESS;
1275}
1276
1277RTDECL(int) RTJsonValueQueryInteger(RTJSONVAL hJsonVal, int64_t *pi64Num)
1278{
1279 PRTJSONVALINT pThis = hJsonVal;
1280 AssertPtrReturn(pi64Num, VERR_INVALID_POINTER);
1281 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1282 AssertReturn(pThis->enmType == RTJSONVALTYPE_NUMBER, VERR_JSON_VALUE_INVALID_TYPE);
1283
1284 *pi64Num = pThis->Type.Number.i64Num;
1285 return VINF_SUCCESS;
1286}
1287
1288RTDECL(int) RTJsonValueQueryByName(RTJSONVAL hJsonVal, const char *pszName, PRTJSONVAL phJsonVal)
1289{
1290 PRTJSONVALINT pThis = hJsonVal;
1291 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1292 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1293 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1294 AssertReturn(pThis->enmType == RTJSONVALTYPE_OBJECT, VERR_JSON_VALUE_INVALID_TYPE);
1295
1296 int rc = VERR_NOT_FOUND;
1297 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
1298 {
1299 if (!RTStrCmp(pThis->Type.Object.papszNames[i], pszName))
1300 {
1301 RTJsonValueRetain(pThis->Type.Object.papValues[i]);
1302 *phJsonVal = pThis->Type.Object.papValues[i];
1303 rc = VINF_SUCCESS;
1304 break;
1305 }
1306 }
1307
1308 return rc;
1309}
1310
1311RTDECL(int) RTJsonValueQueryIntegerByName(RTJSONVAL hJsonVal, const char *pszName, int64_t *pi64Num)
1312{
1313 RTJSONVAL hJsonValNum = NIL_RTJSONVAL;
1314 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValNum);
1315 if (RT_SUCCESS(rc))
1316 {
1317 rc = RTJsonValueQueryInteger(hJsonValNum, pi64Num);
1318 RTJsonValueRelease(hJsonValNum);
1319 }
1320
1321 return rc;
1322}
1323
1324RTDECL(int) RTJsonValueQueryStringByName(RTJSONVAL hJsonVal, const char *pszName, char **ppszStr)
1325{
1326 RTJSONVAL hJsonValStr = NIL_RTJSONVAL;
1327 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValStr);
1328 if (RT_SUCCESS(rc))
1329 {
1330 const char *pszStr = NULL;
1331 rc = RTJsonValueQueryString(hJsonValStr, &pszStr);
1332 if (RT_SUCCESS(rc))
1333 {
1334 *ppszStr = RTStrDup(pszStr);
1335 if (!*ppszStr)
1336 rc = VERR_NO_STR_MEMORY;
1337 }
1338 RTJsonValueRelease(hJsonValStr);
1339 }
1340
1341 return rc;
1342}
1343
1344RTDECL(int) RTJsonValueQueryBooleanByName(RTJSONVAL hJsonVal, const char *pszName, bool *pfBoolean)
1345{
1346 AssertPtrReturn(pfBoolean, VERR_INVALID_POINTER);
1347
1348 RTJSONVAL hJsonValBool = NIL_RTJSONVAL;
1349 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValBool);
1350 if (RT_SUCCESS(rc))
1351 {
1352 RTJSONVALTYPE enmType = RTJsonValueGetType(hJsonValBool);
1353 if (enmType == RTJSONVALTYPE_TRUE)
1354 *pfBoolean = true;
1355 else if (enmType == RTJSONVALTYPE_FALSE)
1356 *pfBoolean = false;
1357 else
1358 rc = VERR_JSON_VALUE_INVALID_TYPE;
1359 RTJsonValueRelease(hJsonValBool);
1360 }
1361
1362 return rc;
1363}
1364
1365RTDECL(unsigned) RTJsonValueGetArraySize(RTJSONVAL hJsonVal)
1366{
1367 PRTJSONVALINT pThis = hJsonVal;
1368 AssertReturn(pThis != NIL_RTJSONVAL, 0);
1369 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, 0);
1370
1371 return pThis->Type.Array.cItems;
1372}
1373
1374RTDECL(int) RTJsonValueQueryArraySize(RTJSONVAL hJsonVal, unsigned *pcItems)
1375{
1376 PRTJSONVALINT pThis = hJsonVal;
1377 AssertPtrReturn(pcItems, VERR_INVALID_POINTER);
1378 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1379 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, VERR_JSON_VALUE_INVALID_TYPE);
1380
1381 *pcItems = pThis->Type.Array.cItems;
1382 return VINF_SUCCESS;
1383}
1384
1385RTDECL(int) RTJsonValueQueryByIndex(RTJSONVAL hJsonVal, unsigned idx, PRTJSONVAL phJsonVal)
1386{
1387 PRTJSONVALINT pThis = hJsonVal;
1388 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1389 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1390 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, VERR_JSON_VALUE_INVALID_TYPE);
1391 AssertReturn(idx < pThis->Type.Array.cItems, VERR_OUT_OF_RANGE);
1392
1393 RTJsonValueRetain(pThis->Type.Array.papItems[idx]);
1394 *phJsonVal = pThis->Type.Array.papItems[idx];
1395 return VINF_SUCCESS;
1396}
1397
1398RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1399{
1400 PRTJSONVALINT pThis = hJsonVal;
1401 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1402 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1403 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY || pThis->enmType == RTJSONVALTYPE_OBJECT,
1404 VERR_JSON_VALUE_INVALID_TYPE);
1405
1406 PRTJSONITINT pIt = (PRTJSONITINT)RTMemTmpAllocZ(sizeof(RTJSONITINT));
1407 if (RT_UNLIKELY(!pIt))
1408 return VERR_NO_MEMORY;
1409
1410 RTJsonValueRetain(hJsonVal);
1411 pIt->pJsonVal = pThis;
1412 pIt->idxCur = 0;
1413 *phJsonIt = pIt;
1414
1415 return VINF_SUCCESS;
1416}
1417
1418RTDECL(int) RTJsonIteratorQueryValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName)
1419{
1420 PRTJSONITINT pIt = hJsonIt;
1421 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1422 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1423
1424 int rc = VINF_SUCCESS;
1425 PRTJSONVALINT pThis = pIt->pJsonVal;
1426 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1427 {
1428 if (pIt->idxCur < pThis->Type.Array.cItems)
1429 {
1430 if (ppszName)
1431 *ppszName = NULL;
1432
1433 RTJsonValueRetain(pThis->Type.Array.papItems[pIt->idxCur]);
1434 *phJsonVal = pThis->Type.Array.papItems[pIt->idxCur];
1435 }
1436 else
1437 rc = VERR_JSON_ITERATOR_END;
1438 }
1439 else
1440 {
1441 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1442
1443 if (pIt->idxCur < pThis->Type.Object.cMembers)
1444 {
1445 if (ppszName)
1446 *ppszName = pThis->Type.Object.papszNames[pIt->idxCur];
1447
1448 RTJsonValueRetain(pThis->Type.Object.papValues[pIt->idxCur]);
1449 *phJsonVal = pThis->Type.Object.papValues[pIt->idxCur];
1450 }
1451 else
1452 rc = VERR_JSON_ITERATOR_END;
1453 }
1454
1455 return rc;
1456}
1457
1458RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt)
1459{
1460 PRTJSONITINT pIt = hJsonIt;
1461 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1462
1463 int rc = VINF_SUCCESS;
1464 PRTJSONVALINT pThis = pIt->pJsonVal;
1465 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1466 {
1467 if (pIt->idxCur < pThis->Type.Array.cItems)
1468 pIt->idxCur++;
1469
1470 if (pIt->idxCur == pThis->Type.Object.cMembers)
1471 rc = VERR_JSON_ITERATOR_END;
1472 }
1473 else
1474 {
1475 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1476
1477 if (pIt->idxCur < pThis->Type.Object.cMembers)
1478 pIt->idxCur++;
1479
1480 if (pIt->idxCur == pThis->Type.Object.cMembers)
1481 rc = VERR_JSON_ITERATOR_END;
1482 }
1483
1484 return rc;
1485}
1486
1487RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt)
1488{
1489 PRTJSONITINT pThis = hJsonIt;
1490 if (pThis == NIL_RTJSONIT)
1491 return;
1492 AssertPtrReturnVoid(pThis);
1493
1494 RTJsonValueRelease(pThis->pJsonVal);
1495 RTMemTmpFree(pThis);
1496}
1497
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