VirtualBox

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

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

build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.8 KB
Line 
1/* $Id: json.cpp 61705 2016-06-15 09:59:39Z 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, uint32_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 uint32_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, unsigned 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 unsigned 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 rc = pToken->enmClass == RTJSONTOKENCLASS_BEGIN_OBJECT;
644 else if (ch == '}')
645 rc = pToken->enmClass == RTJSONTOKENCLASS_END_OBJECT;
646 else if (ch == '[')
647 rc = pToken->enmClass == RTJSONTOKENCLASS_BEGIN_ARRAY;
648 else if (ch == ']')
649 rc = pToken->enmClass == RTJSONTOKENCLASS_END_ARRAY;
650 else if (ch == ':')
651 rc = pToken->enmClass == RTJSONTOKENCLASS_NAME_SEPARATOR;
652 else if (ch == ',')
653 rc = pToken->enmClass == RTJSONTOKENCLASS_VALUE_SEPARATOR;
654 else
655 {
656 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
657 rc = VERR_JSON_MALFORMED;
658 }
659
660 return rc;
661}
662
663/**
664 * Create a new tokenizer.
665 *
666 * @returns IPRT status code.
667 * @param pTokenizer The tokenizer state to initialize.
668 * @param pfnRead Read callback for the input stream.
669 * @param pvUser Opaque user data to pass to the callback.
670 */
671static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, PFNRTJSONTOKENIZERREAD pfnRead, void *pvUser)
672{
673 pTokenizer->pfnRead = pfnRead;
674 pTokenizer->pvUser = pvUser;
675 pTokenizer->offInput = 0;
676 pTokenizer->cbBuf = 0;
677 pTokenizer->offBuf = 0;
678 pTokenizer->Pos.iLine = 1;
679 pTokenizer->Pos.iChStart = 1;
680 pTokenizer->Pos.iChEnd = 1;
681 pTokenizer->pTokenCurr = &pTokenizer->Token1;
682 pTokenizer->pTokenNext = &pTokenizer->Token2;
683
684 RT_ZERO(pTokenizer->achBuf);
685
686 /* Fill the input buffer. */
687 int rc = rtJsonTokenizerRead(pTokenizer);
688
689 /* Fill the tokenizer with two first tokens. */
690 if (RT_SUCCESS(rc))
691 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr);
692 if (RT_SUCCESS(rc))
693 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
694
695 return rc;
696}
697
698/**
699 * Destroys a given tokenizer state.
700 *
701 * @returns nothing.
702 * @param pTokenizer The tokenizer to destroy.
703 */
704static void rtJsonTokenizerDestroy(PRTJSONTOKENIZER pTokenizer)
705{
706
707}
708
709/**
710 * Get the current token in the input stream.
711 *
712 * @returns Pointer to the next token in the stream.
713 * @param pTokenizer The tokenizer state.
714 * @param ppToken Where to store the pointer to the current token on success.
715 */
716DECLINLINE(int) rtJsonTokenizerGetToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN *ppToken)
717{
718 *ppToken = pTokenizer->pTokenCurr;
719 return VINF_SUCCESS;
720}
721
722/**
723 * Consume the current token advancing to the next in the stream.
724 *
725 * @returns nothing.
726 * @param pTokenizer The tokenizer state.
727 */
728static void rtJsonTokenizerConsume(PRTJSONTOKENIZER pTokenizer)
729{
730 PRTJSONTOKEN pTokenTmp = pTokenizer->pTokenCurr;
731
732 /* Switch next token to current token and read in the next token. */
733 pTokenizer->pTokenCurr = pTokenizer->pTokenNext;
734 pTokenizer->pTokenNext = pTokenTmp;
735 rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
736}
737
738/**
739 * Consumes the current token if it matches the given class returning an indicator.
740 *
741 * @returns true if the class matched and the token was consumed.
742 * @param false otherwise.
743 * @param pTokenizer The tokenizer state.
744 * @param enmClass The token class to match against.
745 */
746static bool rtJsonTokenizerConsumeIfMatched(PRTJSONTOKENIZER pTokenizer, RTJSONTOKENCLASS enmClass)
747{
748 PRTJSONTOKEN pToken = NULL;
749 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
750 AssertRC(rc);
751
752 if (pToken->enmClass == enmClass)
753 {
754 rtJsonTokenizerConsume(pTokenizer);
755 return true;
756 }
757
758 return false;
759}
760
761/**
762 * Destroys a given JSON value releasing the reference to all child values.
763 *
764 * @returns nothing.
765 * @param pThis The JSON value to destroy.
766 */
767static void rtJsonValDestroy(PRTJSONVALINT pThis)
768{
769 switch (pThis->enmType)
770 {
771 case RTJSONVALTYPE_OBJECT:
772 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
773 {
774 RTStrFree(pThis->Type.Object.papszNames[i]);
775 RTJsonValueRelease(pThis->Type.Object.papValues[i]);
776 }
777 break;
778 case RTJSONVALTYPE_ARRAY:
779 for (unsigned i = 0; i < pThis->Type.Array.cItems; i++)
780 RTJsonValueRelease(pThis->Type.Array.papItems[i]);
781 break;
782 case RTJSONVALTYPE_STRING:
783 RTStrFree(pThis->Type.String.pszStr);
784 break;
785 case RTJSONVALTYPE_NUMBER:
786 case RTJSONVALTYPE_NULL:
787 case RTJSONVALTYPE_TRUE:
788 case RTJSONVALTYPE_FALSE:
789 /* nothing to do. */
790 break;
791 default:
792 AssertMsgFailed(("Invalid JSON value type: %u\n", pThis->enmType));
793 }
794 RTMemFree(pThis);
795}
796
797/**
798 * Creates a new JSON value with the given type.
799 *
800 * @returns Pointer to JSON value on success, NULL if out of memory.
801 * @param enmType The JSON value type.
802 */
803static PRTJSONVALINT rtJsonValueCreate(RTJSONVALTYPE enmType)
804{
805 PRTJSONVALINT pThis = (PRTJSONVALINT)RTMemAllocZ(sizeof(RTJSONVALINT));
806 if (RT_LIKELY(pThis))
807 {
808 pThis->enmType = enmType;
809 pThis->cRefs = 1;
810 }
811
812 return pThis;
813}
814
815/**
816 * Parses an JSON array.
817 *
818 * @returns IPRT status code.
819 * @param pTokenizer The tokenizer to use.
820 * @param pVal The JSON array value to fill in.
821 * @param pErrInfo Where to store extended error info. Optional.
822 */
823static int rtJsonParseArray(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
824{
825 int rc = VINF_SUCCESS;
826 PRTJSONTOKEN pToken = NULL;
827 uint32_t cItems = 0;
828
829 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
830 while ( RT_SUCCESS(rc)
831 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY)
832 {
833 PRTJSONVALINT pVal = NULL;
834 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
835 if (RT_SUCCESS(rc))
836 {
837 cItems++;
838 /** @todo: Add value to array. */
839 }
840
841 /* Next token. */
842 rtJsonTokenizerConsume(pTokenizer);
843 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
844 }
845
846 if (RT_SUCCESS(rc))
847 {
848 Assert(pToken->enmClass == RTJSONTOKENCLASS_END_ARRAY);
849 rtJsonTokenizerConsume(pTokenizer);
850 pJsonVal->Type.Array.cItems = cItems;
851 }
852
853 return rc;
854}
855
856/**
857 * Parses an JSON object.
858 *
859 * @returns IPRT status code.
860 * @param pTokenizer The tokenizer to use.
861 * @param pVal The JSON object value to fill in.
862 * @param pErrInfo Where to store extended error info. Optional.
863 */
864static int rtJsonParseObject(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
865{
866 int rc = VINF_SUCCESS;
867 PRTJSONTOKEN pToken = NULL;
868 uint32_t cMembers = 0;
869
870 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
871 while ( RT_SUCCESS(rc)
872 && pToken->enmClass == RTJSONTOKENCLASS_STRING)
873 {
874 char *pszName = pToken->Class.String.pszStr;
875
876 rtJsonTokenizerConsume(pTokenizer);
877 if (rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_NAME_SEPARATOR))
878 {
879 PRTJSONVALINT pVal = NULL;
880 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
881 if (RT_SUCCESS(rc))
882 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
883 if (RT_SUCCESS(rc))
884 {
885 cMembers++;
886 /** @todo: Add name/value pair to object. */
887
888 /* Next token. */
889 rtJsonTokenizerConsume(pTokenizer);
890 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
891 }
892 }
893 else
894 rc = VERR_JSON_MALFORMED;
895 }
896
897 if (RT_SUCCESS(rc))
898 {
899 if (pToken->enmClass == RTJSONTOKENCLASS_END_OBJECT)
900 {
901 rtJsonTokenizerConsume(pTokenizer);
902 pJsonVal->Type.Object.cMembers = cMembers;
903 }
904 else
905 rc = VERR_JSON_MALFORMED;
906 }
907
908 return rc;
909}
910
911/**
912 * Parses a single JSON value and returns it on success.
913 *
914 * @returns IPRT status code.
915 * @param pTokenizer The tokenizer to use.
916 * @param pToken The token to parse.
917 * @param ppJsonVal Where to store the pointer to the JSON value on success.
918 * @param pErrInfo Where to store extended error info. Optional.
919 */
920static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken,
921 PRTJSONVALINT *ppJsonVal, PRTERRINFO pErrInfo)
922{
923 int rc = VINF_SUCCESS;
924 PRTJSONVALINT pVal = NULL;
925
926 switch (pToken->enmClass)
927 {
928 case RTJSONTOKENCLASS_BEGIN_ARRAY:
929 pVal = rtJsonValueCreate(RTJSONVALTYPE_ARRAY);
930 if (RT_LIKELY(pVal))
931 rc = rtJsonParseArray(pTokenizer, pVal, pErrInfo);
932 break;
933 case RTJSONTOKENCLASS_BEGIN_OBJECT:
934 pVal = rtJsonValueCreate(RTJSONVALTYPE_OBJECT);
935 if (RT_LIKELY(pVal))
936 rc = rtJsonParseObject(pTokenizer, pVal, pErrInfo);
937 break;
938 case RTJSONTOKENCLASS_STRING:
939 pVal = rtJsonValueCreate(RTJSONVALTYPE_STRING);
940 if (RT_LIKELY(pVal))
941 pVal->Type.String.pszStr = pToken->Class.String.pszStr;
942 break;
943 case RTJSONTOKENCLASS_NUMBER:
944 pVal = rtJsonValueCreate(RTJSONVALTYPE_NUMBER);
945 if (RT_LIKELY(pVal))
946 pVal->Type.Number.i64Num = pToken->Class.Number.i64Num;
947 break;
948 case RTJSONTOKENCLASS_NULL:
949 pVal = rtJsonValueCreate(RTJSONVALTYPE_NULL);
950 break;
951 case RTJSONTOKENCLASS_FALSE:
952 pVal = rtJsonValueCreate(RTJSONVALTYPE_FALSE);
953 break;
954 case RTJSONTOKENCLASS_TRUE:
955 pVal = rtJsonValueCreate(RTJSONVALTYPE_TRUE);
956 break;
957 case RTJSONTOKENCLASS_END_ARRAY:
958 case RTJSONTOKENCLASS_END_OBJECT:
959 case RTJSONTOKENCLASS_NAME_SEPARATOR:
960 case RTJSONTOKENCLASS_VALUE_SEPARATOR:
961 case RTJSONTOKENCLASS_EOS:
962 default:
963 /** @todo: Error info */
964 rc = VERR_JSON_MALFORMED;
965 break;
966 }
967
968 if (RT_SUCCESS(rc))
969 {
970 if (pVal)
971 *ppJsonVal = pVal;
972 else
973 rc = VERR_NO_MEMORY;
974 }
975 else if (pVal)
976 rtJsonValDestroy(pVal);
977
978 return rc;
979}
980
981/**
982 * Entry point to parse a JSON document.
983 *
984 * @returns IPRT status code.
985 * @param pTokenizer The tokenizer state.
986 * @param ppJsonVal Where to store the root JSON value on success.
987 * @param pErrInfo Where to store extended error info. Optional.
988 */
989static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal,
990 PRTERRINFO pErrInfo)
991{
992 PRTJSONTOKEN pToken = NULL;
993 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
994 if (RT_SUCCESS(rc))
995 rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal, pErrInfo);
996
997 return rc;
998}
999
1000/**
1001 * Read callback for RTJsonParseFromBuf().
1002 */
1003static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, uint32_t offInput,
1004 void *pvBuf, size_t cbBuf,
1005 size_t *pcbRead)
1006{
1007 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1008 size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0;
1009
1010 if (cbLeft)
1011 memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf));
1012
1013 *pcbRead = RT_MIN(cbLeft, cbBuf);
1014
1015 return VINF_SUCCESS;
1016}
1017
1018/**
1019 * Read callback for RTJsonParseFromString().
1020 */
1021static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, uint32_t offInput,
1022 void *pvBuf, size_t cbBuf,
1023 size_t *pcbRead)
1024{
1025 const char *pszStr = (const char *)pvUser;
1026 size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */
1027 size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0;
1028
1029 if (cbLeft)
1030 memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf));
1031
1032 *pcbRead = RT_MIN(cbLeft, cbBuf);
1033
1034 return VINF_SUCCESS;
1035}
1036
1037/**
1038 * Read callback for RTJsonParseFromFile().
1039 */
1040static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, uint32_t offInput,
1041 void *pvBuf, size_t cbBuf,
1042 size_t *pcbRead)
1043{
1044 int rc = VINF_SUCCESS;
1045 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1046 size_t cbRead = 0;
1047
1048 rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead);
1049 if (RT_SUCCESS(rc))
1050 *pcbRead = cbRead;
1051
1052 return rc;
1053}
1054
1055RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf,
1056 PRTERRINFO pErrInfo)
1057{
1058 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1059 AssertPtrReturn(pbBuf, VERR_INVALID_POINTER);
1060 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
1061
1062 int rc = VINF_SUCCESS;
1063 RTJSONREADERARGS Args;
1064 RTJSONTOKENIZER Tokenizer;
1065
1066 Args.cbData = cbBuf;
1067 Args.u.pbBuf = pbBuf;
1068
1069 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromBuf, &Args);
1070 if (RT_SUCCESS(rc))
1071 {
1072 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1073 rtJsonTokenizerDestroy(&Tokenizer);
1074 }
1075
1076 return rc;
1077}
1078
1079RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo)
1080{
1081 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1082 AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
1083
1084 int rc = VINF_SUCCESS;
1085 RTJSONTOKENIZER Tokenizer;
1086
1087 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromString, (void *)pszStr);
1088 if (RT_SUCCESS(rc))
1089 {
1090 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1091 rtJsonTokenizerDestroy(&Tokenizer);
1092 }
1093
1094 return rc;
1095}
1096
1097RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo)
1098{
1099 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1100 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1101
1102 int rc = VINF_SUCCESS;
1103 RTJSONREADERARGS Args;
1104
1105 Args.cbData = 0;
1106 rc = RTStrmOpen(pszFilename, "r", &Args.u.hStream);
1107 if (RT_SUCCESS(rc))
1108 {
1109 RTJSONTOKENIZER Tokenizer;
1110
1111 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromFile, &Args);
1112 if (RT_SUCCESS(rc))
1113 {
1114 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1115 rtJsonTokenizerDestroy(&Tokenizer);
1116 }
1117 RTStrmClose(Args.u.hStream);
1118 }
1119
1120 return rc;
1121}
1122
1123RTDECL(uint32_t) RTJsonValueRetain(RTJSONVAL hJsonVal)
1124{
1125 PRTJSONVALINT pThis = hJsonVal;
1126 AssertPtrReturn(pThis, UINT32_MAX);
1127
1128 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1129 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1130 return cRefs;
1131}
1132
1133RTDECL(uint32_t) RTJsonValueRelease(RTJSONVAL hJsonVal)
1134{
1135 PRTJSONVALINT pThis = hJsonVal;
1136 if (pThis == NIL_RTJSONVAL)
1137 return 0;
1138 AssertPtrReturn(pThis, UINT32_MAX);
1139
1140 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1141 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1142 if (cRefs == 0)
1143 rtJsonValDestroy(pThis);
1144 return cRefs;
1145}
1146
1147RTDECL(RTJSONVALTYPE) RTJsonValueGetType(RTJSONVAL hJsonVal)
1148{
1149 PRTJSONVALINT pThis = hJsonVal;
1150 if (pThis == NIL_RTJSONVAL)
1151 return RTJSONVALTYPE_INVALID;
1152 AssertPtrReturn(pThis, RTJSONVALTYPE_INVALID);
1153
1154 return pThis->enmType;
1155}
1156
1157RTDECL(const char *) RTJsonValueGetString(RTJSONVAL hJsonVal)
1158{
1159 PRTJSONVALINT pThis = hJsonVal;
1160 AssertReturn(pThis != NIL_RTJSONVAL, NULL);
1161 AssertReturn(pThis->enmType == RTJSONVALTYPE_STRING, NULL);
1162
1163 return pThis->Type.String.pszStr;
1164}
1165
1166RTDECL(int) RTJsonValueGetStringEx(RTJSONVAL hJsonVal, const char **ppszStr)
1167{
1168 PRTJSONVALINT pThis = hJsonVal;
1169 AssertPtrReturn(ppszStr, VERR_INVALID_POINTER);
1170 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1171 AssertReturn(pThis->enmType == RTJSONVALTYPE_STRING, VERR_JSON_VALUE_INVALID_TYPE);
1172
1173 *ppszStr = pThis->Type.String.pszStr;
1174 return VINF_SUCCESS;
1175}
1176
1177RTDECL(int) RTJsonValueGetNumber(RTJSONVAL hJsonVal, int64_t *pi64Num)
1178{
1179 PRTJSONVALINT pThis = hJsonVal;
1180 AssertPtrReturn(pi64Num, VERR_INVALID_POINTER);
1181 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1182 AssertReturn(pThis->enmType == RTJSONVALTYPE_NUMBER, VERR_JSON_VALUE_INVALID_TYPE);
1183
1184 *pi64Num = pThis->Type.Number.i64Num;
1185 return VINF_SUCCESS;
1186}
1187
1188RTDECL(int) RTJsonValueGetByName(RTJSONVAL hJsonVal, const char *pszName, PRTJSONVAL phJsonVal)
1189{
1190 PRTJSONVALINT pThis = hJsonVal;
1191 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1192 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1193 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1194 AssertReturn(pThis->enmType == RTJSONVALTYPE_OBJECT, VERR_JSON_VALUE_INVALID_TYPE);
1195
1196 int rc = VERR_NOT_FOUND;
1197 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
1198 {
1199 if (!RTStrCmp(pThis->Type.Object.papszNames[i], pszName))
1200 {
1201 RTJsonValueRetain(pThis->Type.Object.papValues[i]);
1202 *phJsonVal = pThis->Type.Object.papValues[i];
1203 rc = VINF_SUCCESS;
1204 break;
1205 }
1206 }
1207
1208 return rc;
1209}
1210
1211RTDECL(uint32_t) RTJsonValueGetArraySize(RTJSONVAL hJsonVal)
1212{
1213 PRTJSONVALINT pThis = hJsonVal;
1214 AssertReturn(pThis != NIL_RTJSONVAL, 0);
1215 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, 0);
1216
1217 return pThis->Type.Array.cItems;
1218}
1219
1220RTDECL(int) RTJsonValueGetArraySizeEx(RTJSONVAL hJsonVal, uint32_t *pcItems)
1221{
1222 PRTJSONVALINT pThis = hJsonVal;
1223 AssertPtrReturn(pcItems, VERR_INVALID_POINTER);
1224 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1225 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, VERR_JSON_VALUE_INVALID_TYPE);
1226
1227 *pcItems = pThis->Type.Array.cItems;
1228 return VINF_SUCCESS;
1229}
1230
1231RTDECL(int) RTJsonValueGetByIndex(RTJSONVAL hJsonVal, uint32_t idx, PRTJSONVAL phJsonVal)
1232{
1233 PRTJSONVALINT pThis = hJsonVal;
1234 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1235 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1236 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, VERR_JSON_VALUE_INVALID_TYPE);
1237 AssertReturn(idx < pThis->Type.Array.cItems, VERR_OUT_OF_RANGE);
1238
1239 RTJsonValueRetain(pThis->Type.Array.papItems[idx]);
1240 *phJsonVal = pThis->Type.Array.papItems[idx];
1241 return VINF_SUCCESS;
1242}
1243
1244RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1245{
1246 PRTJSONVALINT pThis = hJsonVal;
1247 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1248 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1249 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY || pThis->enmType == RTJSONVALTYPE_OBJECT,
1250 VERR_JSON_VALUE_INVALID_TYPE);
1251
1252 PRTJSONITINT pIt = (PRTJSONITINT)RTMemTmpAllocZ(sizeof(RTJSONITINT));
1253 if (RT_UNLIKELY(!pIt))
1254 return VERR_NO_MEMORY;
1255
1256 RTJsonValueRetain(hJsonVal);
1257 pIt->pJsonVal = pThis;
1258 pIt->idxCur = 0;
1259 *phJsonIt = pIt;
1260
1261 return VINF_SUCCESS;
1262}
1263
1264RTDECL(int) RTJsonIteratorGetValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName)
1265{
1266 PRTJSONITINT pIt = hJsonIt;
1267 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1268 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1269
1270 int rc = VINF_SUCCESS;
1271 PRTJSONVALINT pThis = pIt->pJsonVal;
1272 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1273 {
1274 if (pIt->idxCur < pThis->Type.Array.cItems)
1275 {
1276 if (ppszName)
1277 *ppszName = NULL;
1278
1279 RTJsonValueRetain(pThis->Type.Array.papItems[pIt->idxCur]);
1280 *phJsonVal = pThis->Type.Array.papItems[pIt->idxCur];
1281 }
1282 else
1283 rc = VERR_JSON_ITERATOR_END;
1284 }
1285 else
1286 {
1287 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1288
1289 if (pIt->idxCur < pThis->Type.Object.cMembers)
1290 {
1291 if (ppszName)
1292 *ppszName = pThis->Type.Object.papszNames[pIt->idxCur];
1293
1294 RTJsonValueRetain(pThis->Type.Object.papValues[pIt->idxCur]);
1295 *phJsonVal = pThis->Type.Object.papValues[pIt->idxCur];
1296 }
1297 else
1298 rc = VERR_JSON_ITERATOR_END;
1299 }
1300
1301 return rc;
1302}
1303
1304RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt)
1305{
1306 PRTJSONITINT pIt = hJsonIt;
1307 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1308
1309 int rc = VINF_SUCCESS;
1310 PRTJSONVALINT pThis = pIt->pJsonVal;
1311 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1312 {
1313 if (pIt->idxCur < pThis->Type.Array.cItems)
1314 pIt->idxCur++;
1315 else
1316 rc = VERR_JSON_ITERATOR_END;
1317 }
1318 else
1319 {
1320 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1321
1322 if (pIt->idxCur < pThis->Type.Object.cMembers)
1323 pIt->idxCur++;
1324 else
1325 rc = VERR_JSON_ITERATOR_END;
1326 }
1327
1328 return rc;
1329}
1330
1331RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt)
1332{
1333 PRTJSONITINT pThis = hJsonIt;
1334 if (pThis == NIL_RTJSONIT)
1335 return;
1336 AssertPtrReturnVoid(pThis);
1337
1338 RTJsonValueRelease(pThis->pJsonVal);
1339 RTMemTmpFree(pThis);
1340}
1341
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