1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 16 окт. 2019 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <core/io/InStringSequence.h>
23 #include <core/io/InSequence.h>
24 #include <core/io/InFileStream.h>
25 #include <core/files/json/Parser.h>
26 
27 namespace lsp
28 {
29     namespace json
30     {
31 
Parser()32         Parser::Parser()
33         {
34             pTokenizer      = NULL;
35             pSequence       = NULL;
36             nWFlags         = 0;
37             enVersion       = JSON_LEGACY;
38             sState.mode     = READ_ROOT;
39             sState.flags    = 0;
40             sCurrent.type   = JE_UNKNOWN;
41         }
42 
~Parser()43         Parser::~Parser()
44         {
45             close();
46         }
47 
open(const char * path,json_version_t version,const char * charset)48         status_t Parser::open(const char *path, json_version_t version, const char *charset)
49         {
50             if (pTokenizer != NULL)
51                 return STATUS_BAD_STATE;
52             else if (path == NULL)
53                 return STATUS_BAD_ARGUMENTS;
54 
55             io::InFileStream *ifs = new io::InFileStream();
56             if (ifs == NULL)
57                 return STATUS_NO_MEM;
58             status_t res = ifs->open(path);
59             if (res == STATUS_OK)
60             {
61                 res     = wrap(ifs, version, WRAP_CLOSE | WRAP_DELETE, charset);
62                 if (res == STATUS_OK)
63                     return res;
64                 ifs->close();
65             }
66             delete ifs;
67 
68             return res;
69         }
70 
open(const LSPString * path,json_version_t version,const char * charset)71         status_t Parser::open(const LSPString *path, json_version_t version, const char *charset)
72         {
73             if (pTokenizer != NULL)
74                 return STATUS_BAD_STATE;
75             else if (path == NULL)
76                 return STATUS_BAD_ARGUMENTS;
77 
78             io::InFileStream *ifs = new io::InFileStream();
79             if (ifs == NULL)
80                 return STATUS_NO_MEM;
81             status_t res = ifs->open(path);
82             if (res == STATUS_OK)
83             {
84                 res     = wrap(ifs, version, WRAP_CLOSE | WRAP_DELETE, charset);
85                 if (res == STATUS_OK)
86                     return res;
87                 ifs->close();
88             }
89             delete ifs;
90 
91             return res;
92         }
93 
open(const io::Path * path,json_version_t version,const char * charset)94         status_t Parser::open(const io::Path *path, json_version_t version, const char *charset)
95         {
96             if (pTokenizer != NULL)
97                 return STATUS_BAD_STATE;
98             else if (path == NULL)
99                 return STATUS_BAD_ARGUMENTS;
100 
101             io::InFileStream *ifs = new io::InFileStream();
102             if (ifs == NULL)
103                 return STATUS_NO_MEM;
104             status_t res = ifs->open(path);
105             if (res == STATUS_OK)
106             {
107                 res     = wrap(ifs, version, WRAP_CLOSE | WRAP_DELETE, charset);
108                 if (res == STATUS_OK)
109                     return res;
110                 ifs->close();
111             }
112             delete ifs;
113 
114             return res;
115         }
116 
wrap(const char * str,json_version_t version,const char * charset)117         status_t Parser::wrap(const char *str, json_version_t version, const char *charset)
118         {
119             if (pTokenizer != NULL)
120                 return STATUS_BAD_STATE;
121             else if (str == NULL)
122                 return STATUS_BAD_ARGUMENTS;
123 
124             io::InStringSequence *seq = new io::InStringSequence();
125             if (seq == NULL)
126                 return STATUS_NO_MEM;
127 
128             status_t res = seq->wrap(str, charset);
129             if (res == STATUS_OK)
130             {
131                 if ((res = wrap(seq, version, WRAP_CLOSE | WRAP_DELETE)) == STATUS_OK)
132                     return res;
133                 seq->close();
134             }
135 
136             delete seq;
137             return res;
138         }
139 
wrap(const LSPString * str,json_version_t version)140         status_t Parser::wrap(const LSPString *str, json_version_t version)
141         {
142             if (pTokenizer != NULL)
143                 return STATUS_BAD_STATE;
144             else if (str == NULL)
145                 return STATUS_BAD_ARGUMENTS;
146 
147             io::InStringSequence *seq = new io::InStringSequence();
148             if (seq == NULL)
149                 return STATUS_NO_MEM;
150 
151             status_t res = seq->wrap(str);
152             if (res == STATUS_OK)
153             {
154                 if ((res = wrap(seq, version, WRAP_CLOSE | WRAP_DELETE)) == STATUS_OK)
155                     return res;
156                 seq->close();
157             }
158 
159             delete seq;
160             return res;
161         }
162 
wrap(io::IInStream * is,json_version_t version,size_t flags,const char * charset)163         status_t Parser::wrap(io::IInStream *is, json_version_t version, size_t flags, const char *charset)
164         {
165             if (pTokenizer != NULL)
166                 return STATUS_BAD_STATE;
167             else if (is == NULL)
168                 return STATUS_BAD_ARGUMENTS;
169 
170             io::InSequence *seq = new io::InSequence();
171             if (seq == NULL)
172                 return STATUS_NO_MEM;
173 
174             status_t res = seq->wrap(is, flags, charset);
175             if (res == STATUS_OK)
176             {
177                 if ((res = wrap(seq, version, WRAP_CLOSE | WRAP_DELETE)) == STATUS_OK)
178                     return res;
179                 seq->close();
180             }
181 
182             delete seq;
183             return res;
184         }
185 
wrap(io::IInSequence * seq,json_version_t version,size_t flags)186         status_t Parser::wrap(io::IInSequence *seq, json_version_t version, size_t flags)
187         {
188             if (pTokenizer != NULL)
189                 return STATUS_BAD_STATE;
190             else if (seq == NULL)
191                 return STATUS_BAD_ARGUMENTS;
192 
193             Tokenizer *tok = new Tokenizer(seq);
194             if (tok == NULL)
195                 return STATUS_NO_MEM;
196 
197             pTokenizer      = tok;
198             pSequence       = seq;
199             nWFlags         = flags;
200             enVersion       = version;
201             sState.mode     = READ_ROOT;
202             sState.flags    = 0;
203 
204             return STATUS_OK;
205         }
206 
close()207         status_t Parser::close()
208         {
209             status_t res = STATUS_OK;
210 
211             if (pTokenizer != NULL)
212             {
213                 delete pTokenizer;
214                 pTokenizer = NULL;
215             }
216 
217             if (pSequence != NULL)
218             {
219                 if (nWFlags & WRAP_CLOSE)
220                 {
221                     status_t xres = pSequence->close();
222                     if (res == STATUS_OK)
223                         res = xres;
224                 }
225 
226                 if (nWFlags & WRAP_DELETE)
227                     delete pSequence;
228 
229                 pSequence = NULL;
230             }
231 
232             sCurrent.type   = JE_UNKNOWN;
233             sCurrent.sValue.truncate();
234             sStack.flush();
235 
236             return res;
237         }
238 
push_state(pmode_t mode)239         status_t Parser::push_state(pmode_t mode)
240         {
241             if (!sStack.add(&sState))
242                 return STATUS_NO_MEM;
243 
244             sState.mode     = mode;
245             sState.flags    = 0;
246             return STATUS_OK;
247         }
248 
pop_state()249         status_t Parser::pop_state()
250         {
251             state_t *st = sStack.last();
252             if (st == NULL)
253                 return STATUS_BAD_STATE;
254             sState          = *st;
255             return (sStack.remove_last()) ? STATUS_OK : STATUS_BAD_STATE;
256         }
257 
lookup_token()258         token_t Parser::lookup_token()
259         {
260             return pTokenizer->get_token(true);
261         }
262 
get_current(event_t * ev)263         status_t Parser::get_current(event_t *ev)
264         {
265             if (pTokenizer == NULL)
266                 return STATUS_BAD_STATE;
267             if (ev == NULL)
268                 return STATUS_BAD_ARGUMENTS;
269 
270             switch (sCurrent.type)
271             {
272                 case JE_OBJECT_START:
273                 case JE_OBJECT_END:
274                 case JE_ARRAY_START:
275                 case JE_ARRAY_END:
276                 case JE_UNKNOWN:
277                 case JE_NULL:
278                     break;
279 
280                 case JE_PROPERTY:
281                 case JE_STRING:
282                     if (!ev->sValue.set(&sCurrent.sValue))
283                         return STATUS_NO_MEM;
284                     break;
285                 case JE_INTEGER:
286                     ev->iValue      = sCurrent.iValue;
287                     break;
288                 case JE_DOUBLE:
289                     ev->fValue      = sCurrent.fValue;
290                     break;
291                 case JE_BOOL:
292                     ev->bValue      = sCurrent.bValue;
293                     break;
294 
295                 default:
296                     return STATUS_BAD_STATE;
297             }
298 
299             ev->type = sCurrent.type;
300             return STATUS_OK;
301         }
302 
read_primitive(token_t tok)303         status_t Parser::read_primitive(token_t tok)
304         {
305             switch (tok)
306             {
307                 case JT_DQ_STRING:
308                     if (!sCurrent.sValue.set(pTokenizer->text_value()))
309                         return STATUS_NO_MEM;
310                     sCurrent.type = JE_STRING;
311                     break;
312 
313                 case JT_TRUE:
314                 case JT_FALSE:
315                     sCurrent.bValue = (tok == JT_TRUE);
316                     sCurrent.type   = JE_BOOL;
317                     break;
318 
319                 case JT_NULL:
320                     sCurrent.type   = JE_NULL;
321                     break;
322 
323                 case JT_DECIMAL:
324                     sCurrent.iValue = pTokenizer->int_value();
325                     sCurrent.type   = JE_INTEGER;
326                     break;
327 
328                 case JT_DOUBLE:
329                     sCurrent.fValue = pTokenizer->float_value();
330                     sCurrent.type   = JE_DOUBLE;
331                     break;
332 
333                 case JT_SQ_STRING:   // Single-quoted strings are allowed since JSON5
334                 case JT_IDENTIFIER:
335                     if (enVersion < JSON_VERSION5)
336                         return STATUS_BAD_TOKEN;
337                     if (!sCurrent.sValue.set(pTokenizer->text_value()))
338                         return STATUS_NO_MEM;
339                     sCurrent.type = JE_STRING;
340                     break;
341 
342                 case JT_HEXADECIMAL: // Hexadecimals are allowed since JSON5
343                     if (enVersion < JSON_VERSION5)
344                         return STATUS_BAD_TOKEN;
345                     sCurrent.iValue = pTokenizer->int_value();
346                     sCurrent.type   = JE_INTEGER;
347                     break;
348 
349                 default:
350                     return STATUS_BAD_TOKEN;
351             }
352 
353             return STATUS_OK;
354         }
355 
read_root()356         status_t Parser::read_root()
357         {
358             while (true)
359             {
360                 // Get token
361                 token_t tok     = lookup_token();
362 
363                 // Analyze token
364                 switch (tok)
365                 {
366                     case JT_EOF:            // End of input
367                         return STATUS_EOF;
368                     case JT_ERROR:          // Error input
369                         return pTokenizer->error();
370 
371                     case JT_SL_COMMENT:     // Skip comments
372                     case JT_ML_COMMENT:
373                         if (enVersion < JSON_VERSION5) // Only JSON5 allows comments
374                             return STATUS_BAD_TOKEN;
375                         break;
376 
377                     case JT_LQ_BRACE:       // Start of array
378                         if (sState.flags & PF_VALUE)
379                             return STATUS_BAD_TOKEN;
380                         sCurrent.type       = JE_ARRAY_START;
381                         sState.flags       |= PF_VALUE;
382                         return push_state(READ_ARRAY);
383 
384                     case JT_LC_BRACE:       // Start of object
385                         if (sState.flags & PF_VALUE)
386                             return STATUS_BAD_TOKEN;
387                         sCurrent.type       = JE_OBJECT_START;
388                         sState.flags       |= PF_VALUE;
389                         return push_state(READ_OBJECT);
390 
391                     case JT_SQ_STRING:
392                     case JT_DQ_STRING:
393                     case JT_TRUE:
394                     case JT_FALSE:
395                     case JT_NULL:
396                     case JT_DECIMAL:
397                     case JT_DOUBLE:
398                     case JT_HEXADECIMAL:
399                         if (sState.flags & PF_VALUE)
400                             return STATUS_BAD_TOKEN;
401                         sState.flags       |= PF_VALUE;
402                         return read_primitive(tok);
403 
404                     default:
405                         return STATUS_BAD_TOKEN;
406                 }
407             }
408         }
409 
read_array()410         status_t Parser::read_array()
411         {
412             while (true)
413             {
414                 // Get token
415                 token_t tok     = lookup_token();
416 
417                 // Analyze token
418                 switch (tok)
419                 {
420                     case JT_EOF:            // End of input
421                         return STATUS_CORRUPTED;
422                     case JT_ERROR:          // Error input
423                         return pTokenizer->error();
424 
425                     case JT_SL_COMMENT:     // Skip comments
426                     case JT_ML_COMMENT:
427                         if (enVersion < JSON_VERSION5) // Only JSON5 allows comments
428                             return STATUS_BAD_TOKEN;
429                         break;
430 
431                     case JT_COMMA:          // Comma
432                         if ((sState.flags & PF_ARRAY_ALL) != PF_VALUE)
433                             return STATUS_BAD_TOKEN;
434                         sState.flags    |= PF_COMMA;    // Add comma flag
435                         break;
436 
437                     case JT_RQ_BRACE:       // End of current array
438                         // Closing brace after comma is allowed only since JSON5
439                         if ((sState.flags & PF_COMMA) && (enVersion < JSON_VERSION5))
440                             return STATUS_BAD_TOKEN;
441                         sCurrent.type       = JE_ARRAY_END;
442                         return pop_state();
443 
444                     case JT_LQ_BRACE:       // Start of sub-array
445                     {
446                         size_t flags        = sState.flags & PF_ARRAY_ALL;
447                         if ((flags != 0) && (flags != (PF_VALUE | PF_COMMA)))
448                             return STATUS_BAD_TOKEN;
449                         sState.flags        = PF_VALUE;
450                         sCurrent.type       = JE_ARRAY_START;
451                         return push_state(READ_ARRAY);
452                     }
453 
454                     case JT_LC_BRACE:       // Start of nested object
455                     {
456                         size_t flags        = sState.flags & PF_ARRAY_ALL;
457                         if ((flags != 0) && (flags != (PF_VALUE | PF_COMMA)))
458                             return STATUS_BAD_TOKEN;
459                         sState.flags        = PF_VALUE;
460                         sCurrent.type       = JE_OBJECT_START;
461                         return push_state(READ_OBJECT);
462                     }
463 
464                     case JT_SQ_STRING:
465                     case JT_DQ_STRING:
466                     case JT_TRUE:
467                     case JT_FALSE:
468                     case JT_NULL:
469                     case JT_DECIMAL:
470                     case JT_DOUBLE:
471                     case JT_HEXADECIMAL:    // Read primitive type
472                     {
473                         size_t flags        = sState.flags & PF_ARRAY_ALL;
474                         if ((flags != 0) && (flags != (PF_VALUE | PF_COMMA)))
475                             return STATUS_BAD_TOKEN;
476                         sState.flags        = PF_VALUE;
477                         return read_primitive(tok);
478                     }
479 
480                     default:
481                         return STATUS_BAD_TOKEN;
482                 }
483             }
484         }
485 
read_object()486         status_t Parser::read_object()
487         {
488             status_t res;
489 
490             while (true)
491             {
492                 // Get token
493                 token_t tok     = lookup_token();
494 
495                 // Analyze token
496                 switch (tok)
497                 {
498                     case JT_EOF:            // End of input
499                         return STATUS_CORRUPTED;
500                     case JT_ERROR:          // Error input
501                         return pTokenizer->error();
502 
503                     case JT_SL_COMMENT:     // Skip comments
504                     case JT_ML_COMMENT:
505                         if (enVersion < JSON_VERSION5) // Only JSON5 allows comments
506                             return STATUS_BAD_TOKEN;
507                         break;
508 
509                     case JT_COMMA:          // Comma
510                         if ((sState.flags & PF_OBJECT_ALL) != (PF_PROPERTY | PF_COLON | PF_VALUE))
511                             return STATUS_BAD_TOKEN;
512                         sState.flags     |= PF_COMMA;    // Add comma flag
513                         break;
514 
515                     case JT_COLON:          // Colon
516                         if ((sState.flags & PF_OBJECT_ALL) != PF_PROPERTY)
517                             return STATUS_BAD_TOKEN;
518                         sState.flags     |= PF_COLON;
519                         break;
520 
521                     case JT_RC_BRACE:       // End of current object
522                     {
523                         size_t flags = sState.flags & PF_OBJECT_ALL;
524 
525                         // If property is present, there should be a corresponding value
526                         // JSON5 allows a comma before closing brace
527                         if (flags == PF_OBJECT_ALL)
528                         {
529                             if (enVersion < JSON_VERSION5)
530                                 return STATUS_BAD_TOKEN;
531                         }
532                         else if ((flags != 0) && (flags != (PF_PROPERTY | PF_COLON | PF_VALUE)))
533                             return STATUS_BAD_TOKEN;
534 
535                         sCurrent.type       = JE_OBJECT_END;
536                         return pop_state();
537                     }
538 
539                     case JT_LQ_BRACE:       // Start of array value
540                         // Property should be defined first
541                         if ((sState.flags & PF_OBJECT_ALL) != (PF_PROPERTY | PF_COLON))
542                             return STATUS_BAD_TOKEN;
543                         sCurrent.type       = JE_ARRAY_START;
544                         sState.flags       |= PF_VALUE;
545                         return push_state(READ_ARRAY);
546 
547                     case JT_LC_BRACE:       // Start of object value
548                         // Property should be defined first
549                         if ((sState.flags & PF_OBJECT_ALL) != (PF_PROPERTY | PF_COLON))
550                              return STATUS_BAD_TOKEN;
551                         sCurrent.type       = JE_OBJECT_START;
552                         sState.flags       |= PF_VALUE;
553                         return push_state(READ_OBJECT);
554 
555                     case JT_SQ_STRING:
556                     case JT_DQ_STRING:
557                     case JT_IDENTIFIER:     // Property name
558                     {
559                         size_t flags = sState.flags & PF_OBJECT_ALL;
560                         if ((flags == 0) || (flags == PF_OBJECT_ALL)) // Property name?
561                         {
562                             if ((res = read_primitive(tok)) == STATUS_OK)
563                             {
564                                 sState.flags        = PF_PROPERTY;
565                                 sCurrent.type       = JE_PROPERTY;  // Override type of event
566                             }
567                         }
568                         else if (flags == (PF_PROPERTY | PF_COLON)) // Value?
569                         {
570                             if ((res = read_primitive(tok)) == STATUS_OK)
571                                 sState.flags       |= PF_VALUE;
572                         }
573                         else
574                             res = STATUS_BAD_STATE;
575 
576                         return res;
577                     }
578 
579                     case JT_TRUE:
580                     case JT_FALSE:
581                     case JT_NULL:
582                     case JT_DECIMAL:
583                     case JT_DOUBLE:
584                     case JT_HEXADECIMAL:    // Read primitive type
585                     {
586                         if ((sState.flags & PF_OBJECT_ALL) != (PF_PROPERTY | PF_COLON))
587                              return STATUS_BAD_TOKEN;
588                         sState.flags    |= PF_VALUE;
589                         return read_primitive(tok);
590                     }
591 
592                     default:
593                         return STATUS_BAD_TOKEN;
594                 }
595             }
596         }
597 
read_next(event_t * ev)598         status_t Parser::read_next(event_t *ev)
599         {
600             if (pTokenizer == NULL)
601                 return STATUS_BAD_STATE;
602 
603             status_t res;
604 
605             // Root position?
606             switch (sState.mode)
607             {
608                 case READ_ROOT:
609                     res = read_root();
610                     break;
611 
612                 case READ_ARRAY:
613                     res = read_array();
614                     break;
615 
616                 case READ_OBJECT:
617                     res = read_object();
618                     break;
619 
620                 default:
621                     return STATUS_BAD_STATE;
622             }
623 
624             // Deploy result if there is place to deploy
625             if ((res == STATUS_OK) && (ev != NULL))
626                 res = get_current(ev);
627 
628             return res;
629         }
630 
read_next_type(event_type_t * type)631         status_t Parser::read_next_type(event_type_t *type)
632         {
633             event_t ev;
634             status_t res = read_next(&ev);
635             if ((res == STATUS_OK) && (type != NULL))
636                 *type = ev.type;
637             return res;
638         }
639 
read_string(LSPString * dst)640         status_t Parser::read_string(LSPString *dst)
641         {
642             event_t ev;
643             status_t res = read_next(&ev);
644             if (res != STATUS_OK)
645                 return res;
646             switch (ev.type)
647             {
648                 case JE_STRING: break;
649                 case JE_NULL: return STATUS_NULL;
650                 default: return STATUS_BAD_TYPE;
651             }
652             if (dst != NULL)
653                 dst->swap(&ev.sValue);
654             return STATUS_OK;
655         }
656 
read_double(double * dst)657         status_t Parser::read_double(double *dst)
658         {
659             event_t ev;
660             status_t res = read_next(&ev);
661             if (res != STATUS_OK)
662                 return res;
663             switch (ev.type)
664             {
665                 case JE_DOUBLE: break;
666                 case JE_NULL: return STATUS_NULL;
667                 default: return STATUS_BAD_TYPE;
668             }
669             if (dst != NULL)
670                 *dst = ev.fValue;
671             return STATUS_OK;
672         }
673 
read_int(ssize_t * dst)674         status_t Parser::read_int(ssize_t *dst)
675         {
676             event_t ev;
677             status_t res = read_next(&ev);
678             if (res != STATUS_OK)
679                 return res;
680             switch (ev.type)
681             {
682                 case JE_INTEGER: break;
683                 case JE_NULL: return STATUS_NULL;
684                 default: return STATUS_BAD_TYPE;
685             }
686             if (dst != NULL)
687                 *dst = ev.iValue;
688             return STATUS_OK;
689         }
690 
read_bool(bool * dst)691         status_t Parser::read_bool(bool *dst)
692         {
693             event_t ev;
694             status_t res = read_next(&ev);
695             if (res != STATUS_OK)
696                 return res;
697             switch (ev.type)
698             {
699                 case JE_BOOL: break;
700                 case JE_NULL: return STATUS_NULL;
701                 default: return STATUS_BAD_TYPE;
702             }
703             if (dst != NULL)
704                 *dst = ev.bValue;
705             return STATUS_OK;
706         }
707 
get_string(LSPString * dst)708         status_t Parser::get_string(LSPString *dst)
709         {
710             if (pTokenizer == NULL)
711                 return STATUS_BAD_STATE;
712             switch (sCurrent.type)
713             {
714                 case JE_STRING: break;
715                 case JE_NULL: return STATUS_NULL;
716                 default: return STATUS_BAD_TYPE;
717             }
718             if (dst != NULL)
719                 return (dst->set(&sCurrent.sValue)) ? STATUS_OK : STATUS_NO_MEM;
720             return STATUS_OK;
721         }
722 
get_double(double * dst)723         status_t Parser::get_double(double *dst)
724         {
725             if (pTokenizer == NULL)
726                 return STATUS_BAD_STATE;
727             switch (sCurrent.type)
728             {
729                 case JE_DOUBLE: break;
730                 case JE_NULL: return STATUS_NULL;
731                 default: return STATUS_BAD_TYPE;
732             }
733             if (dst != NULL)
734                 *dst = sCurrent.fValue;
735             return STATUS_OK;
736         }
737 
get_int(ssize_t * dst)738         status_t Parser::get_int(ssize_t *dst)
739         {
740             if (pTokenizer == NULL)
741                 return STATUS_BAD_STATE;
742             switch (sCurrent.type)
743             {
744                 case JE_INTEGER: break;
745                 case JE_NULL: return STATUS_NULL;
746                 default: return STATUS_BAD_TYPE;
747             }
748             if (dst != NULL)
749                 *dst = sCurrent.iValue;
750             return STATUS_OK;
751         }
752 
get_bool(bool * dst)753         status_t Parser::get_bool(bool *dst)
754         {
755             if (pTokenizer == NULL)
756                 return STATUS_BAD_STATE;
757             switch (sCurrent.type)
758             {
759                 case JE_BOOL: break;
760                 case JE_NULL: return STATUS_NULL;
761                 default: return STATUS_BAD_TYPE;
762             }
763             if (dst != NULL)
764                 *dst = sCurrent.bValue;
765             return STATUS_OK;
766         }
767 
skip_next()768         status_t Parser::skip_next()
769         {
770             status_t res = read_next(NULL);
771             if (res == STATUS_OK)
772                 res     = skip_current();
773             return res;
774         }
775 
skip_current()776         status_t Parser::skip_current()
777         {
778             status_t res;
779 
780             switch (sCurrent.type)
781             {
782                 case JE_OBJECT_START:
783                     while (true)
784                     {
785                         // Get next event
786                         if ((res = read_next(NULL)) != STATUS_OK)
787                             return res;
788 
789                         // Analyze event type
790                         if (sCurrent.type != JE_PROPERTY)
791                             return (sCurrent.type == JE_OBJECT_END) ? STATUS_OK : STATUS_BAD_TOKEN;
792 
793                         // Skip the value after property
794                         if ((res = read_next(NULL)) != STATUS_OK)
795                             return res;
796                         if ((res = skip_current()) != STATUS_OK)
797                             return res;
798                     }
799                     break;
800 
801                 case JE_ARRAY_START:
802                     while (true)
803                     {
804                         // Get next event
805                         if ((res = read_next(NULL)) != STATUS_OK)
806                             return res;
807 
808                         // Analyze event type
809                         if (sCurrent.type == JE_ARRAY_END)
810                             return STATUS_OK;
811 
812                         // Skip the value after property
813                         if ((res = skip_current()) != STATUS_OK)
814                             return res;
815                     }
816                     break;
817 
818                 case JE_PROPERTY:
819                     // Skip the value after property
820                     if ((res = read_next(NULL)) != STATUS_OK)
821                         return res;
822                     if ((res = skip_current()) != STATUS_OK)
823                         return res;
824                     break;
825 
826                 default:
827                     break;
828             }
829 
830             return STATUS_OK;
831         }
832 
833     } /* namespace json */
834 } /* namespace lsp */
835