VirtualBox

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

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

Runtime/RTJson: Fixes, updates to the testcase

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.1 KB
Line 
1/* $Id: json.cpp 61721 2016-06-15 14:26:43Z 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 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
880 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
881
882 if ( RT_SUCCESS(rc)
883 && !fSkippedSep
884 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY)
885 rc = VERR_JSON_MALFORMED;
886 }
887
888 if (RT_SUCCESS(rc))
889 {
890 if (pToken->enmClass == RTJSONTOKENCLASS_END_ARRAY)
891 {
892 rtJsonTokenizerConsume(pTokenizer);
893 pJsonVal->Type.Array.cItems = cItems;
894 pJsonVal->Type.Array.papItems = papItems;
895 }
896 else
897 rc = VERR_JSON_MALFORMED;
898 }
899
900 if (RT_FAILURE(rc))
901 {
902 for (uint32_t i = 0; i < cItems; i++)
903 RTJsonValueRelease(papItems[i]);
904 RTMemFree(papItems);
905 }
906
907 return rc;
908}
909
910/**
911 * Parses an JSON object.
912 *
913 * @returns IPRT status code.
914 * @param pTokenizer The tokenizer to use.
915 * @param pVal The JSON object value to fill in.
916 * @param pErrInfo Where to store extended error info. Optional.
917 */
918static int rtJsonParseObject(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
919{
920 int rc = VINF_SUCCESS;
921 PRTJSONTOKEN pToken = NULL;
922 uint32_t cMembers = 0;
923 uint32_t cMembersMax = 0;
924 PRTJSONVALINT *papValues = NULL;
925 char **papszNames = NULL;
926
927 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
928 while ( RT_SUCCESS(rc)
929 && pToken->enmClass == RTJSONTOKENCLASS_STRING)
930 {
931 char *pszName = pToken->Class.String.pszStr;
932
933 rtJsonTokenizerConsume(pTokenizer);
934 if (rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_NAME_SEPARATOR))
935 {
936 PRTJSONVALINT pVal = NULL;
937 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
938 if (RT_SUCCESS(rc))
939 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
940 if (RT_SUCCESS(rc))
941 {
942 if (cMembers == cMembersMax)
943 {
944 cMembersMax += 10;
945 PRTJSONVALINT *papValuesNew = (PRTJSONVALINT *)RTMemRealloc(papValues, cMembersMax * sizeof(PRTJSONVALINT));
946 char **papszNamesNew = (char **)RTMemRealloc(papValues, cMembersMax * sizeof(char *));
947 if (RT_UNLIKELY(!papValuesNew || !papszNamesNew))
948 {
949 rc = VERR_NO_MEMORY;
950 break;
951 }
952
953 papValues = papValuesNew;
954 papszNames = papszNamesNew;
955 }
956
957 Assert(cMembers < cMembersMax);
958 papszNames[cMembers] = pszName;
959 papValues[cMembers] = pVal;
960 cMembers++;
961
962 /* Skip value separator and continue with next token. */
963 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
964 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
965
966 if ( RT_SUCCESS(rc)
967 && !fSkippedSep
968 && pToken->enmClass != RTJSONTOKENCLASS_END_OBJECT)
969 rc = VERR_JSON_MALFORMED;
970 }
971 }
972 else
973 rc = VERR_JSON_MALFORMED;
974 }
975
976 if (RT_SUCCESS(rc))
977 {
978 if (pToken->enmClass == RTJSONTOKENCLASS_END_OBJECT)
979 {
980 rtJsonTokenizerConsume(pTokenizer);
981 pJsonVal->Type.Object.cMembers = cMembers;
982 pJsonVal->Type.Object.papValues = papValues;
983 pJsonVal->Type.Object.papszNames = papszNames;
984 }
985 else
986 rc = VERR_JSON_MALFORMED;
987 }
988
989 if (RT_FAILURE(rc))
990 {
991 for (uint32_t i = 0; i < cMembers; i++)
992 {
993 RTJsonValueRelease(papValues[i]);
994 RTStrFree(papszNames[i]);
995 }
996 RTMemFree(papValues);
997 RTMemFree(papszNames);
998 }
999
1000 return rc;
1001}
1002
1003/**
1004 * Parses a single JSON value and returns it on success.
1005 *
1006 * @returns IPRT status code.
1007 * @param pTokenizer The tokenizer to use.
1008 * @param pToken The token to parse.
1009 * @param ppJsonVal Where to store the pointer to the JSON value on success.
1010 * @param pErrInfo Where to store extended error info. Optional.
1011 */
1012static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken,
1013 PRTJSONVALINT *ppJsonVal, PRTERRINFO pErrInfo)
1014{
1015 int rc = VINF_SUCCESS;
1016 PRTJSONVALINT pVal = NULL;
1017
1018 switch (pToken->enmClass)
1019 {
1020 case RTJSONTOKENCLASS_BEGIN_ARRAY:
1021 rtJsonTokenizerConsume(pTokenizer);
1022 pVal = rtJsonValueCreate(RTJSONVALTYPE_ARRAY);
1023 if (RT_LIKELY(pVal))
1024 rc = rtJsonParseArray(pTokenizer, pVal, pErrInfo);
1025 break;
1026 case RTJSONTOKENCLASS_BEGIN_OBJECT:
1027 rtJsonTokenizerConsume(pTokenizer);
1028 pVal = rtJsonValueCreate(RTJSONVALTYPE_OBJECT);
1029 if (RT_LIKELY(pVal))
1030 rc = rtJsonParseObject(pTokenizer, pVal, pErrInfo);
1031 break;
1032 case RTJSONTOKENCLASS_STRING:
1033 pVal = rtJsonValueCreate(RTJSONVALTYPE_STRING);
1034 if (RT_LIKELY(pVal))
1035 pVal->Type.String.pszStr = pToken->Class.String.pszStr;
1036 rtJsonTokenizerConsume(pTokenizer);
1037 break;
1038 case RTJSONTOKENCLASS_NUMBER:
1039 pVal = rtJsonValueCreate(RTJSONVALTYPE_NUMBER);
1040 if (RT_LIKELY(pVal))
1041 pVal->Type.Number.i64Num = pToken->Class.Number.i64Num;
1042 rtJsonTokenizerConsume(pTokenizer);
1043 break;
1044 case RTJSONTOKENCLASS_NULL:
1045 rtJsonTokenizerConsume(pTokenizer);
1046 pVal = rtJsonValueCreate(RTJSONVALTYPE_NULL);
1047 break;
1048 case RTJSONTOKENCLASS_FALSE:
1049 rtJsonTokenizerConsume(pTokenizer);
1050 pVal = rtJsonValueCreate(RTJSONVALTYPE_FALSE);
1051 break;
1052 case RTJSONTOKENCLASS_TRUE:
1053 rtJsonTokenizerConsume(pTokenizer);
1054 pVal = rtJsonValueCreate(RTJSONVALTYPE_TRUE);
1055 break;
1056 case RTJSONTOKENCLASS_END_ARRAY:
1057 case RTJSONTOKENCLASS_END_OBJECT:
1058 case RTJSONTOKENCLASS_NAME_SEPARATOR:
1059 case RTJSONTOKENCLASS_VALUE_SEPARATOR:
1060 case RTJSONTOKENCLASS_EOS:
1061 default:
1062 /** @todo: Error info */
1063 rc = VERR_JSON_MALFORMED;
1064 break;
1065 }
1066
1067 if (RT_SUCCESS(rc))
1068 {
1069 if (pVal)
1070 *ppJsonVal = pVal;
1071 else
1072 rc = VERR_NO_MEMORY;
1073 }
1074 else if (pVal)
1075 rtJsonValDestroy(pVal);
1076
1077 return rc;
1078}
1079
1080/**
1081 * Entry point to parse a JSON document.
1082 *
1083 * @returns IPRT status code.
1084 * @param pTokenizer The tokenizer state.
1085 * @param ppJsonVal Where to store the root JSON value on success.
1086 * @param pErrInfo Where to store extended error info. Optional.
1087 */
1088static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal,
1089 PRTERRINFO pErrInfo)
1090{
1091 PRTJSONTOKEN pToken = NULL;
1092 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1093 if (RT_SUCCESS(rc))
1094 rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal, pErrInfo);
1095
1096 return rc;
1097}
1098
1099/**
1100 * Read callback for RTJsonParseFromBuf().
1101 */
1102static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, size_t offInput,
1103 void *pvBuf, size_t cbBuf,
1104 size_t *pcbRead)
1105{
1106 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1107 size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0;
1108
1109 if (cbLeft)
1110 memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf));
1111
1112 *pcbRead = RT_MIN(cbLeft, cbBuf);
1113
1114 return VINF_SUCCESS;
1115}
1116
1117/**
1118 * Read callback for RTJsonParseFromString().
1119 */
1120static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, size_t offInput,
1121 void *pvBuf, size_t cbBuf,
1122 size_t *pcbRead)
1123{
1124 const char *pszStr = (const char *)pvUser;
1125 size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */
1126 size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0;
1127
1128 if (cbLeft)
1129 memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf));
1130
1131 *pcbRead = RT_MIN(cbLeft, cbBuf);
1132
1133 return VINF_SUCCESS;
1134}
1135
1136/**
1137 * Read callback for RTJsonParseFromFile().
1138 */
1139static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, size_t offInput,
1140 void *pvBuf, size_t cbBuf,
1141 size_t *pcbRead)
1142{
1143 int rc = VINF_SUCCESS;
1144 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1145 size_t cbRead = 0;
1146
1147 rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead);
1148 if (RT_SUCCESS(rc))
1149 *pcbRead = cbRead;
1150
1151 return rc;
1152}
1153
1154RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf,
1155 PRTERRINFO pErrInfo)
1156{
1157 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1158 AssertPtrReturn(pbBuf, VERR_INVALID_POINTER);
1159 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
1160
1161 int rc = VINF_SUCCESS;
1162 RTJSONREADERARGS Args;
1163 RTJSONTOKENIZER Tokenizer;
1164
1165 Args.cbData = cbBuf;
1166 Args.u.pbBuf = pbBuf;
1167
1168 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromBuf, &Args);
1169 if (RT_SUCCESS(rc))
1170 {
1171 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1172 rtJsonTokenizerDestroy(&Tokenizer);
1173 }
1174
1175 return rc;
1176}
1177
1178RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo)
1179{
1180 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1181 AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
1182
1183 int rc = VINF_SUCCESS;
1184 RTJSONTOKENIZER Tokenizer;
1185
1186 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromString, (void *)pszStr);
1187 if (RT_SUCCESS(rc))
1188 {
1189 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1190 rtJsonTokenizerDestroy(&Tokenizer);
1191 }
1192
1193 return rc;
1194}
1195
1196RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo)
1197{
1198 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1199 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1200
1201 int rc = VINF_SUCCESS;
1202 RTJSONREADERARGS Args;
1203
1204 Args.cbData = 0;
1205 rc = RTStrmOpen(pszFilename, "r", &Args.u.hStream);
1206 if (RT_SUCCESS(rc))
1207 {
1208 RTJSONTOKENIZER Tokenizer;
1209
1210 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromFile, &Args);
1211 if (RT_SUCCESS(rc))
1212 {
1213 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1214 rtJsonTokenizerDestroy(&Tokenizer);
1215 }
1216 RTStrmClose(Args.u.hStream);
1217 }
1218
1219 return rc;
1220}
1221
1222RTDECL(uint32_t) RTJsonValueRetain(RTJSONVAL hJsonVal)
1223{
1224 PRTJSONVALINT pThis = hJsonVal;
1225 AssertPtrReturn(pThis, UINT32_MAX);
1226
1227 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1228 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1229 return cRefs;
1230}
1231
1232RTDECL(uint32_t) RTJsonValueRelease(RTJSONVAL hJsonVal)
1233{
1234 PRTJSONVALINT pThis = hJsonVal;
1235 if (pThis == NIL_RTJSONVAL)
1236 return 0;
1237 AssertPtrReturn(pThis, UINT32_MAX);
1238
1239 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1240 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1241 if (cRefs == 0)
1242 rtJsonValDestroy(pThis);
1243 return cRefs;
1244}
1245
1246RTDECL(RTJSONVALTYPE) RTJsonValueGetType(RTJSONVAL hJsonVal)
1247{
1248 PRTJSONVALINT pThis = hJsonVal;
1249 if (pThis == NIL_RTJSONVAL)
1250 return RTJSONVALTYPE_INVALID;
1251 AssertPtrReturn(pThis, RTJSONVALTYPE_INVALID);
1252
1253 return pThis->enmType;
1254}
1255
1256RTDECL(const char *) RTJsonValueGetString(RTJSONVAL hJsonVal)
1257{
1258 PRTJSONVALINT pThis = hJsonVal;
1259 AssertReturn(pThis != NIL_RTJSONVAL, NULL);
1260 AssertReturn(pThis->enmType == RTJSONVALTYPE_STRING, NULL);
1261
1262 return pThis->Type.String.pszStr;
1263}
1264
1265RTDECL(int) RTJsonValueGetStringEx(RTJSONVAL hJsonVal, const char **ppszStr)
1266{
1267 PRTJSONVALINT pThis = hJsonVal;
1268 AssertPtrReturn(ppszStr, VERR_INVALID_POINTER);
1269 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1270 AssertReturn(pThis->enmType == RTJSONVALTYPE_STRING, VERR_JSON_VALUE_INVALID_TYPE);
1271
1272 *ppszStr = pThis->Type.String.pszStr;
1273 return VINF_SUCCESS;
1274}
1275
1276RTDECL(int) RTJsonValueGetNumber(RTJSONVAL hJsonVal, int64_t *pi64Num)
1277{
1278 PRTJSONVALINT pThis = hJsonVal;
1279 AssertPtrReturn(pi64Num, VERR_INVALID_POINTER);
1280 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1281 AssertReturn(pThis->enmType == RTJSONVALTYPE_NUMBER, VERR_JSON_VALUE_INVALID_TYPE);
1282
1283 *pi64Num = pThis->Type.Number.i64Num;
1284 return VINF_SUCCESS;
1285}
1286
1287RTDECL(int) RTJsonValueGetByName(RTJSONVAL hJsonVal, const char *pszName, PRTJSONVAL phJsonVal)
1288{
1289 PRTJSONVALINT pThis = hJsonVal;
1290 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1291 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1292 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1293 AssertReturn(pThis->enmType == RTJSONVALTYPE_OBJECT, VERR_JSON_VALUE_INVALID_TYPE);
1294
1295 int rc = VERR_NOT_FOUND;
1296 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
1297 {
1298 if (!RTStrCmp(pThis->Type.Object.papszNames[i], pszName))
1299 {
1300 RTJsonValueRetain(pThis->Type.Object.papValues[i]);
1301 *phJsonVal = pThis->Type.Object.papValues[i];
1302 rc = VINF_SUCCESS;
1303 break;
1304 }
1305 }
1306
1307 return rc;
1308}
1309
1310RTDECL(uint32_t) RTJsonValueGetArraySize(RTJSONVAL hJsonVal)
1311{
1312 PRTJSONVALINT pThis = hJsonVal;
1313 AssertReturn(pThis != NIL_RTJSONVAL, 0);
1314 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, 0);
1315
1316 return pThis->Type.Array.cItems;
1317}
1318
1319RTDECL(int) RTJsonValueGetArraySizeEx(RTJSONVAL hJsonVal, uint32_t *pcItems)
1320{
1321 PRTJSONVALINT pThis = hJsonVal;
1322 AssertPtrReturn(pcItems, VERR_INVALID_POINTER);
1323 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1324 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, VERR_JSON_VALUE_INVALID_TYPE);
1325
1326 *pcItems = pThis->Type.Array.cItems;
1327 return VINF_SUCCESS;
1328}
1329
1330RTDECL(int) RTJsonValueGetByIndex(RTJSONVAL hJsonVal, uint32_t idx, PRTJSONVAL phJsonVal)
1331{
1332 PRTJSONVALINT pThis = hJsonVal;
1333 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1334 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1335 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, VERR_JSON_VALUE_INVALID_TYPE);
1336 AssertReturn(idx < pThis->Type.Array.cItems, VERR_OUT_OF_RANGE);
1337
1338 RTJsonValueRetain(pThis->Type.Array.papItems[idx]);
1339 *phJsonVal = pThis->Type.Array.papItems[idx];
1340 return VINF_SUCCESS;
1341}
1342
1343RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1344{
1345 PRTJSONVALINT pThis = hJsonVal;
1346 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1347 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1348 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY || pThis->enmType == RTJSONVALTYPE_OBJECT,
1349 VERR_JSON_VALUE_INVALID_TYPE);
1350
1351 PRTJSONITINT pIt = (PRTJSONITINT)RTMemTmpAllocZ(sizeof(RTJSONITINT));
1352 if (RT_UNLIKELY(!pIt))
1353 return VERR_NO_MEMORY;
1354
1355 RTJsonValueRetain(hJsonVal);
1356 pIt->pJsonVal = pThis;
1357 pIt->idxCur = 0;
1358 *phJsonIt = pIt;
1359
1360 return VINF_SUCCESS;
1361}
1362
1363RTDECL(int) RTJsonIteratorGetValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName)
1364{
1365 PRTJSONITINT pIt = hJsonIt;
1366 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1367 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1368
1369 int rc = VINF_SUCCESS;
1370 PRTJSONVALINT pThis = pIt->pJsonVal;
1371 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1372 {
1373 if (pIt->idxCur < pThis->Type.Array.cItems)
1374 {
1375 if (ppszName)
1376 *ppszName = NULL;
1377
1378 RTJsonValueRetain(pThis->Type.Array.papItems[pIt->idxCur]);
1379 *phJsonVal = pThis->Type.Array.papItems[pIt->idxCur];
1380 }
1381 else
1382 rc = VERR_JSON_ITERATOR_END;
1383 }
1384 else
1385 {
1386 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1387
1388 if (pIt->idxCur < pThis->Type.Object.cMembers)
1389 {
1390 if (ppszName)
1391 *ppszName = pThis->Type.Object.papszNames[pIt->idxCur];
1392
1393 RTJsonValueRetain(pThis->Type.Object.papValues[pIt->idxCur]);
1394 *phJsonVal = pThis->Type.Object.papValues[pIt->idxCur];
1395 }
1396 else
1397 rc = VERR_JSON_ITERATOR_END;
1398 }
1399
1400 return rc;
1401}
1402
1403RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt)
1404{
1405 PRTJSONITINT pIt = hJsonIt;
1406 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1407
1408 int rc = VINF_SUCCESS;
1409 PRTJSONVALINT pThis = pIt->pJsonVal;
1410 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1411 {
1412 if (pIt->idxCur < pThis->Type.Array.cItems)
1413 pIt->idxCur++;
1414 else
1415 rc = VERR_JSON_ITERATOR_END;
1416 }
1417 else
1418 {
1419 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1420
1421 if (pIt->idxCur < pThis->Type.Object.cMembers)
1422 pIt->idxCur++;
1423 else
1424 rc = VERR_JSON_ITERATOR_END;
1425 }
1426
1427 return rc;
1428}
1429
1430RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt)
1431{
1432 PRTJSONITINT pThis = hJsonIt;
1433 if (pThis == NIL_RTJSONIT)
1434 return;
1435 AssertPtrReturnVoid(pThis);
1436
1437 RTJsonValueRelease(pThis->pJsonVal);
1438 RTMemTmpFree(pThis);
1439}
1440
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