VirtualBox

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

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

IPRT/rest: Added RTJsonIteratorBeginArray and RTJsonIteratorBeginObject for more accurate JSON decoding. Early RTCRestArray implementation. bugref:9167

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.3 KB
Line 
1/* $Id: json.cpp 73956 2018-08-29 15:09:34Z 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 /** The tokenizer error state. */
170 int rcTok;
171} RTJSONTOKENIZER;
172/** Pointer to a JSON tokenizer. */
173typedef RTJSONTOKENIZER *PRTJSONTOKENIZER;
174
175/** Pointer to the internal JSON value instance. */
176typedef struct RTJSONVALINT *PRTJSONVALINT;
177
178/**
179 * A JSON value.
180 */
181typedef struct RTJSONVALINT
182{
183 /** Type of the JSON value. */
184 RTJSONVALTYPE enmType;
185 /** Reference count for this JSON value. */
186 volatile uint32_t cRefs;
187 /** Type dependent data. */
188 union
189 {
190 /** String type*/
191 struct
192 {
193 /** Pointer to the string. */
194 char *pszStr;
195 } String;
196 /** Number type. */
197 struct
198 {
199 /** Signed 64-bit integer. */
200 int64_t i64Num;
201 } Number;
202 /** Array type. */
203 struct
204 {
205 /** Number of elements in the array. */
206 unsigned cItems;
207 /** Pointer to the array of items. */
208 PRTJSONVALINT *papItems;
209 } Array;
210 /** Object type. */
211 struct
212 {
213 /** Number of members. */
214 unsigned cMembers;
215 /** Pointer to the array holding the member names. */
216 char **papszNames;
217 /** Pointer to the array holding the values. */
218 PRTJSONVALINT *papValues;
219 } Object;
220 } Type;
221} RTJSONVALINT;
222
223/**
224 * A JSON iterator.
225 */
226typedef struct RTJSONITINT
227{
228 /** Referenced JSON value. */
229 PRTJSONVALINT pJsonVal;
230 /** Current index. */
231 unsigned idxCur;
232} RTJSONITINT;
233/** Pointer to the internal JSON iterator instance. */
234typedef RTJSONITINT *PRTJSONITINT;
235
236/**
237 * Passing arguments for the read callbacks.
238 */
239typedef struct RTJSONREADERARGS
240{
241 /** Buffer/File size */
242 size_t cbData;
243 /** Data specific for one callback. */
244 union
245 {
246 PRTSTREAM hStream;
247 const uint8_t *pbBuf;
248 } u;
249} RTJSONREADERARGS;
250/** Pointer to a readers argument. */
251typedef RTJSONREADERARGS *PRTJSONREADERARGS;
252
253
254/*********************************************************************************************************************************
255* Global variables *
256*********************************************************************************************************************************/
257
258static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken,
259 PRTJSONVALINT *ppJsonVal, PRTERRINFO pErrInfo);
260
261/**
262 * Fill the input buffer from the input stream.
263 *
264 * @returns IPRT status code.
265 * @param pTokenizer The tokenizer state.
266 */
267static int rtJsonTokenizerRead(PRTJSONTOKENIZER pTokenizer)
268{
269 size_t cbRead = 0;
270 int rc = pTokenizer->pfnRead(pTokenizer->pvUser, pTokenizer->offInput, &pTokenizer->achBuf[0],
271 sizeof(pTokenizer->achBuf), &cbRead);
272 if (RT_SUCCESS(rc))
273 {
274 pTokenizer->cbBuf = cbRead;
275 pTokenizer->offInput += cbRead;
276 pTokenizer->offBuf = 0;
277 /* Validate UTF-8 encoding. */
278 rc = RTStrValidateEncodingEx(&pTokenizer->achBuf[0], cbRead, 0 /* fFlags */);
279 /* If we read less than requested we reached the end and fill the remainder with terminators. */
280 if (cbRead < sizeof(pTokenizer->achBuf))
281 memset(&pTokenizer->achBuf[cbRead], 0, sizeof(pTokenizer->achBuf) - cbRead);
282 }
283
284 return rc;
285}
286
287/**
288 * Skips the given amount of characters in the input stream.
289 *
290 * @returns IPRT status code.
291 * @param pTokenizer The tokenizer state.
292 * @param cchSkip The amount of characters to skip.
293 */
294static int rtJsonTokenizerSkip(PRTJSONTOKENIZER pTokenizer, size_t cchSkip)
295{
296 int rc = VINF_SUCCESS;
297
298 /*
299 * In case we reached the end of the stream don't even attempt to read new data.
300 * Safety precaution for possible bugs in the parser causing out of bounds reads
301 */
302 if (pTokenizer->achBuf[pTokenizer->offBuf] == '\0')
303 return rc;
304
305 while ( cchSkip > 0
306 && pTokenizer->offBuf < pTokenizer->cbBuf
307 && RT_SUCCESS(rc))
308 {
309 size_t cchThisSkip = RT_MIN(cchSkip, pTokenizer->cbBuf - pTokenizer->offBuf);
310
311 pTokenizer->offBuf += cchThisSkip;
312 /* Read new data if required and we didn't reach the end yet. */
313 if ( pTokenizer->offBuf == pTokenizer->cbBuf
314 && pTokenizer->cbBuf == sizeof(pTokenizer->achBuf))
315 rc = rtJsonTokenizerRead(pTokenizer);
316
317 cchSkip -= cchThisSkip;
318 }
319
320 return rc;
321}
322
323
324/**
325 * Returns whether the tokenizer reached the end of the stream.
326 *
327 * @returns true if the tokenizer reached the end of stream marker
328 * false otherwise.
329 * @param pTokenizer The tokenizer state.
330 */
331DECLINLINE(bool) rtJsonTokenizerIsEos(PRTJSONTOKENIZER pTokenizer)
332{
333 return pTokenizer->achBuf[pTokenizer->offBuf] == '\0';
334}
335
336/**
337 * Skip one character in the input stream.
338 *
339 * @returns nothing.
340 * @param pTokenizer The tokenizer state.
341 */
342DECLINLINE(void) rtJsonTokenizerSkipCh(PRTJSONTOKENIZER pTokenizer)
343{
344 rtJsonTokenizerSkip(pTokenizer, 1);
345 pTokenizer->Pos.iChStart++;
346 pTokenizer->Pos.iChEnd++;
347}
348
349/**
350 * Returns the next char in the input buffer without advancing it.
351 *
352 * @returns Next character in the input buffer.
353 * @param pTokenizer The tokenizer state.
354 */
355DECLINLINE(char) rtJsonTokenizerPeekCh(PRTJSONTOKENIZER pTokenizer)
356{
357 return rtJsonTokenizerIsEos(pTokenizer)
358 ? '\0'
359 : pTokenizer->achBuf[pTokenizer->offBuf + 1]; /** @todo Read out of bounds */
360}
361
362/**
363 * Returns the next character in the input buffer advancing the internal
364 * position.
365 *
366 * @returns Next character in the stream.
367 * @param pTokenizer The tokenizer state.
368 */
369DECLINLINE(char) rtJsonTokenizerGetCh(PRTJSONTOKENIZER pTokenizer)
370{
371 char ch;
372
373 if (rtJsonTokenizerIsEos(pTokenizer))
374 ch = '\0';
375 else
376 ch = pTokenizer->achBuf[pTokenizer->offBuf];
377
378 return ch;
379}
380
381/**
382 * Sets a new line for the tokenizer.
383 *
384 * @returns nothing.
385 * @param pTokenizer The tokenizer state.
386 * @param cSkip Amount of characters to skip making up the new line.
387 */
388DECLINLINE(void) rtJsonTokenizerNewLine(PRTJSONTOKENIZER pTokenizer, unsigned cSkip)
389{
390 rtJsonTokenizerSkip(pTokenizer, cSkip);
391 pTokenizer->Pos.iLine++;
392 pTokenizer->Pos.iChStart = 1;
393 pTokenizer->Pos.iChEnd = 1;
394}
395
396/**
397 * Checks whether the current position in the input stream is a new line
398 * and skips it.
399 *
400 * @returns Flag whether there was a new line at the current position
401 * in the input buffer.
402 * @param pTokenizer The tokenizer state.
403 */
404DECLINLINE(bool) rtJsonTokenizerIsSkipNewLine(PRTJSONTOKENIZER pTokenizer)
405{
406 bool fNewline = true;
407
408 if ( rtJsonTokenizerGetCh(pTokenizer) == '\r'
409 && rtJsonTokenizerPeekCh(pTokenizer) == '\n')
410 rtJsonTokenizerNewLine(pTokenizer, 2);
411 else if (rtJsonTokenizerGetCh(pTokenizer) == '\n')
412 rtJsonTokenizerNewLine(pTokenizer, 1);
413 else
414 fNewline = false;
415
416 return fNewline;
417}
418
419/**
420 * Skip all whitespace starting from the current input buffer position.
421 * Skips all present comments too.
422 *
423 * @returns nothing.
424 * @param pTokenizer The tokenizer state.
425 */
426DECLINLINE(void) rtJsonTokenizerSkipWhitespace(PRTJSONTOKENIZER pTokenizer)
427{
428 while (!rtJsonTokenizerIsEos(pTokenizer))
429 {
430 while ( rtJsonTokenizerGetCh(pTokenizer) == ' '
431 || rtJsonTokenizerGetCh(pTokenizer) == '\t')
432 rtJsonTokenizerSkipCh(pTokenizer);
433
434 if ( !rtJsonTokenizerIsEos(pTokenizer)
435 && !rtJsonTokenizerIsSkipNewLine(pTokenizer))
436 break; /* Skipped everything, next is some real content. */
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 size_t cchStrMax = _4K;
535 char *pszTmp = (char *)RTMemAllocZ(cchStrMax * sizeof(char));
536 if (RT_UNLIKELY(!pszTmp))
537 return VERR_NO_STR_MEMORY;
538
539 RT_BZERO(pszTmp, cchStrMax);
540
541 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\"');
542 rtJsonTokenizerSkipCh(pTokenizer); /* Skip " */
543
544 pToken->enmClass = RTJSONTOKENCLASS_STRING;
545 pToken->Pos = pTokenizer->Pos;
546
547 char ch = rtJsonTokenizerGetCh(pTokenizer);
548 while ( ch != '\"'
549 && ch != '\0'
550 && RT_SUCCESS(rc))
551 {
552 if (ch == '\\')
553 {
554 /* Escape sequence, check the next character */
555 rtJsonTokenizerSkipCh(pTokenizer);
556 char chNext = rtJsonTokenizerGetCh(pTokenizer);
557 switch (chNext)
558 {
559 case '\"':
560 pszTmp[cchStr] = '\"';
561 break;
562 case '\\':
563 pszTmp[cchStr] = '\\';
564 break;
565 case '/':
566 pszTmp[cchStr] = '/';
567 break;
568 case '\b':
569 pszTmp[cchStr] = '\b';
570 break;
571 case '\n':
572 pszTmp[cchStr] = '\n';
573 break;
574 case '\f':
575 pszTmp[cchStr] = '\f';
576 break;
577 case '\r':
578 pszTmp[cchStr] = '\r';
579 break;
580 case '\t':
581 pszTmp[cchStr] = '\t';
582 break;
583 case 'u':
584 rc = VERR_NOT_SUPPORTED;
585 break;
586 default:
587 rc = VERR_JSON_MALFORMED;
588 }
589 }
590 else
591 pszTmp[cchStr] = ch;
592
593 if (RT_FAILURE(rc))
594 break;
595
596 cchStr++;
597 rtJsonTokenizerSkipCh(pTokenizer);
598 if (cchStr == cchStrMax - 1)
599 {
600 /* Increase string space. */
601 size_t cchStrMaxNew = cchStrMax + _4K;
602 char *pszTmpNew = (char *)RTMemRealloc(pszTmp, cchStrMaxNew * sizeof(char));
603 if (RT_UNLIKELY(!pszTmpNew))
604 {
605 rc = VERR_NO_STR_MEMORY;
606 break;
607 }
608
609 RT_BZERO(&pszTmpNew[cchStr], _4K);
610 pszTmp = pszTmpNew;
611 cchStrMax = cchStrMaxNew;
612 }
613 ch = rtJsonTokenizerGetCh(pTokenizer);
614 }
615
616 if (RT_SUCCESS(rc))
617 {
618 if (rtJsonTokenizerGetCh(pTokenizer) == '\"')
619 rtJsonTokenizerSkipCh(pTokenizer); /* Skip closing " */
620
621 pToken->Class.String.pszStr = RTStrDupN(pszTmp, cchStr);
622 if (pToken->Class.String.pszStr)
623 pToken->Pos.iChEnd += cchStr;
624 else
625 rc = VERR_NO_STR_MEMORY;
626 }
627
628 if (pszTmp)
629 RTMemFree(pszTmp);
630
631 return rc;
632}
633
634/**
635 * Get the end of stream token.
636 *
637 * @returns IPRT status code.
638 * @param pTokenizer The tokenizer state.
639 * @param pToken The uninitialized token.
640 */
641static int rtJsonTokenizerGetEos(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
642{
643 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\0');
644
645 pToken->enmClass = RTJSONTOKENCLASS_EOS;
646 pToken->Pos = pTokenizer->Pos;
647 return VINF_SUCCESS;
648}
649
650/**
651 * Read the next token from the tokenizer stream.
652 *
653 * @returns IPRT status code.
654 * @param pTokenizer The tokenizer to read from.
655 * @param pToken Uninitialized token to fill the token data into.
656 */
657static int rtJsonTokenizerReadNextToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
658{
659 int rc = VINF_SUCCESS;
660
661 /* Skip all eventually existing whitespace and newlines first. */
662 rtJsonTokenizerSkipWhitespace(pTokenizer);
663
664 char ch = rtJsonTokenizerGetCh(pTokenizer);
665 if (RT_C_IS_ALPHA(ch))
666 rc = rtJsonTokenizerGetLiteral(pTokenizer, pToken);
667 else if (RT_C_IS_DIGIT(ch))
668 rc = rtJsonTokenizerGetNumber(pTokenizer, pToken);
669 else if (ch == '\"')
670 rc = rtJsonTokenizerGetString(pTokenizer, pToken);
671 else if (ch == '\0')
672 rc = rtJsonTokenizerGetEos(pTokenizer, pToken);
673 else if (ch == '{')
674 {
675 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_OBJECT;
676 rtJsonTokenizerSkipCh(pTokenizer);
677 }
678 else if (ch == '}')
679 {
680 pToken->enmClass = RTJSONTOKENCLASS_END_OBJECT;
681 rtJsonTokenizerSkipCh(pTokenizer);
682 }
683 else if (ch == '[')
684 {
685 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_ARRAY;
686 rtJsonTokenizerSkipCh(pTokenizer);
687 }
688 else if (ch == ']')
689 {
690 pToken->enmClass = RTJSONTOKENCLASS_END_ARRAY;
691 rtJsonTokenizerSkipCh(pTokenizer);
692 }
693 else if (ch == ':')
694 {
695 pToken->enmClass = RTJSONTOKENCLASS_NAME_SEPARATOR;
696 rtJsonTokenizerSkipCh(pTokenizer);
697 }
698 else if (ch == ',')
699 {
700 pToken->enmClass = RTJSONTOKENCLASS_VALUE_SEPARATOR;
701 rtJsonTokenizerSkipCh(pTokenizer);
702 }
703 else
704 {
705 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
706 rc = VERR_JSON_MALFORMED;
707 }
708
709 if (RT_FAILURE(rc))
710 pTokenizer->rcTok = rc;
711
712 return rc;
713}
714
715/**
716 * Create a new tokenizer.
717 *
718 * @returns IPRT status code.
719 * @param pTokenizer The tokenizer state to initialize.
720 * @param pfnRead Read callback for the input stream.
721 * @param pvUser Opaque user data to pass to the callback.
722 */
723static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, PFNRTJSONTOKENIZERREAD pfnRead, void *pvUser)
724{
725 pTokenizer->pfnRead = pfnRead;
726 pTokenizer->pvUser = pvUser;
727 pTokenizer->offInput = 0;
728 pTokenizer->cbBuf = 0;
729 pTokenizer->offBuf = 0;
730 pTokenizer->Pos.iLine = 1;
731 pTokenizer->Pos.iChStart = 1;
732 pTokenizer->Pos.iChEnd = 1;
733 pTokenizer->pTokenCurr = &pTokenizer->Token1;
734 pTokenizer->pTokenNext = &pTokenizer->Token2;
735 pTokenizer->rcTok = VINF_SUCCESS;
736
737 RT_ZERO(pTokenizer->achBuf);
738
739 /* Fill the input buffer. */
740 int rc = rtJsonTokenizerRead(pTokenizer);
741
742 /* Fill the tokenizer with two first tokens. */
743 if (RT_SUCCESS(rc))
744 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr);
745 if (RT_SUCCESS(rc))
746 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
747
748 return rc;
749}
750
751/**
752 * Destroys a given tokenizer state.
753 *
754 * @returns nothing.
755 * @param pTokenizer The tokenizer to destroy.
756 */
757static void rtJsonTokenizerDestroy(PRTJSONTOKENIZER pTokenizer)
758{
759 RT_NOREF_PV(pTokenizer);
760}
761
762/**
763 * Get the current token in the input stream.
764 *
765 * @returns Pointer to the next token in the stream.
766 * @param pTokenizer The tokenizer state.
767 * @param ppToken Where to store the pointer to the current token on success.
768 */
769DECLINLINE(int) rtJsonTokenizerGetToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN *ppToken)
770{
771 if (RT_SUCCESS(pTokenizer->rcTok))
772 {
773 *ppToken = pTokenizer->pTokenCurr;
774 return VINF_SUCCESS;
775 }
776
777 return pTokenizer->rcTok;
778}
779
780/**
781 * Consume the current token advancing to the next in the stream.
782 *
783 * @returns nothing.
784 * @param pTokenizer The tokenizer state.
785 */
786static void rtJsonTokenizerConsume(PRTJSONTOKENIZER pTokenizer)
787{
788 PRTJSONTOKEN pTokenTmp = pTokenizer->pTokenCurr;
789
790 /* Switch next token to current token and read in the next token. */
791 pTokenizer->pTokenCurr = pTokenizer->pTokenNext;
792 pTokenizer->pTokenNext = pTokenTmp;
793 rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
794}
795
796/**
797 * Consumes the current token if it matches the given class returning an indicator.
798 *
799 * @returns true if the class matched and the token was consumed.
800 * @retval false otherwise.
801 * @param pTokenizer The tokenizer state.
802 * @param enmClass The token class to match against.
803 */
804static bool rtJsonTokenizerConsumeIfMatched(PRTJSONTOKENIZER pTokenizer, RTJSONTOKENCLASS enmClass)
805{
806 PRTJSONTOKEN pToken = NULL;
807 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
808 if (RT_SUCCESS(rc))
809 {
810 if (pToken->enmClass == enmClass)
811 {
812 rtJsonTokenizerConsume(pTokenizer);
813 return true;
814 }
815 }
816
817 return false;
818}
819
820/**
821 * Destroys a given JSON value releasing the reference to all child values.
822 *
823 * @returns nothing.
824 * @param pThis The JSON value to destroy.
825 */
826static void rtJsonValDestroy(PRTJSONVALINT pThis)
827{
828 switch (pThis->enmType)
829 {
830 case RTJSONVALTYPE_OBJECT:
831 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
832 {
833 RTStrFree(pThis->Type.Object.papszNames[i]);
834 RTJsonValueRelease(pThis->Type.Object.papValues[i]);
835 }
836 RTMemFree(pThis->Type.Object.papszNames);
837 RTMemFree(pThis->Type.Object.papValues);
838 break;
839 case RTJSONVALTYPE_ARRAY:
840 for (unsigned i = 0; i < pThis->Type.Array.cItems; i++)
841 RTJsonValueRelease(pThis->Type.Array.papItems[i]);
842 RTMemFree(pThis->Type.Array.papItems);
843 break;
844 case RTJSONVALTYPE_STRING:
845 RTStrFree(pThis->Type.String.pszStr);
846 break;
847 case RTJSONVALTYPE_NUMBER:
848 case RTJSONVALTYPE_NULL:
849 case RTJSONVALTYPE_TRUE:
850 case RTJSONVALTYPE_FALSE:
851 /* nothing to do. */
852 break;
853 default:
854 AssertMsgFailed(("Invalid JSON value type: %u\n", pThis->enmType));
855 }
856 RTMemFree(pThis);
857}
858
859/**
860 * Creates a new JSON value with the given type.
861 *
862 * @returns Pointer to JSON value on success, NULL if out of memory.
863 * @param enmType The JSON value type.
864 */
865static PRTJSONVALINT rtJsonValueCreate(RTJSONVALTYPE enmType)
866{
867 PRTJSONVALINT pThis = (PRTJSONVALINT)RTMemAllocZ(sizeof(RTJSONVALINT));
868 if (RT_LIKELY(pThis))
869 {
870 pThis->enmType = enmType;
871 pThis->cRefs = 1;
872 }
873
874 return pThis;
875}
876
877/**
878 * Parses an JSON array.
879 *
880 * @returns IPRT status code.
881 * @param pTokenizer The tokenizer to use.
882 * @param pJsonVal The JSON array value to fill in.
883 * @param pErrInfo Where to store extended error info. Optional.
884 */
885static int rtJsonParseArray(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
886{
887 int rc = VINF_SUCCESS;
888 PRTJSONTOKEN pToken = NULL;
889 uint32_t cItems = 0;
890 uint32_t cItemsMax = 0;
891 PRTJSONVALINT *papItems = NULL;
892
893 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
894 while ( RT_SUCCESS(rc)
895 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY
896 && pToken->enmClass != RTJSONTOKENCLASS_EOS)
897 {
898 PRTJSONVALINT pVal = NULL;
899 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
900 if (RT_SUCCESS(rc))
901 {
902 if (cItems == cItemsMax)
903 {
904 cItemsMax += 10;
905 PRTJSONVALINT *papItemsNew = (PRTJSONVALINT *)RTMemRealloc(papItems, cItemsMax * sizeof(PRTJSONVALINT));
906 if (RT_UNLIKELY(!papItemsNew))
907 {
908 rc = VERR_NO_MEMORY;
909 break;
910 }
911 papItems = papItemsNew;
912 }
913
914 Assert(cItems < cItemsMax);
915 papItems[cItems] = pVal;
916 cItems++;
917 }
918
919 /* Skip value separator and continue with next token. */
920 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
921 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
922
923 if ( RT_SUCCESS(rc)
924 && !fSkippedSep
925 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY)
926 rc = VERR_JSON_MALFORMED;
927 }
928
929 if (RT_SUCCESS(rc))
930 {
931 if (pToken->enmClass == RTJSONTOKENCLASS_END_ARRAY)
932 {
933 rtJsonTokenizerConsume(pTokenizer);
934 pJsonVal->Type.Array.cItems = cItems;
935 pJsonVal->Type.Array.papItems = papItems;
936 }
937 else
938 rc = VERR_JSON_MALFORMED;
939 }
940
941 if (RT_FAILURE(rc))
942 {
943 for (uint32_t i = 0; i < cItems; i++)
944 RTJsonValueRelease(papItems[i]);
945 RTMemFree(papItems);
946 }
947
948 return rc;
949}
950
951/**
952 * Parses an JSON object.
953 *
954 * @returns IPRT status code.
955 * @param pTokenizer The tokenizer to use.
956 * @param pJsonVal The JSON object value to fill in.
957 * @param pErrInfo Where to store extended error info. Optional.
958 */
959static int rtJsonParseObject(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
960{
961 int rc = VINF_SUCCESS;
962 PRTJSONTOKEN pToken = NULL;
963 uint32_t cMembers = 0;
964 uint32_t cMembersMax = 0;
965 PRTJSONVALINT *papValues = NULL;
966 char **papszNames = NULL;
967
968 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
969 while ( RT_SUCCESS(rc)
970 && pToken->enmClass == RTJSONTOKENCLASS_STRING)
971 {
972 char *pszName = pToken->Class.String.pszStr; /* We can consume this string as it was allocated. */
973
974 rtJsonTokenizerConsume(pTokenizer);
975 if (rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_NAME_SEPARATOR))
976 {
977 PRTJSONVALINT pVal = NULL;
978 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
979 if (RT_SUCCESS(rc))
980 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
981 if (RT_SUCCESS(rc))
982 {
983 if (cMembers == cMembersMax)
984 {
985 cMembersMax += 10;
986 PRTJSONVALINT *papValuesNew = (PRTJSONVALINT *)RTMemRealloc(papValues, cMembersMax * sizeof(PRTJSONVALINT));
987 char **papszNamesNew = (char **)RTMemRealloc(papszNames, cMembersMax * sizeof(char *));
988 if (RT_UNLIKELY(!papValuesNew || !papszNamesNew))
989 {
990 if (papValuesNew)
991 RTMemFree(papValuesNew);
992 if (papszNamesNew)
993 RTMemFree(papszNamesNew);
994 rc = VERR_NO_MEMORY;
995 break;
996 }
997
998 papValues = papValuesNew;
999 papszNames = papszNamesNew;
1000 }
1001
1002 Assert(cMembers < cMembersMax);
1003 papszNames[cMembers] = pszName;
1004 papValues[cMembers] = pVal;
1005 cMembers++;
1006
1007 /* Skip value separator and continue with next token. */
1008 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
1009 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1010
1011 if ( RT_SUCCESS(rc)
1012 && !fSkippedSep
1013 && pToken->enmClass != RTJSONTOKENCLASS_END_OBJECT)
1014 rc = VERR_JSON_MALFORMED;
1015 }
1016 }
1017 else
1018 rc = VERR_JSON_MALFORMED;
1019 }
1020
1021 if (RT_SUCCESS(rc))
1022 {
1023 if (pToken->enmClass == RTJSONTOKENCLASS_END_OBJECT)
1024 {
1025 rtJsonTokenizerConsume(pTokenizer);
1026 pJsonVal->Type.Object.cMembers = cMembers;
1027 pJsonVal->Type.Object.papValues = papValues;
1028 pJsonVal->Type.Object.papszNames = papszNames;
1029 }
1030 else
1031 rc = VERR_JSON_MALFORMED;
1032 }
1033
1034 if (RT_FAILURE(rc))
1035 {
1036 for (uint32_t i = 0; i < cMembers; i++)
1037 {
1038 RTJsonValueRelease(papValues[i]);
1039 RTStrFree(papszNames[i]);
1040 }
1041 RTMemFree(papValues);
1042 RTMemFree(papszNames);
1043 }
1044
1045 return rc;
1046}
1047
1048/**
1049 * Parses a single JSON value and returns it on success.
1050 *
1051 * @returns IPRT status code.
1052 * @param pTokenizer The tokenizer to use.
1053 * @param pToken The token to parse.
1054 * @param ppJsonVal Where to store the pointer to the JSON value on success.
1055 * @param pErrInfo Where to store extended error info. Optional.
1056 */
1057static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken,
1058 PRTJSONVALINT *ppJsonVal, PRTERRINFO pErrInfo)
1059{
1060 int rc = VINF_SUCCESS;
1061 PRTJSONVALINT pVal = NULL;
1062
1063 switch (pToken->enmClass)
1064 {
1065 case RTJSONTOKENCLASS_BEGIN_ARRAY:
1066 rtJsonTokenizerConsume(pTokenizer);
1067 pVal = rtJsonValueCreate(RTJSONVALTYPE_ARRAY);
1068 if (RT_LIKELY(pVal))
1069 rc = rtJsonParseArray(pTokenizer, pVal, pErrInfo);
1070 break;
1071 case RTJSONTOKENCLASS_BEGIN_OBJECT:
1072 rtJsonTokenizerConsume(pTokenizer);
1073 pVal = rtJsonValueCreate(RTJSONVALTYPE_OBJECT);
1074 if (RT_LIKELY(pVal))
1075 rc = rtJsonParseObject(pTokenizer, pVal, pErrInfo);
1076 break;
1077 case RTJSONTOKENCLASS_STRING:
1078 pVal = rtJsonValueCreate(RTJSONVALTYPE_STRING);
1079 if (RT_LIKELY(pVal))
1080 pVal->Type.String.pszStr = pToken->Class.String.pszStr;
1081 rtJsonTokenizerConsume(pTokenizer);
1082 break;
1083 case RTJSONTOKENCLASS_NUMBER:
1084 pVal = rtJsonValueCreate(RTJSONVALTYPE_NUMBER);
1085 if (RT_LIKELY(pVal))
1086 pVal->Type.Number.i64Num = pToken->Class.Number.i64Num;
1087 rtJsonTokenizerConsume(pTokenizer);
1088 break;
1089 case RTJSONTOKENCLASS_NULL:
1090 rtJsonTokenizerConsume(pTokenizer);
1091 pVal = rtJsonValueCreate(RTJSONVALTYPE_NULL);
1092 break;
1093 case RTJSONTOKENCLASS_FALSE:
1094 rtJsonTokenizerConsume(pTokenizer);
1095 pVal = rtJsonValueCreate(RTJSONVALTYPE_FALSE);
1096 break;
1097 case RTJSONTOKENCLASS_TRUE:
1098 rtJsonTokenizerConsume(pTokenizer);
1099 pVal = rtJsonValueCreate(RTJSONVALTYPE_TRUE);
1100 break;
1101 case RTJSONTOKENCLASS_END_ARRAY:
1102 case RTJSONTOKENCLASS_END_OBJECT:
1103 case RTJSONTOKENCLASS_NAME_SEPARATOR:
1104 case RTJSONTOKENCLASS_VALUE_SEPARATOR:
1105 case RTJSONTOKENCLASS_EOS:
1106 default:
1107 /** @todo Error info */
1108 rc = VERR_JSON_MALFORMED;
1109 break;
1110 }
1111
1112 if (RT_SUCCESS(rc))
1113 {
1114 if (pVal)
1115 *ppJsonVal = pVal;
1116 else
1117 rc = VERR_NO_MEMORY;
1118 }
1119 else if (pVal)
1120 rtJsonValDestroy(pVal);
1121
1122 return rc;
1123}
1124
1125/**
1126 * Entry point to parse a JSON document.
1127 *
1128 * @returns IPRT status code.
1129 * @param pTokenizer The tokenizer state.
1130 * @param ppJsonVal Where to store the root JSON value on success.
1131 * @param pErrInfo Where to store extended error info. Optional.
1132 */
1133static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal,
1134 PRTERRINFO pErrInfo)
1135{
1136 PRTJSONTOKEN pToken = NULL;
1137 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1138 if (RT_SUCCESS(rc))
1139 rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal, pErrInfo);
1140
1141 return rc;
1142}
1143
1144/**
1145 * Read callback for RTJsonParseFromBuf().
1146 */
1147static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, size_t offInput,
1148 void *pvBuf, size_t cbBuf,
1149 size_t *pcbRead)
1150{
1151 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1152 size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0;
1153
1154 if (cbLeft)
1155 memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf));
1156
1157 *pcbRead = RT_MIN(cbLeft, cbBuf);
1158
1159 return VINF_SUCCESS;
1160}
1161
1162/**
1163 * Read callback for RTJsonParseFromString().
1164 */
1165static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, size_t offInput,
1166 void *pvBuf, size_t cbBuf,
1167 size_t *pcbRead)
1168{
1169 const char *pszStr = (const char *)pvUser;
1170 size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */
1171 size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0;
1172
1173 if (cbLeft)
1174 memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf));
1175
1176 *pcbRead = RT_MIN(cbLeft, cbBuf);
1177
1178 return VINF_SUCCESS;
1179}
1180
1181/**
1182 * Read callback for RTJsonParseFromFile().
1183 */
1184static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, size_t offInput,
1185 void *pvBuf, size_t cbBuf,
1186 size_t *pcbRead)
1187{
1188 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1189
1190 RT_NOREF_PV(offInput);
1191
1192 size_t cbRead = 0;
1193 int rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead);
1194 if (RT_SUCCESS(rc))
1195 *pcbRead = cbRead;
1196
1197 return rc;
1198}
1199
1200RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf,
1201 PRTERRINFO pErrInfo)
1202{
1203 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1204 AssertPtrReturn(pbBuf, VERR_INVALID_POINTER);
1205 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
1206
1207 RTJSONTOKENIZER Tokenizer;
1208 RTJSONREADERARGS Args;
1209 Args.cbData = cbBuf;
1210 Args.u.pbBuf = pbBuf;
1211
1212 int rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromBuf, &Args);
1213 if (RT_SUCCESS(rc))
1214 {
1215 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1216 rtJsonTokenizerDestroy(&Tokenizer);
1217 }
1218
1219 return rc;
1220}
1221
1222RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo)
1223{
1224 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1225 AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
1226
1227 /** @todo r=bird: The rtJsonTokenizerParseFromString function does
1228 * strlen() on the whole pszStr for each read. For larger strings (
1229 * longer than sizeof(Tokenizer.achBuf)) it would be good to join
1230 * forces with RTJsonParseFromBuf. */
1231 RTJSONTOKENIZER Tokenizer;
1232 int rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromString, (void *)pszStr);
1233 if (RT_SUCCESS(rc))
1234 {
1235 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1236 rtJsonTokenizerDestroy(&Tokenizer);
1237 }
1238
1239 return rc;
1240}
1241
1242RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo)
1243{
1244 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1245 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1246
1247 int rc = VINF_SUCCESS;
1248 RTJSONREADERARGS Args;
1249
1250 Args.cbData = 0;
1251 rc = RTStrmOpen(pszFilename, "r", &Args.u.hStream);
1252 if (RT_SUCCESS(rc))
1253 {
1254 RTJSONTOKENIZER Tokenizer;
1255
1256 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromFile, &Args);
1257 if (RT_SUCCESS(rc))
1258 {
1259 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1260 rtJsonTokenizerDestroy(&Tokenizer);
1261 }
1262 RTStrmClose(Args.u.hStream);
1263 }
1264
1265 return rc;
1266}
1267
1268RTDECL(uint32_t) RTJsonValueRetain(RTJSONVAL hJsonVal)
1269{
1270 PRTJSONVALINT pThis = hJsonVal;
1271 AssertPtrReturn(pThis, UINT32_MAX);
1272
1273 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1274 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1275 return cRefs;
1276}
1277
1278RTDECL(uint32_t) RTJsonValueRelease(RTJSONVAL hJsonVal)
1279{
1280 PRTJSONVALINT pThis = hJsonVal;
1281 if (pThis == NIL_RTJSONVAL)
1282 return 0;
1283 AssertPtrReturn(pThis, UINT32_MAX);
1284
1285 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1286 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1287 if (cRefs == 0)
1288 rtJsonValDestroy(pThis);
1289 return cRefs;
1290}
1291
1292RTDECL(RTJSONVALTYPE) RTJsonValueGetType(RTJSONVAL hJsonVal)
1293{
1294 PRTJSONVALINT pThis = hJsonVal;
1295 AssertPtrReturn(pThis, RTJSONVALTYPE_INVALID);
1296
1297 if (pThis == NIL_RTJSONVAL)
1298 return RTJSONVALTYPE_INVALID;
1299
1300 return pThis->enmType;
1301}
1302
1303
1304RTDECL(const char *) RTJsonValueTypeName(RTJSONVALTYPE enmType)
1305{
1306 switch (enmType)
1307 {
1308 case RTJSONVALTYPE_INVALID: return "invalid";
1309 case RTJSONVALTYPE_OBJECT: return "object";
1310 case RTJSONVALTYPE_ARRAY: return "array";
1311 case RTJSONVALTYPE_STRING: return "string";
1312 case RTJSONVALTYPE_NUMBER: return "number";
1313 case RTJSONVALTYPE_NULL: return "null";
1314 case RTJSONVALTYPE_TRUE: return "true";
1315 case RTJSONVALTYPE_FALSE: return "false";
1316 default: return "???";
1317 }
1318}
1319
1320
1321#define RTJSON_ASSERT_TYPE_RETURN(pJson, enmExpectedType, ret) do { \
1322 AssertPtrReturn((pJson), (ret)); \
1323 AssertReturn((pJson) != NIL_RTJSONVAL, (ret)); \
1324 AssertReturn((pJson)->enmType == (enmExpectedType), (ret)); \
1325 } while (0)
1326
1327#define RTJSON_TYPECHECK_RETURN(pJson, enmExpectedType) do {\
1328 if (RT_LIKELY((pJson) != NIL_RTJSONVAL)) { /*likely*/ } \
1329 else return VERR_INVALID_HANDLE; \
1330 if ((pJson)->enmType == (enmExpectedType)) { /*likely*/ } \
1331 else return VERR_JSON_VALUE_INVALID_TYPE; \
1332 } while (0)
1333
1334
1335#define RTJSON_TYPECHECK_CONTAINER_RETURN(pJson) do { \
1336 if (RT_LIKELY((pJson) != NIL_RTJSONVAL)) { /* likely */ } \
1337 else return VERR_INVALID_HANDLE; \
1338 if ( (pJson)->enmType == RTJSONVALTYPE_ARRAY \
1339 || (pJson)->enmType == RTJSONVALTYPE_OBJECT) \
1340 { /* likely */ } \
1341 else return VERR_JSON_VALUE_INVALID_TYPE; \
1342 } while (0)
1343
1344
1345RTDECL(const char *) RTJsonValueGetString(RTJSONVAL hJsonVal)
1346{
1347 PRTJSONVALINT pThis = hJsonVal;
1348 RTJSON_ASSERT_TYPE_RETURN(pThis, RTJSONVALTYPE_STRING, NULL);
1349
1350 return pThis->Type.String.pszStr;
1351}
1352
1353
1354RTDECL(int) RTJsonValueQueryString(RTJSONVAL hJsonVal, const char **ppszStr)
1355{
1356 PRTJSONVALINT pThis = hJsonVal;
1357 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1358 AssertPtrReturn(ppszStr, VERR_INVALID_POINTER);
1359
1360 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_STRING);
1361 *ppszStr = pThis->Type.String.pszStr;
1362 return VINF_SUCCESS;
1363}
1364
1365RTDECL(int) RTJsonValueQueryInteger(RTJSONVAL hJsonVal, int64_t *pi64Num)
1366{
1367 PRTJSONVALINT pThis = hJsonVal;
1368 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1369 AssertPtrReturn(pi64Num, VERR_INVALID_POINTER);
1370
1371 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_NUMBER);
1372 *pi64Num = pThis->Type.Number.i64Num;
1373 return VINF_SUCCESS;
1374}
1375
1376RTDECL(int) RTJsonValueQueryByName(RTJSONVAL hJsonVal, const char *pszName, PRTJSONVAL phJsonVal)
1377{
1378 PRTJSONVALINT pThis = hJsonVal;
1379 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1380 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1381 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1382
1383 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_OBJECT);
1384
1385 int rc = VERR_NOT_FOUND;
1386 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
1387 {
1388 if (!RTStrCmp(pThis->Type.Object.papszNames[i], pszName))
1389 {
1390 RTJsonValueRetain(pThis->Type.Object.papValues[i]);
1391 *phJsonVal = pThis->Type.Object.papValues[i];
1392 rc = VINF_SUCCESS;
1393 break;
1394 }
1395 }
1396
1397 return rc;
1398}
1399
1400RTDECL(int) RTJsonValueQueryIntegerByName(RTJSONVAL hJsonVal, const char *pszName, int64_t *pi64Num)
1401{
1402 RTJSONVAL hJsonValNum = NIL_RTJSONVAL;
1403 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValNum);
1404 if (RT_SUCCESS(rc))
1405 {
1406 rc = RTJsonValueQueryInteger(hJsonValNum, pi64Num);
1407 RTJsonValueRelease(hJsonValNum);
1408 }
1409
1410 return rc;
1411}
1412
1413RTDECL(int) RTJsonValueQueryStringByName(RTJSONVAL hJsonVal, const char *pszName, char **ppszStr)
1414{
1415 RTJSONVAL hJsonValStr = NIL_RTJSONVAL;
1416 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValStr);
1417 if (RT_SUCCESS(rc))
1418 {
1419 const char *pszStr = NULL;
1420 rc = RTJsonValueQueryString(hJsonValStr, &pszStr);
1421 if (RT_SUCCESS(rc))
1422 {
1423 *ppszStr = RTStrDup(pszStr);
1424 if (!*ppszStr)
1425 rc = VERR_NO_STR_MEMORY;
1426 }
1427 RTJsonValueRelease(hJsonValStr);
1428 }
1429
1430 return rc;
1431}
1432
1433RTDECL(int) RTJsonValueQueryBooleanByName(RTJSONVAL hJsonVal, const char *pszName, bool *pfBoolean)
1434{
1435 AssertPtrReturn(pfBoolean, VERR_INVALID_POINTER);
1436
1437 RTJSONVAL hJsonValBool = NIL_RTJSONVAL;
1438 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValBool);
1439 if (RT_SUCCESS(rc))
1440 {
1441 RTJSONVALTYPE enmType = RTJsonValueGetType(hJsonValBool);
1442 if (enmType == RTJSONVALTYPE_TRUE)
1443 *pfBoolean = true;
1444 else if (enmType == RTJSONVALTYPE_FALSE)
1445 *pfBoolean = false;
1446 else
1447 rc = VERR_JSON_VALUE_INVALID_TYPE;
1448 RTJsonValueRelease(hJsonValBool);
1449 }
1450
1451 return rc;
1452}
1453
1454RTDECL(unsigned) RTJsonValueGetArraySize(RTJSONVAL hJsonVal)
1455{
1456 PRTJSONVALINT pThis = hJsonVal;
1457 RTJSON_ASSERT_TYPE_RETURN(pThis, RTJSONVALTYPE_ARRAY, 0);
1458
1459 return pThis->Type.Array.cItems;
1460}
1461
1462RTDECL(int) RTJsonValueQueryArraySize(RTJSONVAL hJsonVal, unsigned *pcItems)
1463{
1464 PRTJSONVALINT pThis = hJsonVal;
1465 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1466 AssertPtrReturn(pcItems, VERR_INVALID_POINTER);
1467
1468 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
1469 *pcItems = pThis->Type.Array.cItems;
1470 return VINF_SUCCESS;
1471}
1472
1473RTDECL(int) RTJsonValueQueryByIndex(RTJSONVAL hJsonVal, unsigned idx, PRTJSONVAL phJsonVal)
1474{
1475 PRTJSONVALINT pThis = hJsonVal;
1476 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1477 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1478
1479 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
1480 if (RT_UNLIKELY(idx >= pThis->Type.Array.cItems))
1481 return VERR_OUT_OF_RANGE;
1482
1483 RTJsonValueRetain(pThis->Type.Array.papItems[idx]);
1484 *phJsonVal = pThis->Type.Array.papItems[idx];
1485 return VINF_SUCCESS;
1486}
1487
1488static int rtJsonIteratorBeginWorker(PRTJSONVALINT pThis, PRTJSONIT phJsonIt)
1489{
1490 PRTJSONITINT pIt = (PRTJSONITINT)RTMemTmpAllocZ(sizeof(RTJSONITINT));
1491 if (pIt)
1492 {
1493 RTJsonValueRetain(pThis);
1494 pIt->pJsonVal = pThis;
1495 pIt->idxCur = 0;
1496
1497 *phJsonIt = pIt;
1498 return VINF_SUCCESS;
1499 }
1500 return VERR_NO_MEMORY;
1501}
1502
1503RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1504{
1505 PRTJSONVALINT pThis = hJsonVal;
1506 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1507 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1508 RTJSON_TYPECHECK_CONTAINER_RETURN(pThis);
1509
1510 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
1511}
1512
1513RTDECL(int) RTJsonIteratorBeginArray(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1514{
1515 PRTJSONVALINT pThis = hJsonVal;
1516 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1517 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1518 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_ARRAY);
1519
1520 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
1521}
1522
1523RTDECL(int) RTJsonIteratorBeginObject(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1524{
1525 PRTJSONVALINT pThis = hJsonVal;
1526 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1527 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1528 RTJSON_TYPECHECK_RETURN(pThis, RTJSONVALTYPE_OBJECT);
1529
1530 return rtJsonIteratorBeginWorker(pThis, phJsonIt);
1531}
1532
1533RTDECL(int) RTJsonIteratorQueryValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName)
1534{
1535 PRTJSONITINT pIt = hJsonIt;
1536 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
1537 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1538 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1539
1540 int rc = VINF_SUCCESS;
1541 PRTJSONVALINT pThis = pIt->pJsonVal;
1542 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1543 {
1544 if (pIt->idxCur < pThis->Type.Array.cItems)
1545 {
1546 if (ppszName)
1547 *ppszName = NULL;
1548
1549 RTJsonValueRetain(pThis->Type.Array.papItems[pIt->idxCur]);
1550 *phJsonVal = pThis->Type.Array.papItems[pIt->idxCur];
1551 }
1552 else
1553 rc = VERR_JSON_ITERATOR_END;
1554 }
1555 else
1556 {
1557 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1558
1559 if (pIt->idxCur < pThis->Type.Object.cMembers)
1560 {
1561 if (ppszName)
1562 *ppszName = pThis->Type.Object.papszNames[pIt->idxCur];
1563
1564 RTJsonValueRetain(pThis->Type.Object.papValues[pIt->idxCur]);
1565 *phJsonVal = pThis->Type.Object.papValues[pIt->idxCur];
1566 }
1567 else
1568 rc = VERR_JSON_ITERATOR_END;
1569 }
1570
1571 return rc;
1572}
1573
1574RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt)
1575{
1576 PRTJSONITINT pIt = hJsonIt;
1577 AssertPtrReturn(pIt, VERR_INVALID_HANDLE);
1578 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1579
1580 int rc = VINF_SUCCESS;
1581 PRTJSONVALINT pThis = pIt->pJsonVal;
1582 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1583 {
1584 if (pIt->idxCur < pThis->Type.Array.cItems)
1585 pIt->idxCur++;
1586
1587 if (pIt->idxCur == pThis->Type.Object.cMembers)
1588 rc = VERR_JSON_ITERATOR_END;
1589 }
1590 else
1591 {
1592 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1593
1594 if (pIt->idxCur < pThis->Type.Object.cMembers)
1595 pIt->idxCur++;
1596
1597 if (pIt->idxCur == pThis->Type.Object.cMembers)
1598 rc = VERR_JSON_ITERATOR_END;
1599 }
1600
1601 return rc;
1602}
1603
1604RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt)
1605{
1606 PRTJSONITINT pThis = hJsonIt;
1607 AssertPtrReturnVoid(pThis);
1608
1609 if (pThis == NIL_RTJSONIT)
1610 return;
1611
1612 RTJsonValueRelease(pThis->pJsonVal);
1613 RTMemTmpFree(pThis);
1614}
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