VirtualBox

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

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

Runtime/RTJson: Fix review todos

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.8 KB
Line 
1/* $Id: json.cpp 62021 2016-07-05 09:34:17Z 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* Structures and Typedefs *
42*********************************************************************************************************************************/
43
44/**
45 * JSON parser position information.
46 */
47typedef struct RTJSONPOS
48{
49 /** Line in the source. */
50 size_t iLine;
51 /** Current start character .*/
52 size_t iChStart;
53 /** Current end character. */
54 size_t iChEnd;
55} RTJSONPOS;
56/** Pointer to a position. */
57typedef RTJSONPOS *PRTJSONPOS;
58
59/**
60 * JSON token class.
61 */
62typedef enum RTJSONTOKENCLASS
63{
64 /** Invalid. */
65 RTJSONTOKENCLASS_INVALID = 0,
66 /** Array begin. */
67 RTJSONTOKENCLASS_BEGIN_ARRAY,
68 /** Object begin. */
69 RTJSONTOKENCLASS_BEGIN_OBJECT,
70 /** Array end. */
71 RTJSONTOKENCLASS_END_ARRAY,
72 /** Object end. */
73 RTJSONTOKENCLASS_END_OBJECT,
74 /** Separator for name/value pairs. */
75 RTJSONTOKENCLASS_NAME_SEPARATOR,
76 /** Value separator. */
77 RTJSONTOKENCLASS_VALUE_SEPARATOR,
78 /** String */
79 RTJSONTOKENCLASS_STRING,
80 /** Number. */
81 RTJSONTOKENCLASS_NUMBER,
82 /** null keyword. */
83 RTJSONTOKENCLASS_NULL,
84 /** false keyword. */
85 RTJSONTOKENCLASS_FALSE,
86 /** true keyword. */
87 RTJSONTOKENCLASS_TRUE,
88 /** End of stream */
89 RTJSONTOKENCLASS_EOS,
90 /** 32bit hack. */
91 RTJSONTOKENCLASS_32BIT_HACK = 0x7fffffff
92} RTJSONTOKENCLASS;
93/** Pointer to a token class. */
94typedef RTJSONTOKENCLASS *PRTJSONTOKENCLASS;
95
96/**
97 * JSON token.
98 */
99typedef struct RTJSONTOKEN
100{
101 /** Token class. */
102 RTJSONTOKENCLASS enmClass;
103 /** Token position in the source buffer. */
104 RTJSONPOS Pos;
105 /** Data based on the token class. */
106 union
107 {
108 /** String. */
109 struct
110 {
111 /** Pointer to the start of the string. */
112 char *pszStr;
113 } String;
114 /** Number. */
115 struct
116 {
117 int64_t i64Num;
118 } Number;
119 } Class;
120} RTJSONTOKEN;
121/** Pointer to a JSON token. */
122typedef RTJSONTOKEN *PRTJSONTOKEN;
123/** Pointer to a const script token. */
124typedef const RTJSONTOKEN *PCRTJSONTOKEN;
125
126/**
127 * Tokenizer read input callback.
128 *
129 * @returns IPRT status code.
130 * @param pvUser Opaque user data for the callee.
131 * @param offInput Start offset from the start of the input stream to read from.
132 * @param pvBuf Where to store the read data.
133 * @param cbBuf How much to read.
134 * @param pcbRead Where to store the amount of data read on succcess.
135 */
136typedef DECLCALLBACK(int) FNRTJSONTOKENIZERREAD(void *pvUser, size_t offInput, void *pvBuf, size_t cbBuf,
137 size_t *pcbRead);
138/** Pointer to a tokenizer read buffer callback. */
139typedef FNRTJSONTOKENIZERREAD *PFNRTJSONTOKENIZERREAD;
140
141/**
142 * Tokenizer state.
143 */
144typedef struct RTJSONTOKENIZER
145{
146 /** Read callback. */
147 PFNRTJSONTOKENIZERREAD pfnRead;
148 /** Opaque user data. */
149 void *pvUser;
150 /** Current offset into the input stream. */
151 size_t offInput;
152 /** Number of valid bytes in the input buffer. */
153 size_t cbBuf;
154 /* Current offset into the input buffer. */
155 size_t offBuf;
156 /** Input cache buffer. */
157 char achBuf[512];
158 /** Current position into the input stream. */
159 RTJSONPOS Pos;
160 /** Token 1. */
161 RTJSONTOKEN Token1;
162 /** Token 2. */
163 RTJSONTOKEN Token2;
164 /** Pointer to the current active token. */
165 PRTJSONTOKEN pTokenCurr;
166 /** The next token in the input stream (used for peeking). */
167 PRTJSONTOKEN pTokenNext;
168} RTJSONTOKENIZER;
169/** Pointer to a JSON tokenizer. */
170typedef RTJSONTOKENIZER *PRTJSONTOKENIZER;
171
172/** Pointer to the internal JSON value instance. */
173typedef struct RTJSONVALINT *PRTJSONVALINT;
174
175/**
176 * A JSON value.
177 */
178typedef struct RTJSONVALINT
179{
180 /** Type of the JSON value. */
181 RTJSONVALTYPE enmType;
182 /** Reference count for this JSON value. */
183 volatile uint32_t cRefs;
184 /** Type dependent data. */
185 union
186 {
187 /** String type*/
188 struct
189 {
190 /** Pointer to the string. */
191 char *pszStr;
192 } String;
193 /** Number type. */
194 struct
195 {
196 /** Signed 64-bit integer. */
197 int64_t i64Num;
198 } Number;
199 /** Array type. */
200 struct
201 {
202 /** Number of elements in the array. */
203 unsigned cItems;
204 /** Pointer to the array of items. */
205 PRTJSONVALINT *papItems;
206 } Array;
207 /** Object type. */
208 struct
209 {
210 /** Number of members. */
211 unsigned cMembers;
212 /** Pointer to the array holding the member names. */
213 char **papszNames;
214 /** Pointer to the array holding the values. */
215 PRTJSONVALINT *papValues;
216 } Object;
217 } Type;
218} RTJSONVALINT;
219
220/**
221 * A JSON iterator.
222 */
223typedef struct RTJSONITINT
224{
225 /** Referenced JSON value. */
226 PRTJSONVALINT pJsonVal;
227 /** Current index. */
228 unsigned idxCur;
229} RTJSONITINT;
230/** Pointer to the internal JSON iterator instance. */
231typedef RTJSONITINT *PRTJSONITINT;
232
233/**
234 * Passing arguments for the read callbacks.
235 */
236typedef struct RTJSONREADERARGS
237{
238 /** Buffer/File size */
239 size_t cbData;
240 /** Data specific for one callback. */
241 union
242 {
243 PRTSTREAM hStream;
244 const uint8_t *pbBuf;
245 } u;
246} RTJSONREADERARGS;
247/** Pointer to a readers argument. */
248typedef RTJSONREADERARGS *PRTJSONREADERARGS;
249
250/*********************************************************************************************************************************
251* Global variables *
252*********************************************************************************************************************************/
253
254static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken,
255 PRTJSONVALINT *ppJsonVal, PRTERRINFO pErrInfo);
256
257/**
258 * Fill the input buffer from the input stream.
259 *
260 * @returns IPRT status code.
261 * @param pTokenizer The tokenizer state.
262 */
263static int rtJsonTokenizerRead(PRTJSONTOKENIZER pTokenizer)
264{
265 size_t cbRead = 0;
266 int rc = pTokenizer->pfnRead(pTokenizer->pvUser, pTokenizer->offInput, &pTokenizer->achBuf[0],
267 sizeof(pTokenizer->achBuf), &cbRead);
268 if (RT_SUCCESS(rc))
269 {
270 pTokenizer->cbBuf = cbRead;
271 pTokenizer->offInput += cbRead;
272 pTokenizer->offBuf = 0;
273 /* Validate UTF-8 encoding. */
274 rc = RTStrValidateEncodingEx(&pTokenizer->achBuf[0], cbRead, 0 /* fFlags */);
275 /* If we read less than requested we reached the end and fill the remainder with terminators. */
276 if (cbRead < sizeof(pTokenizer->achBuf))
277 memset(&pTokenizer->achBuf[cbRead], 0, sizeof(pTokenizer->achBuf) - cbRead);
278 }
279
280 return rc;
281}
282
283/**
284 * Skips the given amount of characters in the input stream.
285 *
286 * @returns IPRT status code.
287 * @param pTokenizer The tokenizer state.
288 * @param cchSkip The amount of characters to skip.
289 */
290static int rtJsonTokenizerSkip(PRTJSONTOKENIZER pTokenizer, size_t cchSkip)
291{
292 int rc = VINF_SUCCESS;
293
294 /*
295 * In case we reached the end of the stream don't even attempt to read new data.
296 * Safety precaution for possible bugs in the parser causing out of bounds reads
297 */
298 if (pTokenizer->achBuf[pTokenizer->offBuf] == '\0')
299 return rc;
300
301 while ( cchSkip > 0
302 && pTokenizer->offBuf < pTokenizer->cbBuf
303 && RT_SUCCESS(rc))
304 {
305 size_t cchThisSkip = RT_MIN(cchSkip, pTokenizer->cbBuf - pTokenizer->offBuf);
306
307 pTokenizer->offBuf += cchThisSkip;
308 /* Read new data if required and we didn't reach the end yet. */
309 if ( pTokenizer->offBuf == pTokenizer->cbBuf
310 && pTokenizer->cbBuf == sizeof(pTokenizer->achBuf))
311 rc = rtJsonTokenizerRead(pTokenizer);
312
313 cchSkip -= cchThisSkip;
314 }
315
316 return rc;
317}
318
319
320/**
321 * Returns whether the tokenizer reached the end of the stream.
322 *
323 * @returns true if the tokenizer reached the end of stream marker
324 * false otherwise.
325 * @param pTokenizer The tokenizer state.
326 */
327DECLINLINE(bool) rtJsonTokenizerIsEos(PRTJSONTOKENIZER pTokenizer)
328{
329 return pTokenizer->achBuf[pTokenizer->offBuf] == '\0';
330}
331
332/**
333 * Skip one character in the input stream.
334 *
335 * @returns nothing.
336 * @param pTokenizer The tokenizer state.
337 */
338DECLINLINE(void) rtJsonTokenizerSkipCh(PRTJSONTOKENIZER pTokenizer)
339{
340 rtJsonTokenizerSkip(pTokenizer, 1);
341 pTokenizer->Pos.iChStart++;
342 pTokenizer->Pos.iChEnd++;
343}
344
345/**
346 * Returns the next char in the input buffer without advancing it.
347 *
348 * @returns Next character in the input buffer.
349 * @param pTokenizer The tokenizer state.
350 */
351DECLINLINE(char) rtJsonTokenizerPeekCh(PRTJSONTOKENIZER pTokenizer)
352{
353 return rtJsonTokenizerIsEos(pTokenizer)
354 ? '\0'
355 : pTokenizer->achBuf[pTokenizer->offBuf + 1]; /** @todo: Read out of bounds */
356}
357
358/**
359 * Returns the next character in the input buffer advancing the internal
360 * position.
361 *
362 * @returns Next character in the stream.
363 * @param pTokenizer The tokenizer state.
364 */
365DECLINLINE(char) rtJsonTokenizerGetCh(PRTJSONTOKENIZER pTokenizer)
366{
367 char ch;
368
369 if (rtJsonTokenizerIsEos(pTokenizer))
370 ch = '\0';
371 else
372 ch = pTokenizer->achBuf[pTokenizer->offBuf];
373
374 return ch;
375}
376
377/**
378 * Sets a new line for the tokenizer.
379 *
380 * @returns nothing.
381 * @param pTokenizer The tokenizer state.
382 * @param cSkip Amount of characters to skip making up the new line.
383 */
384DECLINLINE(void) rtJsonTokenizerNewLine(PRTJSONTOKENIZER pTokenizer, unsigned cSkip)
385{
386 rtJsonTokenizerSkip(pTokenizer, cSkip);
387 pTokenizer->Pos.iLine++;
388 pTokenizer->Pos.iChStart = 1;
389 pTokenizer->Pos.iChEnd = 1;
390}
391
392/**
393 * Checks whether the current position in the input stream is a new line
394 * and skips it.
395 *
396 * @returns Flag whether there was a new line at the current position
397 * in the input buffer.
398 * @param pTokenizer The tokenizer state.
399 */
400DECLINLINE(bool) rtJsonTokenizerIsSkipNewLine(PRTJSONTOKENIZER pTokenizer)
401{
402 bool fNewline = true;
403
404 if ( rtJsonTokenizerGetCh(pTokenizer) == '\r'
405 && rtJsonTokenizerPeekCh(pTokenizer) == '\n')
406 rtJsonTokenizerNewLine(pTokenizer, 2);
407 else if (rtJsonTokenizerGetCh(pTokenizer) == '\n')
408 rtJsonTokenizerNewLine(pTokenizer, 1);
409 else
410 fNewline = false;
411
412 return fNewline;
413}
414
415/**
416 * Skip all whitespace starting from the current input buffer position.
417 * Skips all present comments too.
418 *
419 * @returns nothing.
420 * @param pTokenizer The tokenizer state.
421 */
422DECLINLINE(void) rtJsonTokenizerSkipWhitespace(PRTJSONTOKENIZER pTokenizer)
423{
424 while (!rtJsonTokenizerIsEos(pTokenizer))
425 {
426 while ( rtJsonTokenizerGetCh(pTokenizer) == ' '
427 || rtJsonTokenizerGetCh(pTokenizer) == '\t')
428 rtJsonTokenizerSkipCh(pTokenizer);
429
430 if ( !rtJsonTokenizerIsEos(pTokenizer)
431 && !rtJsonTokenizerIsSkipNewLine(pTokenizer))
432 {
433 break; /* Skipped everything, next is some real content. */
434 }
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 aszLiteral[6]; /* false + 0 terminator as the lingest possible literal. */
451 RT_ZERO(aszLiteral);
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(aszLiteral) - 1)
459 {
460 aszLiteral[cchLiteral] = ch;
461 cchLiteral++;
462 rtJsonTokenizerSkipCh(pTokenizer);
463 ch = rtJsonTokenizerGetCh(pTokenizer);
464 }
465
466 if (!RTStrNCmp(&aszLiteral[0], "false", RT_ELEMENTS(aszLiteral)))
467 pToken->enmClass = RTJSONTOKENCLASS_FALSE;
468 else if (!RTStrNCmp(&aszLiteral[0], "true", RT_ELEMENTS(aszLiteral)))
469 pToken->enmClass = RTJSONTOKENCLASS_TRUE;
470 else if (!RTStrNCmp(&aszLiteral[0], "null", RT_ELEMENTS(aszLiteral)))
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 unsigned uBase = 10;
492 char *pszNext = NULL;
493 size_t cchNum = 0;
494 char aszTmp[128]; /* Everything larger is not possible to display in signed 64bit. */
495 RT_ZERO(aszTmp);
496
497 pToken->enmClass = RTJSONTOKENCLASS_NUMBER;
498
499 char ch = rtJsonTokenizerGetCh(pTokenizer);
500 while ( RT_C_IS_DIGIT(ch)
501 && cchNum < sizeof(aszTmp) - 1)
502 {
503 aszTmp[cchNum] = ch;
504 cchNum++;
505 rtJsonTokenizerSkipCh(pTokenizer);
506 ch = rtJsonTokenizerGetCh(pTokenizer);
507 }
508
509 int rc = VINF_SUCCESS;
510 if (RT_C_IS_DIGIT(ch) && cchNum == sizeof(aszTmp) - 1)
511 rc = VERR_NUMBER_TOO_BIG;
512 else
513 {
514 rc = RTStrToInt64Ex(&aszTmp[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 aszTmp[_4K];
535 RT_ZERO(aszTmp);
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(aszTmp) - 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 aszTmp[cchStr] = '\"';
557 break;
558 case '\\':
559 aszTmp[cchStr] = '\\';
560 break;
561 case '/':
562 aszTmp[cchStr] = '/';
563 break;
564 case '\b':
565 aszTmp[cchStr] = '\b';
566 break;
567 case '\n':
568 aszTmp[cchStr] = '\n';
569 break;
570 case '\f':
571 aszTmp[cchStr] = '\f';
572 break;
573 case '\r':
574 aszTmp[cchStr] = '\r';
575 break;
576 case '\t':
577 aszTmp[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 aszTmp[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(&aszTmp[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