VirtualBox

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

Last change on this file since 71725 was 69520, checked in by vboxsync, 7 years ago

Runtime/json: Plug small memory leak in out of memory error condition

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.9 KB
Line 
1/* $Id: json.cpp 69520 2017-10-30 10:46:51Z vboxsync $ */
2/** @file
3 * IPRT JSON parser API (JSON).
4 */
5
6/*
7 * Copyright (C) 2016-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/cdefs.h>
34#include <iprt/ctype.h>
35#include <iprt/json.h>
36#include <iprt/mem.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44
45/**
46 * JSON parser position information.
47 */
48typedef struct RTJSONPOS
49{
50 /** Line in the source. */
51 size_t iLine;
52 /** Current start character .*/
53 size_t iChStart;
54 /** Current end character. */
55 size_t iChEnd;
56} RTJSONPOS;
57/** Pointer to a position. */
58typedef RTJSONPOS *PRTJSONPOS;
59
60/**
61 * JSON token class.
62 */
63typedef enum RTJSONTOKENCLASS
64{
65 /** Invalid. */
66 RTJSONTOKENCLASS_INVALID = 0,
67 /** Array begin. */
68 RTJSONTOKENCLASS_BEGIN_ARRAY,
69 /** Object begin. */
70 RTJSONTOKENCLASS_BEGIN_OBJECT,
71 /** Array end. */
72 RTJSONTOKENCLASS_END_ARRAY,
73 /** Object end. */
74 RTJSONTOKENCLASS_END_OBJECT,
75 /** Separator for name/value pairs. */
76 RTJSONTOKENCLASS_NAME_SEPARATOR,
77 /** Value separator. */
78 RTJSONTOKENCLASS_VALUE_SEPARATOR,
79 /** String */
80 RTJSONTOKENCLASS_STRING,
81 /** Number. */
82 RTJSONTOKENCLASS_NUMBER,
83 /** null keyword. */
84 RTJSONTOKENCLASS_NULL,
85 /** false keyword. */
86 RTJSONTOKENCLASS_FALSE,
87 /** true keyword. */
88 RTJSONTOKENCLASS_TRUE,
89 /** End of stream */
90 RTJSONTOKENCLASS_EOS,
91 /** 32bit hack. */
92 RTJSONTOKENCLASS_32BIT_HACK = 0x7fffffff
93} RTJSONTOKENCLASS;
94/** Pointer to a token class. */
95typedef RTJSONTOKENCLASS *PRTJSONTOKENCLASS;
96
97/**
98 * JSON token.
99 */
100typedef struct RTJSONTOKEN
101{
102 /** Token class. */
103 RTJSONTOKENCLASS enmClass;
104 /** Token position in the source buffer. */
105 RTJSONPOS Pos;
106 /** Data based on the token class. */
107 union
108 {
109 /** String. */
110 struct
111 {
112 /** Pointer to the start of the string. */
113 char *pszStr;
114 } String;
115 /** Number. */
116 struct
117 {
118 int64_t i64Num;
119 } Number;
120 } Class;
121} RTJSONTOKEN;
122/** Pointer to a JSON token. */
123typedef RTJSONTOKEN *PRTJSONTOKEN;
124/** Pointer to a const script token. */
125typedef const RTJSONTOKEN *PCRTJSONTOKEN;
126
127/**
128 * Tokenizer read input callback.
129 *
130 * @returns IPRT status code.
131 * @param pvUser Opaque user data for the callee.
132 * @param offInput Start offset from the start of the input stream to read from.
133 * @param pvBuf Where to store the read data.
134 * @param cbBuf How much to read.
135 * @param pcbRead Where to store the amount of data read on succcess.
136 */
137typedef DECLCALLBACK(int) FNRTJSONTOKENIZERREAD(void *pvUser, size_t offInput, void *pvBuf, size_t cbBuf,
138 size_t *pcbRead);
139/** Pointer to a tokenizer read buffer callback. */
140typedef FNRTJSONTOKENIZERREAD *PFNRTJSONTOKENIZERREAD;
141
142/**
143 * Tokenizer state.
144 */
145typedef struct RTJSONTOKENIZER
146{
147 /** Read callback. */
148 PFNRTJSONTOKENIZERREAD pfnRead;
149 /** Opaque user data. */
150 void *pvUser;
151 /** Current offset into the input stream. */
152 size_t offInput;
153 /** Number of valid bytes in the input buffer. */
154 size_t cbBuf;
155 /* Current offset into the input buffer. */
156 size_t offBuf;
157 /** Input cache buffer. */
158 char achBuf[512];
159 /** Current position into the input stream. */
160 RTJSONPOS Pos;
161 /** Token 1. */
162 RTJSONTOKEN Token1;
163 /** Token 2. */
164 RTJSONTOKEN Token2;
165 /** Pointer to the current active token. */
166 PRTJSONTOKEN pTokenCurr;
167 /** The next token in the input stream (used for peeking). */
168 PRTJSONTOKEN pTokenNext;
169} RTJSONTOKENIZER;
170/** Pointer to a JSON tokenizer. */
171typedef RTJSONTOKENIZER *PRTJSONTOKENIZER;
172
173/** Pointer to the internal JSON value instance. */
174typedef struct RTJSONVALINT *PRTJSONVALINT;
175
176/**
177 * A JSON value.
178 */
179typedef struct RTJSONVALINT
180{
181 /** Type of the JSON value. */
182 RTJSONVALTYPE enmType;
183 /** Reference count for this JSON value. */
184 volatile uint32_t cRefs;
185 /** Type dependent data. */
186 union
187 {
188 /** String type*/
189 struct
190 {
191 /** Pointer to the string. */
192 char *pszStr;
193 } String;
194 /** Number type. */
195 struct
196 {
197 /** Signed 64-bit integer. */
198 int64_t i64Num;
199 } Number;
200 /** Array type. */
201 struct
202 {
203 /** Number of elements in the array. */
204 unsigned cItems;
205 /** Pointer to the array of items. */
206 PRTJSONVALINT *papItems;
207 } Array;
208 /** Object type. */
209 struct
210 {
211 /** Number of members. */
212 unsigned cMembers;
213 /** Pointer to the array holding the member names. */
214 char **papszNames;
215 /** Pointer to the array holding the values. */
216 PRTJSONVALINT *papValues;
217 } Object;
218 } Type;
219} RTJSONVALINT;
220
221/**
222 * A JSON iterator.
223 */
224typedef struct RTJSONITINT
225{
226 /** Referenced JSON value. */
227 PRTJSONVALINT pJsonVal;
228 /** Current index. */
229 unsigned idxCur;
230} RTJSONITINT;
231/** Pointer to the internal JSON iterator instance. */
232typedef RTJSONITINT *PRTJSONITINT;
233
234/**
235 * Passing arguments for the read callbacks.
236 */
237typedef struct RTJSONREADERARGS
238{
239 /** Buffer/File size */
240 size_t cbData;
241 /** Data specific for one callback. */
242 union
243 {
244 PRTSTREAM hStream;
245 const uint8_t *pbBuf;
246 } u;
247} RTJSONREADERARGS;
248/** Pointer to a readers argument. */
249typedef RTJSONREADERARGS *PRTJSONREADERARGS;
250
251
252/*********************************************************************************************************************************
253* Global variables *
254*********************************************************************************************************************************/
255
256static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken,
257 PRTJSONVALINT *ppJsonVal, PRTERRINFO pErrInfo);
258
259/**
260 * Fill the input buffer from the input stream.
261 *
262 * @returns IPRT status code.
263 * @param pTokenizer The tokenizer state.
264 */
265static int rtJsonTokenizerRead(PRTJSONTOKENIZER pTokenizer)
266{
267 size_t cbRead = 0;
268 int rc = pTokenizer->pfnRead(pTokenizer->pvUser, pTokenizer->offInput, &pTokenizer->achBuf[0],
269 sizeof(pTokenizer->achBuf), &cbRead);
270 if (RT_SUCCESS(rc))
271 {
272 pTokenizer->cbBuf = cbRead;
273 pTokenizer->offInput += cbRead;
274 pTokenizer->offBuf = 0;
275 /* Validate UTF-8 encoding. */
276 rc = RTStrValidateEncodingEx(&pTokenizer->achBuf[0], cbRead, 0 /* fFlags */);
277 /* If we read less than requested we reached the end and fill the remainder with terminators. */
278 if (cbRead < sizeof(pTokenizer->achBuf))
279 memset(&pTokenizer->achBuf[cbRead], 0, sizeof(pTokenizer->achBuf) - cbRead);
280 }
281
282 return rc;
283}
284
285/**
286 * Skips the given amount of characters in the input stream.
287 *
288 * @returns IPRT status code.
289 * @param pTokenizer The tokenizer state.
290 * @param cchSkip The amount of characters to skip.
291 */
292static int rtJsonTokenizerSkip(PRTJSONTOKENIZER pTokenizer, size_t cchSkip)
293{
294 int rc = VINF_SUCCESS;
295
296 /*
297 * In case we reached the end of the stream don't even attempt to read new data.
298 * Safety precaution for possible bugs in the parser causing out of bounds reads
299 */
300 if (pTokenizer->achBuf[pTokenizer->offBuf] == '\0')
301 return rc;
302
303 while ( cchSkip > 0
304 && pTokenizer->offBuf < pTokenizer->cbBuf
305 && RT_SUCCESS(rc))
306 {
307 size_t cchThisSkip = RT_MIN(cchSkip, pTokenizer->cbBuf - pTokenizer->offBuf);
308
309 pTokenizer->offBuf += cchThisSkip;
310 /* Read new data if required and we didn't reach the end yet. */
311 if ( pTokenizer->offBuf == pTokenizer->cbBuf
312 && pTokenizer->cbBuf == sizeof(pTokenizer->achBuf))
313 rc = rtJsonTokenizerRead(pTokenizer);
314
315 cchSkip -= cchThisSkip;
316 }
317
318 return rc;
319}
320
321
322/**
323 * Returns whether the tokenizer reached the end of the stream.
324 *
325 * @returns true if the tokenizer reached the end of stream marker
326 * false otherwise.
327 * @param pTokenizer The tokenizer state.
328 */
329DECLINLINE(bool) rtJsonTokenizerIsEos(PRTJSONTOKENIZER pTokenizer)
330{
331 return pTokenizer->achBuf[pTokenizer->offBuf] == '\0';
332}
333
334/**
335 * Skip one character in the input stream.
336 *
337 * @returns nothing.
338 * @param pTokenizer The tokenizer state.
339 */
340DECLINLINE(void) rtJsonTokenizerSkipCh(PRTJSONTOKENIZER pTokenizer)
341{
342 rtJsonTokenizerSkip(pTokenizer, 1);
343 pTokenizer->Pos.iChStart++;
344 pTokenizer->Pos.iChEnd++;
345}
346
347/**
348 * Returns the next char in the input buffer without advancing it.
349 *
350 * @returns Next character in the input buffer.
351 * @param pTokenizer The tokenizer state.
352 */
353DECLINLINE(char) rtJsonTokenizerPeekCh(PRTJSONTOKENIZER pTokenizer)
354{
355 return rtJsonTokenizerIsEos(pTokenizer)
356 ? '\0'
357 : pTokenizer->achBuf[pTokenizer->offBuf + 1]; /** @todo Read out of bounds */
358}
359
360/**
361 * Returns the next character in the input buffer advancing the internal
362 * position.
363 *
364 * @returns Next character in the stream.
365 * @param pTokenizer The tokenizer state.
366 */
367DECLINLINE(char) rtJsonTokenizerGetCh(PRTJSONTOKENIZER pTokenizer)
368{
369 char ch;
370
371 if (rtJsonTokenizerIsEos(pTokenizer))
372 ch = '\0';
373 else
374 ch = pTokenizer->achBuf[pTokenizer->offBuf];
375
376 return ch;
377}
378
379/**
380 * Sets a new line for the tokenizer.
381 *
382 * @returns nothing.
383 * @param pTokenizer The tokenizer state.
384 * @param cSkip Amount of characters to skip making up the new line.
385 */
386DECLINLINE(void) rtJsonTokenizerNewLine(PRTJSONTOKENIZER pTokenizer, unsigned cSkip)
387{
388 rtJsonTokenizerSkip(pTokenizer, cSkip);
389 pTokenizer->Pos.iLine++;
390 pTokenizer->Pos.iChStart = 1;
391 pTokenizer->Pos.iChEnd = 1;
392}
393
394/**
395 * Checks whether the current position in the input stream is a new line
396 * and skips it.
397 *
398 * @returns Flag whether there was a new line at the current position
399 * in the input buffer.
400 * @param pTokenizer The tokenizer state.
401 */
402DECLINLINE(bool) rtJsonTokenizerIsSkipNewLine(PRTJSONTOKENIZER pTokenizer)
403{
404 bool fNewline = true;
405
406 if ( rtJsonTokenizerGetCh(pTokenizer) == '\r'
407 && rtJsonTokenizerPeekCh(pTokenizer) == '\n')
408 rtJsonTokenizerNewLine(pTokenizer, 2);
409 else if (rtJsonTokenizerGetCh(pTokenizer) == '\n')
410 rtJsonTokenizerNewLine(pTokenizer, 1);
411 else
412 fNewline = false;
413
414 return fNewline;
415}
416
417/**
418 * Skip all whitespace starting from the current input buffer position.
419 * Skips all present comments too.
420 *
421 * @returns nothing.
422 * @param pTokenizer The tokenizer state.
423 */
424DECLINLINE(void) rtJsonTokenizerSkipWhitespace(PRTJSONTOKENIZER pTokenizer)
425{
426 while (!rtJsonTokenizerIsEos(pTokenizer))
427 {
428 while ( rtJsonTokenizerGetCh(pTokenizer) == ' '
429 || rtJsonTokenizerGetCh(pTokenizer) == '\t')
430 rtJsonTokenizerSkipCh(pTokenizer);
431
432 if ( !rtJsonTokenizerIsEos(pTokenizer)
433 && !rtJsonTokenizerIsSkipNewLine(pTokenizer))
434 break; /* Skipped everything, next is some real content. */
435 }
436}
437
438/**
439 * Get an literal token from the tokenizer.
440 *
441 * @returns IPRT status code.
442 * @param pTokenizer The tokenizer state.
443 * @param pToken The uninitialized token.
444 */
445static int rtJsonTokenizerGetLiteral(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
446{
447 int rc = VINF_SUCCESS;
448 char ch = rtJsonTokenizerGetCh(pTokenizer);
449 size_t cchLiteral = 0;
450 char szLiteral[6]; /* false + 0 terminator as the lingest possible literal. */
451 RT_ZERO(szLiteral);
452
453 pToken->Pos = pTokenizer->Pos;
454
455 Assert(RT_C_IS_ALPHA(ch));
456
457 while ( RT_C_IS_ALPHA(ch)
458 && cchLiteral < RT_ELEMENTS(szLiteral) - 1)
459 {
460 szLiteral[cchLiteral] = ch;
461 cchLiteral++;
462 rtJsonTokenizerSkipCh(pTokenizer);
463 ch = rtJsonTokenizerGetCh(pTokenizer);
464 }
465
466 if (!RTStrNCmp(&szLiteral[0], "false", RT_ELEMENTS(szLiteral)))
467 pToken->enmClass = RTJSONTOKENCLASS_FALSE;
468 else if (!RTStrNCmp(&szLiteral[0], "true", RT_ELEMENTS(szLiteral)))
469 pToken->enmClass = RTJSONTOKENCLASS_TRUE;
470 else if (!RTStrNCmp(&szLiteral[0], "null", RT_ELEMENTS(szLiteral)))
471 pToken->enmClass = RTJSONTOKENCLASS_NULL;
472 else
473 {
474 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
475 rc = VERR_JSON_MALFORMED;
476 }
477
478 pToken->Pos.iChEnd += cchLiteral;
479 return rc;
480}
481
482/**
483 * Get a numerical constant from the tokenizer.
484 *
485 * @returns IPRT status code.
486 * @param pTokenizer The tokenizer state.
487 * @param pToken The uninitialized token.
488 */
489static int rtJsonTokenizerGetNumber(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
490{
491 size_t cchNum = 0;
492 char szTmp[128]; /* Everything larger is not possible to display in signed 64bit. */
493
494 pToken->enmClass = RTJSONTOKENCLASS_NUMBER;
495
496 char ch = rtJsonTokenizerGetCh(pTokenizer);
497 while ( RT_C_IS_DIGIT(ch)
498 && cchNum < sizeof(szTmp) - 1)
499 {
500 szTmp[cchNum] = ch;
501 cchNum++;
502 rtJsonTokenizerSkipCh(pTokenizer);
503 ch = rtJsonTokenizerGetCh(pTokenizer);
504 }
505
506 int rc = VINF_SUCCESS;
507 if (RT_C_IS_DIGIT(ch) && cchNum >= sizeof(szTmp) - 1)
508 rc = VERR_NUMBER_TOO_BIG;
509 else
510 {
511 szTmp[cchNum] = '\0';
512 rc = RTStrToInt64Ex(&szTmp[0], NULL, 0, &pToken->Class.Number.i64Num);
513 Assert(RT_SUCCESS(rc) || rc == VWRN_NUMBER_TOO_BIG);
514 if (rc == VWRN_NUMBER_TOO_BIG)
515 rc = VERR_NUMBER_TOO_BIG;
516 }
517
518 return rc;
519}
520
521/**
522 * Parses a string constant.
523 *
524 * @returns IPRT status code.
525 * @param pTokenizer The tokenizer state.
526 * @param pToken The uninitialized token.
527 */
528static int rtJsonTokenizerGetString(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
529{
530 int rc = VINF_SUCCESS;
531 size_t cchStr = 0;
532 char szTmp[_4K];
533 RT_ZERO(szTmp);
534
535 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\"');
536 rtJsonTokenizerSkipCh(pTokenizer); /* Skip " */
537
538 pToken->enmClass = RTJSONTOKENCLASS_STRING;
539 pToken->Pos = pTokenizer->Pos;
540
541 char ch = rtJsonTokenizerGetCh(pTokenizer);
542 while ( ch != '\"'
543 && ch != '\0'
544 && cchStr < sizeof(szTmp) - 1)
545 {
546 if (ch == '\\')
547 {
548 /* Escape sequence, check the next character */
549 rtJsonTokenizerSkipCh(pTokenizer);
550 char chNext = rtJsonTokenizerGetCh(pTokenizer);
551 switch (chNext)
552 {
553 case '\"':
554 szTmp[cchStr] = '\"';
555 break;
556 case '\\':
557 szTmp[cchStr] = '\\';
558 break;
559 case '/':
560 szTmp[cchStr] = '/';
561 break;
562 case '\b':
563 szTmp[cchStr] = '\b';
564 break;
565 case '\n':
566 szTmp[cchStr] = '\n';
567 break;
568 case '\f':
569 szTmp[cchStr] = '\f';
570 break;
571 case '\r':
572 szTmp[cchStr] = '\r';
573 break;
574 case '\t':
575 szTmp[cchStr] = '\t';
576 break;
577 case 'u':
578 rc = VERR_NOT_SUPPORTED;
579 break;
580 default:
581 rc = VERR_JSON_MALFORMED;
582 }
583 }
584 else
585 szTmp[cchStr] = ch;
586 cchStr++;
587 rtJsonTokenizerSkipCh(pTokenizer);
588 ch = rtJsonTokenizerGetCh(pTokenizer);
589 }
590
591 if (rtJsonTokenizerGetCh(pTokenizer) == '\"')
592 rtJsonTokenizerSkipCh(pTokenizer); /* Skip closing " */
593
594 pToken->Class.String.pszStr = RTStrDupN(&szTmp[0], cchStr);
595 if (pToken->Class.String.pszStr)
596 pToken->Pos.iChEnd += cchStr;
597 else
598 rc = VERR_NO_STR_MEMORY;
599 return rc;
600}
601
602/**
603 * Get the end of stream token.
604 *
605 * @returns IPRT status code.
606 * @param pTokenizer The tokenizer state.
607 * @param pToken The uninitialized token.
608 */
609static int rtJsonTokenizerGetEos(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
610{
611 Assert(rtJsonTokenizerGetCh(pTokenizer) == '\0');
612
613 pToken->enmClass = RTJSONTOKENCLASS_EOS;
614 pToken->Pos = pTokenizer->Pos;
615 return VINF_SUCCESS;
616}
617
618/**
619 * Read the next token from the tokenizer stream.
620 *
621 * @returns IPRT status code.
622 * @param pTokenizer The tokenizer to read from.
623 * @param pToken Uninitialized token to fill the token data into.
624 */
625static int rtJsonTokenizerReadNextToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
626{
627 int rc = VINF_SUCCESS;
628
629 /* Skip all eventually existing whitespace and newlines first. */
630 rtJsonTokenizerSkipWhitespace(pTokenizer);
631
632 char ch = rtJsonTokenizerGetCh(pTokenizer);
633 if (RT_C_IS_ALPHA(ch))
634 rc = rtJsonTokenizerGetLiteral(pTokenizer, pToken);
635 else if (RT_C_IS_DIGIT(ch))
636 rc = rtJsonTokenizerGetNumber(pTokenizer, pToken);
637 else if (ch == '\"')
638 rc = rtJsonTokenizerGetString(pTokenizer, pToken);
639 else if (ch == '\0')
640 rc = rtJsonTokenizerGetEos(pTokenizer, pToken);
641 else if (ch == '{')
642 {
643 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_OBJECT;
644 rtJsonTokenizerSkipCh(pTokenizer);
645 }
646 else if (ch == '}')
647 {
648 pToken->enmClass = RTJSONTOKENCLASS_END_OBJECT;
649 rtJsonTokenizerSkipCh(pTokenizer);
650 }
651 else if (ch == '[')
652 {
653 pToken->enmClass = RTJSONTOKENCLASS_BEGIN_ARRAY;
654 rtJsonTokenizerSkipCh(pTokenizer);
655 }
656 else if (ch == ']')
657 {
658 pToken->enmClass = RTJSONTOKENCLASS_END_ARRAY;
659 rtJsonTokenizerSkipCh(pTokenizer);
660 }
661 else if (ch == ':')
662 {
663 pToken->enmClass = RTJSONTOKENCLASS_NAME_SEPARATOR;
664 rtJsonTokenizerSkipCh(pTokenizer);
665 }
666 else if (ch == ',')
667 {
668 pToken->enmClass = RTJSONTOKENCLASS_VALUE_SEPARATOR;
669 rtJsonTokenizerSkipCh(pTokenizer);
670 }
671 else
672 {
673 pToken->enmClass = RTJSONTOKENCLASS_INVALID;
674 rc = VERR_JSON_MALFORMED;
675 }
676
677 return rc;
678}
679
680/**
681 * Create a new tokenizer.
682 *
683 * @returns IPRT status code.
684 * @param pTokenizer The tokenizer state to initialize.
685 * @param pfnRead Read callback for the input stream.
686 * @param pvUser Opaque user data to pass to the callback.
687 */
688static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, PFNRTJSONTOKENIZERREAD pfnRead, void *pvUser)
689{
690 pTokenizer->pfnRead = pfnRead;
691 pTokenizer->pvUser = pvUser;
692 pTokenizer->offInput = 0;
693 pTokenizer->cbBuf = 0;
694 pTokenizer->offBuf = 0;
695 pTokenizer->Pos.iLine = 1;
696 pTokenizer->Pos.iChStart = 1;
697 pTokenizer->Pos.iChEnd = 1;
698 pTokenizer->pTokenCurr = &pTokenizer->Token1;
699 pTokenizer->pTokenNext = &pTokenizer->Token2;
700
701 RT_ZERO(pTokenizer->achBuf);
702
703 /* Fill the input buffer. */
704 int rc = rtJsonTokenizerRead(pTokenizer);
705
706 /* Fill the tokenizer with two first tokens. */
707 if (RT_SUCCESS(rc))
708 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr);
709 if (RT_SUCCESS(rc))
710 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
711
712 return rc;
713}
714
715/**
716 * Destroys a given tokenizer state.
717 *
718 * @returns nothing.
719 * @param pTokenizer The tokenizer to destroy.
720 */
721static void rtJsonTokenizerDestroy(PRTJSONTOKENIZER pTokenizer)
722{
723 RT_NOREF_PV(pTokenizer);
724}
725
726/**
727 * Get the current token in the input stream.
728 *
729 * @returns Pointer to the next token in the stream.
730 * @param pTokenizer The tokenizer state.
731 * @param ppToken Where to store the pointer to the current token on success.
732 */
733DECLINLINE(int) rtJsonTokenizerGetToken(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN *ppToken)
734{
735 *ppToken = pTokenizer->pTokenCurr;
736 return VINF_SUCCESS;
737}
738
739/**
740 * Consume the current token advancing to the next in the stream.
741 *
742 * @returns nothing.
743 * @param pTokenizer The tokenizer state.
744 */
745static void rtJsonTokenizerConsume(PRTJSONTOKENIZER pTokenizer)
746{
747 PRTJSONTOKEN pTokenTmp = pTokenizer->pTokenCurr;
748
749 /* Switch next token to current token and read in the next token. */
750 pTokenizer->pTokenCurr = pTokenizer->pTokenNext;
751 pTokenizer->pTokenNext = pTokenTmp;
752 rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
753}
754
755/**
756 * Consumes the current token if it matches the given class returning an indicator.
757 *
758 * @returns true if the class matched and the token was consumed.
759 * @retval false otherwise.
760 * @param pTokenizer The tokenizer state.
761 * @param enmClass The token class to match against.
762 */
763static bool rtJsonTokenizerConsumeIfMatched(PRTJSONTOKENIZER pTokenizer, RTJSONTOKENCLASS enmClass)
764{
765 PRTJSONTOKEN pToken = NULL;
766 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
767 AssertRC(rc);
768
769 if (pToken->enmClass == enmClass)
770 {
771 rtJsonTokenizerConsume(pTokenizer);
772 return true;
773 }
774
775 return false;
776}
777
778/**
779 * Destroys a given JSON value releasing the reference to all child values.
780 *
781 * @returns nothing.
782 * @param pThis The JSON value to destroy.
783 */
784static void rtJsonValDestroy(PRTJSONVALINT pThis)
785{
786 switch (pThis->enmType)
787 {
788 case RTJSONVALTYPE_OBJECT:
789 for (unsigned i = 0; i < pThis->Type.Object.cMembers; i++)
790 {
791 RTStrFree(pThis->Type.Object.papszNames[i]);
792 RTJsonValueRelease(pThis->Type.Object.papValues[i]);
793 }
794 RTMemFree(pThis->Type.Object.papszNames);
795 RTMemFree(pThis->Type.Object.papValues);
796 break;
797 case RTJSONVALTYPE_ARRAY:
798 for (unsigned i = 0; i < pThis->Type.Array.cItems; i++)
799 RTJsonValueRelease(pThis->Type.Array.papItems[i]);
800 RTMemFree(pThis->Type.Array.papItems);
801 break;
802 case RTJSONVALTYPE_STRING:
803 RTStrFree(pThis->Type.String.pszStr);
804 break;
805 case RTJSONVALTYPE_NUMBER:
806 case RTJSONVALTYPE_NULL:
807 case RTJSONVALTYPE_TRUE:
808 case RTJSONVALTYPE_FALSE:
809 /* nothing to do. */
810 break;
811 default:
812 AssertMsgFailed(("Invalid JSON value type: %u\n", pThis->enmType));
813 }
814 RTMemFree(pThis);
815}
816
817/**
818 * Creates a new JSON value with the given type.
819 *
820 * @returns Pointer to JSON value on success, NULL if out of memory.
821 * @param enmType The JSON value type.
822 */
823static PRTJSONVALINT rtJsonValueCreate(RTJSONVALTYPE enmType)
824{
825 PRTJSONVALINT pThis = (PRTJSONVALINT)RTMemAllocZ(sizeof(RTJSONVALINT));
826 if (RT_LIKELY(pThis))
827 {
828 pThis->enmType = enmType;
829 pThis->cRefs = 1;
830 }
831
832 return pThis;
833}
834
835/**
836 * Parses an JSON array.
837 *
838 * @returns IPRT status code.
839 * @param pTokenizer The tokenizer to use.
840 * @param pJsonVal The JSON array value to fill in.
841 * @param pErrInfo Where to store extended error info. Optional.
842 */
843static int rtJsonParseArray(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
844{
845 int rc = VINF_SUCCESS;
846 PRTJSONTOKEN pToken = NULL;
847 uint32_t cItems = 0;
848 uint32_t cItemsMax = 0;
849 PRTJSONVALINT *papItems = NULL;
850
851 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
852 while ( RT_SUCCESS(rc)
853 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY
854 && pToken->enmClass != RTJSONTOKENCLASS_EOS)
855 {
856 PRTJSONVALINT pVal = NULL;
857 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
858 if (RT_SUCCESS(rc))
859 {
860 if (cItems == cItemsMax)
861 {
862 cItemsMax += 10;
863 PRTJSONVALINT *papItemsNew = (PRTJSONVALINT *)RTMemRealloc(papItems, cItemsMax * sizeof(PRTJSONVALINT));
864 if (RT_UNLIKELY(!papItemsNew))
865 {
866 rc = VERR_NO_MEMORY;
867 break;
868 }
869 papItems = papItemsNew;
870 }
871
872 Assert(cItems < cItemsMax);
873 papItems[cItems] = pVal;
874 cItems++;
875 }
876
877 /* Skip value separator and continue with next token. */
878 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
879 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
880
881 if ( RT_SUCCESS(rc)
882 && !fSkippedSep
883 && pToken->enmClass != RTJSONTOKENCLASS_END_ARRAY)
884 rc = VERR_JSON_MALFORMED;
885 }
886
887 if (RT_SUCCESS(rc))
888 {
889 if (pToken->enmClass == RTJSONTOKENCLASS_END_ARRAY)
890 {
891 rtJsonTokenizerConsume(pTokenizer);
892 pJsonVal->Type.Array.cItems = cItems;
893 pJsonVal->Type.Array.papItems = papItems;
894 }
895 else
896 rc = VERR_JSON_MALFORMED;
897 }
898
899 if (RT_FAILURE(rc))
900 {
901 for (uint32_t i = 0; i < cItems; i++)
902 RTJsonValueRelease(papItems[i]);
903 RTMemFree(papItems);
904 }
905
906 return rc;
907}
908
909/**
910 * Parses an JSON object.
911 *
912 * @returns IPRT status code.
913 * @param pTokenizer The tokenizer to use.
914 * @param pJsonVal The JSON object value to fill in.
915 * @param pErrInfo Where to store extended error info. Optional.
916 */
917static int rtJsonParseObject(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT pJsonVal, PRTERRINFO pErrInfo)
918{
919 int rc = VINF_SUCCESS;
920 PRTJSONTOKEN pToken = NULL;
921 uint32_t cMembers = 0;
922 uint32_t cMembersMax = 0;
923 PRTJSONVALINT *papValues = NULL;
924 char **papszNames = NULL;
925
926 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
927 while ( RT_SUCCESS(rc)
928 && pToken->enmClass == RTJSONTOKENCLASS_STRING)
929 {
930 char *pszName = pToken->Class.String.pszStr;
931
932 rtJsonTokenizerConsume(pTokenizer);
933 if (rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_NAME_SEPARATOR))
934 {
935 PRTJSONVALINT pVal = NULL;
936 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
937 if (RT_SUCCESS(rc))
938 rc = rtJsonParseValue(pTokenizer, pToken, &pVal, pErrInfo);
939 if (RT_SUCCESS(rc))
940 {
941 if (cMembers == cMembersMax)
942 {
943 cMembersMax += 10;
944 PRTJSONVALINT *papValuesNew = (PRTJSONVALINT *)RTMemRealloc(papValues, cMembersMax * sizeof(PRTJSONVALINT));
945 char **papszNamesNew = (char **)RTMemRealloc(papValues, cMembersMax * sizeof(char *));
946 if (RT_UNLIKELY(!papValuesNew || !papszNamesNew))
947 {
948 if (papValuesNew)
949 RTMemFree(papValuesNew);
950 if (papszNamesNew)
951 RTMemFree(papszNamesNew);
952 rc = VERR_NO_MEMORY;
953 break;
954 }
955
956 papValues = papValuesNew;
957 papszNames = papszNamesNew;
958 }
959
960 Assert(cMembers < cMembersMax);
961 papszNames[cMembers] = pszName;
962 papValues[cMembers] = pVal;
963 cMembers++;
964
965 /* Skip value separator and continue with next token. */
966 bool fSkippedSep = rtJsonTokenizerConsumeIfMatched(pTokenizer, RTJSONTOKENCLASS_VALUE_SEPARATOR);
967 rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
968
969 if ( RT_SUCCESS(rc)
970 && !fSkippedSep
971 && pToken->enmClass != RTJSONTOKENCLASS_END_OBJECT)
972 rc = VERR_JSON_MALFORMED;
973 }
974 }
975 else
976 rc = VERR_JSON_MALFORMED;
977 }
978
979 if (RT_SUCCESS(rc))
980 {
981 if (pToken->enmClass == RTJSONTOKENCLASS_END_OBJECT)
982 {
983 rtJsonTokenizerConsume(pTokenizer);
984 pJsonVal->Type.Object.cMembers = cMembers;
985 pJsonVal->Type.Object.papValues = papValues;
986 pJsonVal->Type.Object.papszNames = papszNames;
987 }
988 else
989 rc = VERR_JSON_MALFORMED;
990 }
991
992 if (RT_FAILURE(rc))
993 {
994 for (uint32_t i = 0; i < cMembers; i++)
995 {
996 RTJsonValueRelease(papValues[i]);
997 RTStrFree(papszNames[i]);
998 }
999 RTMemFree(papValues);
1000 RTMemFree(papszNames);
1001 }
1002
1003 return rc;
1004}
1005
1006/**
1007 * Parses a single JSON value and returns it on success.
1008 *
1009 * @returns IPRT status code.
1010 * @param pTokenizer The tokenizer to use.
1011 * @param pToken The token to parse.
1012 * @param ppJsonVal Where to store the pointer to the JSON value on success.
1013 * @param pErrInfo Where to store extended error info. Optional.
1014 */
1015static int rtJsonParseValue(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken,
1016 PRTJSONVALINT *ppJsonVal, PRTERRINFO pErrInfo)
1017{
1018 int rc = VINF_SUCCESS;
1019 PRTJSONVALINT pVal = NULL;
1020
1021 switch (pToken->enmClass)
1022 {
1023 case RTJSONTOKENCLASS_BEGIN_ARRAY:
1024 rtJsonTokenizerConsume(pTokenizer);
1025 pVal = rtJsonValueCreate(RTJSONVALTYPE_ARRAY);
1026 if (RT_LIKELY(pVal))
1027 rc = rtJsonParseArray(pTokenizer, pVal, pErrInfo);
1028 break;
1029 case RTJSONTOKENCLASS_BEGIN_OBJECT:
1030 rtJsonTokenizerConsume(pTokenizer);
1031 pVal = rtJsonValueCreate(RTJSONVALTYPE_OBJECT);
1032 if (RT_LIKELY(pVal))
1033 rc = rtJsonParseObject(pTokenizer, pVal, pErrInfo);
1034 break;
1035 case RTJSONTOKENCLASS_STRING:
1036 pVal = rtJsonValueCreate(RTJSONVALTYPE_STRING);
1037 if (RT_LIKELY(pVal))
1038 pVal->Type.String.pszStr = pToken->Class.String.pszStr;
1039 rtJsonTokenizerConsume(pTokenizer);
1040 break;
1041 case RTJSONTOKENCLASS_NUMBER:
1042 pVal = rtJsonValueCreate(RTJSONVALTYPE_NUMBER);
1043 if (RT_LIKELY(pVal))
1044 pVal->Type.Number.i64Num = pToken->Class.Number.i64Num;
1045 rtJsonTokenizerConsume(pTokenizer);
1046 break;
1047 case RTJSONTOKENCLASS_NULL:
1048 rtJsonTokenizerConsume(pTokenizer);
1049 pVal = rtJsonValueCreate(RTJSONVALTYPE_NULL);
1050 break;
1051 case RTJSONTOKENCLASS_FALSE:
1052 rtJsonTokenizerConsume(pTokenizer);
1053 pVal = rtJsonValueCreate(RTJSONVALTYPE_FALSE);
1054 break;
1055 case RTJSONTOKENCLASS_TRUE:
1056 rtJsonTokenizerConsume(pTokenizer);
1057 pVal = rtJsonValueCreate(RTJSONVALTYPE_TRUE);
1058 break;
1059 case RTJSONTOKENCLASS_END_ARRAY:
1060 case RTJSONTOKENCLASS_END_OBJECT:
1061 case RTJSONTOKENCLASS_NAME_SEPARATOR:
1062 case RTJSONTOKENCLASS_VALUE_SEPARATOR:
1063 case RTJSONTOKENCLASS_EOS:
1064 default:
1065 /** @todo Error info */
1066 rc = VERR_JSON_MALFORMED;
1067 break;
1068 }
1069
1070 if (RT_SUCCESS(rc))
1071 {
1072 if (pVal)
1073 *ppJsonVal = pVal;
1074 else
1075 rc = VERR_NO_MEMORY;
1076 }
1077 else if (pVal)
1078 rtJsonValDestroy(pVal);
1079
1080 return rc;
1081}
1082
1083/**
1084 * Entry point to parse a JSON document.
1085 *
1086 * @returns IPRT status code.
1087 * @param pTokenizer The tokenizer state.
1088 * @param ppJsonVal Where to store the root JSON value on success.
1089 * @param pErrInfo Where to store extended error info. Optional.
1090 */
1091static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal,
1092 PRTERRINFO pErrInfo)
1093{
1094 PRTJSONTOKEN pToken = NULL;
1095 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
1096 if (RT_SUCCESS(rc))
1097 rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal, pErrInfo);
1098
1099 return rc;
1100}
1101
1102/**
1103 * Read callback for RTJsonParseFromBuf().
1104 */
1105static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, size_t offInput,
1106 void *pvBuf, size_t cbBuf,
1107 size_t *pcbRead)
1108{
1109 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1110 size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0;
1111
1112 if (cbLeft)
1113 memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf));
1114
1115 *pcbRead = RT_MIN(cbLeft, cbBuf);
1116
1117 return VINF_SUCCESS;
1118}
1119
1120/**
1121 * Read callback for RTJsonParseFromString().
1122 */
1123static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, size_t offInput,
1124 void *pvBuf, size_t cbBuf,
1125 size_t *pcbRead)
1126{
1127 const char *pszStr = (const char *)pvUser;
1128 size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */
1129 size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0;
1130
1131 if (cbLeft)
1132 memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf));
1133
1134 *pcbRead = RT_MIN(cbLeft, cbBuf);
1135
1136 return VINF_SUCCESS;
1137}
1138
1139/**
1140 * Read callback for RTJsonParseFromFile().
1141 */
1142static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, size_t offInput,
1143 void *pvBuf, size_t cbBuf,
1144 size_t *pcbRead)
1145{
1146 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
1147
1148 RT_NOREF_PV(offInput);
1149
1150 size_t cbRead = 0;
1151 int rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead);
1152 if (RT_SUCCESS(rc))
1153 *pcbRead = cbRead;
1154
1155 return rc;
1156}
1157
1158RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf,
1159 PRTERRINFO pErrInfo)
1160{
1161 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1162 AssertPtrReturn(pbBuf, VERR_INVALID_POINTER);
1163 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
1164
1165 RTJSONTOKENIZER Tokenizer;
1166 RTJSONREADERARGS Args;
1167 Args.cbData = cbBuf;
1168 Args.u.pbBuf = pbBuf;
1169
1170 int rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromBuf, &Args);
1171 if (RT_SUCCESS(rc))
1172 {
1173 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
1174 rtJsonTokenizerDestroy(&Tokenizer);
1175 }
1176
1177 return rc;
1178}
1179
1180RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo)
1181{
1182 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1183 AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
1184
1185 RTJSONTOKENIZER Tokenizer;
1186 int 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) RTJsonValueQueryString(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) RTJsonValueQueryInteger(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) RTJsonValueQueryByName(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(int) RTJsonValueQueryIntegerByName(RTJSONVAL hJsonVal, const char *pszName, int64_t *pi64Num)
1311{
1312 RTJSONVAL hJsonValNum = NIL_RTJSONVAL;
1313 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValNum);
1314 if (RT_SUCCESS(rc))
1315 {
1316 rc = RTJsonValueQueryInteger(hJsonValNum, pi64Num);
1317 RTJsonValueRelease(hJsonValNum);
1318 }
1319
1320 return rc;
1321}
1322
1323RTDECL(int) RTJsonValueQueryStringByName(RTJSONVAL hJsonVal, const char *pszName, char **ppszStr)
1324{
1325 RTJSONVAL hJsonValStr = NIL_RTJSONVAL;
1326 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValStr);
1327 if (RT_SUCCESS(rc))
1328 {
1329 const char *pszStr = NULL;
1330 rc = RTJsonValueQueryString(hJsonValStr, &pszStr);
1331 if (RT_SUCCESS(rc))
1332 {
1333 *ppszStr = RTStrDup(pszStr);
1334 if (!*ppszStr)
1335 rc = VERR_NO_STR_MEMORY;
1336 }
1337 RTJsonValueRelease(hJsonValStr);
1338 }
1339
1340 return rc;
1341}
1342
1343RTDECL(int) RTJsonValueQueryBooleanByName(RTJSONVAL hJsonVal, const char *pszName, bool *pfBoolean)
1344{
1345 AssertPtrReturn(pfBoolean, VERR_INVALID_POINTER);
1346
1347 RTJSONVAL hJsonValBool = NIL_RTJSONVAL;
1348 int rc = RTJsonValueQueryByName(hJsonVal, pszName, &hJsonValBool);
1349 if (RT_SUCCESS(rc))
1350 {
1351 RTJSONVALTYPE enmType = RTJsonValueGetType(hJsonValBool);
1352 if (enmType == RTJSONVALTYPE_TRUE)
1353 *pfBoolean = true;
1354 else if (enmType == RTJSONVALTYPE_FALSE)
1355 *pfBoolean = false;
1356 else
1357 rc = VERR_JSON_VALUE_INVALID_TYPE;
1358 RTJsonValueRelease(hJsonValBool);
1359 }
1360
1361 return rc;
1362}
1363
1364RTDECL(unsigned) RTJsonValueGetArraySize(RTJSONVAL hJsonVal)
1365{
1366 PRTJSONVALINT pThis = hJsonVal;
1367 AssertReturn(pThis != NIL_RTJSONVAL, 0);
1368 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, 0);
1369
1370 return pThis->Type.Array.cItems;
1371}
1372
1373RTDECL(int) RTJsonValueQueryArraySize(RTJSONVAL hJsonVal, unsigned *pcItems)
1374{
1375 PRTJSONVALINT pThis = hJsonVal;
1376 AssertPtrReturn(pcItems, VERR_INVALID_POINTER);
1377 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1378 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, VERR_JSON_VALUE_INVALID_TYPE);
1379
1380 *pcItems = pThis->Type.Array.cItems;
1381 return VINF_SUCCESS;
1382}
1383
1384RTDECL(int) RTJsonValueQueryByIndex(RTJSONVAL hJsonVal, unsigned idx, PRTJSONVAL phJsonVal)
1385{
1386 PRTJSONVALINT pThis = hJsonVal;
1387 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1388 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1389 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY, VERR_JSON_VALUE_INVALID_TYPE);
1390 AssertReturn(idx < pThis->Type.Array.cItems, VERR_OUT_OF_RANGE);
1391
1392 RTJsonValueRetain(pThis->Type.Array.papItems[idx]);
1393 *phJsonVal = pThis->Type.Array.papItems[idx];
1394 return VINF_SUCCESS;
1395}
1396
1397RTDECL(int) RTJsonIteratorBegin(RTJSONVAL hJsonVal, PRTJSONIT phJsonIt)
1398{
1399 PRTJSONVALINT pThis = hJsonVal;
1400 AssertPtrReturn(phJsonIt, VERR_INVALID_POINTER);
1401 AssertReturn(pThis != NIL_RTJSONVAL, VERR_INVALID_HANDLE);
1402 AssertReturn(pThis->enmType == RTJSONVALTYPE_ARRAY || pThis->enmType == RTJSONVALTYPE_OBJECT,
1403 VERR_JSON_VALUE_INVALID_TYPE);
1404
1405 PRTJSONITINT pIt = (PRTJSONITINT)RTMemTmpAllocZ(sizeof(RTJSONITINT));
1406 if (RT_UNLIKELY(!pIt))
1407 return VERR_NO_MEMORY;
1408
1409 RTJsonValueRetain(hJsonVal);
1410 pIt->pJsonVal = pThis;
1411 pIt->idxCur = 0;
1412 *phJsonIt = pIt;
1413
1414 return VINF_SUCCESS;
1415}
1416
1417RTDECL(int) RTJsonIteratorQueryValue(RTJSONIT hJsonIt, PRTJSONVAL phJsonVal, const char **ppszName)
1418{
1419 PRTJSONITINT pIt = hJsonIt;
1420 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1421 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
1422
1423 int rc = VINF_SUCCESS;
1424 PRTJSONVALINT pThis = pIt->pJsonVal;
1425 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1426 {
1427 if (pIt->idxCur < pThis->Type.Array.cItems)
1428 {
1429 if (ppszName)
1430 *ppszName = NULL;
1431
1432 RTJsonValueRetain(pThis->Type.Array.papItems[pIt->idxCur]);
1433 *phJsonVal = pThis->Type.Array.papItems[pIt->idxCur];
1434 }
1435 else
1436 rc = VERR_JSON_ITERATOR_END;
1437 }
1438 else
1439 {
1440 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1441
1442 if (pIt->idxCur < pThis->Type.Object.cMembers)
1443 {
1444 if (ppszName)
1445 *ppszName = pThis->Type.Object.papszNames[pIt->idxCur];
1446
1447 RTJsonValueRetain(pThis->Type.Object.papValues[pIt->idxCur]);
1448 *phJsonVal = pThis->Type.Object.papValues[pIt->idxCur];
1449 }
1450 else
1451 rc = VERR_JSON_ITERATOR_END;
1452 }
1453
1454 return rc;
1455}
1456
1457RTDECL(int) RTJsonIteratorNext(RTJSONIT hJsonIt)
1458{
1459 PRTJSONITINT pIt = hJsonIt;
1460 AssertReturn(pIt != NIL_RTJSONIT, VERR_INVALID_HANDLE);
1461
1462 int rc = VINF_SUCCESS;
1463 PRTJSONVALINT pThis = pIt->pJsonVal;
1464 if (pThis->enmType == RTJSONVALTYPE_ARRAY)
1465 {
1466 if (pIt->idxCur < pThis->Type.Array.cItems)
1467 pIt->idxCur++;
1468
1469 if (pIt->idxCur == pThis->Type.Object.cMembers)
1470 rc = VERR_JSON_ITERATOR_END;
1471 }
1472 else
1473 {
1474 Assert(pThis->enmType == RTJSONVALTYPE_OBJECT);
1475
1476 if (pIt->idxCur < pThis->Type.Object.cMembers)
1477 pIt->idxCur++;
1478
1479 if (pIt->idxCur == pThis->Type.Object.cMembers)
1480 rc = VERR_JSON_ITERATOR_END;
1481 }
1482
1483 return rc;
1484}
1485
1486RTDECL(void) RTJsonIteratorFree(RTJSONIT hJsonIt)
1487{
1488 PRTJSONITINT pThis = hJsonIt;
1489 if (pThis == NIL_RTJSONIT)
1490 return;
1491 AssertPtrReturnVoid(pThis);
1492
1493 RTJsonValueRelease(pThis->pJsonVal);
1494 RTMemTmpFree(pThis);
1495}
1496
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