VirtualBox

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

Last change on this file since 61716 was 61716, checked in by vboxsync, 9 years ago

Runtime/JSON: Fixes and start on a testcase

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