OpenCPN Partial API docs
Loading...
Searching...
No Matches
jsonreader.cpp
Go to the documentation of this file.
1
2// Name: jsonreader.cpp
3// Purpose: the wxJSONReader class: a JSON text parser
4// Author: Luciano Cattani
5// Created: 2007/10/14
6// RCS-ID: $Id: jsonreader.cpp,v 1.12 2008/03/12 10:48:19 luccat Exp $
7// Copyright: (c) 2007 Luciano Cattani
8// Licence: wxWidgets licence
10
17#ifdef NDEBUG
18// make wxLogTrace a noop if no debug set, it's really slow
19// must be defined before including debug.h
20#define wxDEBUG_LEVEL 0
21#endif
22
23#include <wx/mstream.h>
24#include <wx/sstream.h>
25#include <wx/debug.h>
26#include <wx/log.h>
27
28#include "jsonreader.h"
29
175// if you have the debug build of wxWidgets and wxJSON you can see
176// trace messages by setting the:
177// WXTRACE=traceReader StoreComment
178// environment variable
179#if wxDEBUG_LEVEL > 0
180static const wxChar* traceMask = "traceReader";
181static const wxChar* storeTraceMask = "StoreComment";
182#endif
183
185
243wxJSONReader::wxJSONReader(int flags, int maxErrors) {
244 m_flags = flags;
245 m_maxErrors = maxErrors;
246 m_noUtf8 = false;
247#if !defined(wxJSON_USE_UNICODE)
248 // in ANSI builds we can suppress UTF-8 conversion for both the writer and the
249 // reader
250 if (m_flags & wxJSONREADER_NOUTF8_STREAM) {
251 m_noUtf8 = true;
252 }
253#endif
254}
255
258
260
305int wxJSONReader::Parse(const wxString& doc, wxJSONValue* val) {
306#if !defined(wxJSON_USE_UNICODE)
307 // in ANSI builds input from a string never use UTF-8 conversion
308 bool noUtf8_bak = m_noUtf8; // save the current setting
309 m_noUtf8 = true;
310#endif
311
312 // convert the string to a UTF-8 / ANSI memory stream and calls overloaded
313 // Parse()
314 char* readBuff = nullptr;
315 wxCharBuffer utf8CB = doc.ToUTF8(); // the UTF-8 buffer
316#if !defined(wxJSON_USE_UNICODE)
317 wxCharBuffer ansiCB(doc.c_str()); // the ANSI buffer
318 if (m_noUtf8) {
319 readBuff = ansiCB.data();
320 } else {
321 readBuff = utf8CB.data();
322 }
323#else
324 readBuff = utf8CB.data();
325#endif
326
327 // now construct the temporary memory input stream
328 size_t len = strlen(readBuff);
329 wxMemoryInputStream is(readBuff, len);
330
331 int numErr = Parse(is, val);
332#if !defined(wxJSON_USE_UNICODE)
333 m_noUtf8 = noUtf8_bak;
334#endif
335 return numErr;
336}
337
339int wxJSONReader::Parse(wxInputStream& is, wxJSONValue* val) {
340 // if val == 0 the 'temp' JSON value will be passed to DoRead()
341 wxJSONValue temp;
342 m_level = 0;
343 m_depth = 0;
344 m_lineNo = 1;
345 m_colNo = 1;
346 m_peekChar = -1;
347 m_errors.clear();
348 m_warnings.clear();
349
350 // if a wxJSONValue is not passed to the Parse function
351 // we set the temparary object created on the stack
352 // I know this will slow down the validation of input
353 if (val == nullptr) {
354 val = &temp;
355 }
356 wxASSERT(val);
357
358 // set the wxJSONValue object's pointers for comment storage
359 m_next = val;
360 m_next->SetLineNo(-1);
361 m_lastStored = 0;
362 m_current = 0;
363
364 int ch = GetStart(is);
365 switch (ch) {
366 case '{':
367 val->SetType(wxJSONTYPE_OBJECT);
368 break;
369 case '[':
370 val->SetType(wxJSONTYPE_ARRAY);
371 break;
372 default:
373 AddError(_T("Cannot find a start object/array character" ));
374 return m_errors.size();
375 break;
376 }
377
378 // returning from DoRead() could be for EOF or for
379 // the closing array-object character
380 // if -1 is returned, it is as an error because the lack
381 // of close-object/array characters
382 // note that the missing close-chars error messages are
383 // added by the DoRead() function
384 ch = DoRead(is, *val);
385 return m_errors.size();
386}
387
389
400int wxJSONReader::GetStart(wxInputStream& is) {
401 int ch = 0;
402 do {
403 switch (ch) {
404 case 0:
405 ch = ReadChar(is);
406 break;
407 case '{':
408 return ch;
409 break;
410 case '[':
411 return ch;
412 break;
413 case '/':
414 ch = SkipComment(is);
415 StoreComment(0);
416 break;
417 default:
418 ch = ReadChar(is);
419 break;
420 }
421 } while (ch >= 0);
422 return ch;
423}
424
426const wxArrayString& wxJSONReader::GetErrors() const { return m_errors; }
427
429const wxArrayString& wxJSONReader::GetWarnings() const { return m_warnings; }
430
432
437int wxJSONReader::GetDepth() const { return m_depth; }
438
440int wxJSONReader::GetErrorCount() const { return m_errors.size(); }
441
443int wxJSONReader::GetWarningCount() const { return m_warnings.size(); }
444
446
461int wxJSONReader::ReadChar(wxInputStream& is) {
462 if (is.Eof()) {
463 return -1;
464 }
465
466 unsigned char ch = is.GetC();
467 size_t last = is.LastRead(); // returns ZERO if EOF
468 if (last == 0) {
469 return -1;
470 }
471
472 // the function also converts CR in LF. only LF is returned
473 // in the case of CR+LF
474 int nextChar;
475
476 if (ch == '\r') {
477 m_colNo = 1;
478 nextChar = PeekChar(is);
479 if (nextChar == -1) {
480 return -1;
481 } else if (nextChar == '\n') {
482 ch = is.GetC();
483 }
484 }
485 if (ch == '\n') {
486 ++m_lineNo;
487 m_colNo = 1;
488 } else {
489 ++m_colNo;
490 }
491 return (int)ch;
492}
493
495
503int wxJSONReader::PeekChar(wxInputStream& is) {
504 int ch = -1;
505 unsigned char c;
506 if (!is.Eof()) {
507 c = is.Peek();
508 ch = c;
509 }
510 return ch;
511}
512
514
537int wxJSONReader::DoRead(wxInputStream& is, wxJSONValue& parent) {
538 ++m_level;
539 if (m_depth < m_level) {
541 }
542
543 // 'value' is the wxJSONValue structure that has to be
544 // read. Data read from the JSON text input is stored
545 // in the following object.
546 wxJSONValue value(wxJSONTYPE_INVALID);
547
548 // sets the pointers to the current, next and last-stored objects
549 // in order to determine the value to which a comment refers to
550 m_next = &value;
551 m_current = &parent;
553 m_lastStored = 0;
554
555 // the 'key' string is stored from 'value' when a ':' is encontered
556 wxString key;
557
558 // the character read: -1=EOF, 0=to be read
559 int ch = 0;
560
561 do { // we read until ch < 0
562 switch (ch) {
563 case 0:
564 ch = ReadChar(is);
565 break;
566 case ' ':
567 case '\t':
568 case '\n':
569 case '\r':
570 ch = SkipWhiteSpace(is);
571 break;
572 case -1: // the EOF
573 break;
574 case '/':
575 ch = SkipComment(is);
576 StoreComment(&parent);
577 break;
578
579 case '{':
580 if (parent.IsObject()) {
581 if (key.empty()) {
582 AddError("\'{\' is not allowed here (\'name\' is missing");
583 }
584 if (value.IsValid()) {
585 AddError("\'{\' cannot follow a \'value\'");
586 }
587 } else if (parent.IsArray()) {
588 if (value.IsValid()) {
589 AddError("\'{\' cannot follow a \'value\' in JSON array");
590 }
591 } else {
592 wxJSON_ASSERT(0); // always fails
593 }
594
595 // the openobject char cause the DoRead() to be called recursively
596 value.SetType(wxJSONTYPE_OBJECT);
597 ch = DoRead(is, value);
598 break;
599
600 case '}':
601 if (!parent.IsObject()) {
603 wxJSONREADER_MISSING,
604 _T("Trying to close an array using the \'}\' (close-object) char" ));
605 }
606 // close-object: store the current value, if any
607 StoreValue(ch, key, value, parent);
608 m_current = &parent;
609 m_next = nullptr;
611 ch = ReadChar(is);
612 return ch;
613 break;
614
615 case '[':
616 if (parent.IsObject()) {
617 if (key.empty()) {
618 AddError("\'[\' is not allowed here (\'name\' is missing");
619 }
620 if (value.IsValid()) {
621 AddError("\'[\' cannot follow a \'value\' text");
622 }
623 } else if (parent.IsArray()) {
624 if (value.IsValid()) {
625 AddError("\'[\' cannot follow a \'value\'");
626 }
627 } else {
628 wxJSON_ASSERT(0); // always fails
629 }
630 // open-array cause the DoRead() to be called recursively
631 value.SetType(wxJSONTYPE_ARRAY);
632 ch = DoRead(is, value);
633 break;
634
635 case ']':
636 if (!parent.IsArray()) {
637 // wrong close-array char (should be close-object)
639 wxJSONREADER_MISSING,
640 _T("Trying to close an object using the \']\' (close-array) char" ));
641 }
642 StoreValue(ch, key, value, parent);
643 m_current = &parent;
644 m_next = nullptr;
646 return 0; // returning ZERO for reading the next char
647 break;
648
649 case ',':
650 // store the value, if any
651 StoreValue(ch, key, value, parent);
652 key.clear();
653 ch = ReadChar(is);
654 break;
655
656 case '\"':
657 ch = ReadString(is, value); // read a JSON string type
658 m_current = &value;
659 m_next = nullptr;
660 break;
661
662 case '\'':
663 ch = ReadMemoryBuff(is, value); // read a memory buffer type
664 m_current = &value;
665 m_next = nullptr;
666 break;
667
668 case ':': // key / value separator
669 m_current = &value;
671 m_next = nullptr;
672 if (!parent.IsObject()) {
673 AddError(_T( "\':\' can only used in object's values" ));
674 } else if (!value.IsString()) {
675 AddError(
676 _T( "\':\' follows a value which is not of type \'string\'" ));
677 } else if (!key.empty()) {
678 AddError(
679 _T( "\':\' not allowed where a \'name\' string was already available" ));
680 } else {
681 // the string in 'value' is set as the 'key'
682 key = value.AsString();
683 value.SetType(wxJSONTYPE_INVALID);
684 }
685 ch = ReadChar(is);
686 break;
687
688 default:
689 // no special char: it is a literal or a number
690 // errors are checked in the 'ReadValue()' function.
691 m_current = &value;
693 m_next = nullptr;
694 ch = ReadValue(is, ch, value);
695 break;
696 } // end switch
697 } while (ch >= 0);
698
699 // the DoRead() should return when the close-object/array char is encontered
700 // if we are here, the EOF condition was encontered so one or more
701 // close-something characters are missing
702 if (parent.IsArray()) {
703 AddWarning(wxJSONREADER_MISSING, "\']\' missing at end of file");
704 } else if (parent.IsObject()) {
705 AddWarning(wxJSONREADER_MISSING, "\'}\' missing at end of file");
706 } else {
707 wxJSON_ASSERT(0);
708 }
709
710 // we store the value, as there is a missing close-object/array char
711 StoreValue(ch, key, value, parent);
712
713 --m_level;
714 return ch;
715}
716
718
731void wxJSONReader::StoreValue(int ch, const wxString& key, wxJSONValue& value,
732 wxJSONValue& parent) {
733 // if 'ch' == } or ] than value AND key may be empty when a open object/array
734 // is immediatly followed by a close object/array
735 //
736 // if 'ch' == , (comma) value AND key (for TypeMap) cannot be empty
737 //
738 wxLogTrace(traceMask, "(%s) ch=%d char=%c", __PRETTY_FUNCTION__, ch,
739 (char)ch);
740 wxLogTrace(traceMask, "(%s) value=%s", __PRETTY_FUNCTION__,
741 value.AsString().c_str());
742
743 m_current = 0;
744 m_next = &value;
745 m_lastStored = 0;
746 m_next->SetLineNo(-1);
747
748 if (!value.IsValid() && key.empty()) {
749 // OK, if the char read is a close-object or close-array
750 if (ch == '}' || ch == ']') {
751 m_lastStored = 0;
752 wxLogTrace(traceMask, "(%s) key and value are empty, returning",
753 __PRETTY_FUNCTION__);
754 } else {
755 AddError("key or value is missing for JSON value");
756 }
757 } else {
758 // key or value are not empty
759 if (parent.IsObject()) {
760 if (!value.IsValid()) {
761 AddError(
762 "cannot store the value: \'value\' is missing for JSON object "
763 "type");
764 } else if (key.empty()) {
765 AddError(
766 "cannot store the value: \'key\' is missing for JSON object "
767 "type");
768 } else {
769 // OK, adding the value to parent key/value map
770 wxLogTrace(traceMask, "(%s) adding value to key:%s",
771 __PRETTY_FUNCTION__, key.c_str());
772 parent[key] = value;
773 m_lastStored = &(parent[key]);
775 }
776 } else if (parent.IsArray()) {
777 if (!value.IsValid()) {
778 AddError(
779 "cannot store the item: \'value\' is missing for JSON array "
780 "type");
781 }
782 if (!key.empty()) {
783 AddError(
784 "cannot store the item: \'key\' (\'%s\') is not permitted in "
785 "JSON array type",
786 key);
787 }
788 wxLogTrace(traceMask, "(%s) appending value to parent array",
789 __PRETTY_FUNCTION__);
790 parent.Append(value);
791 const wxJSONInternalArray* arr = parent.AsArray();
792 wxJSON_ASSERT(arr);
793 m_lastStored = &(arr->Last());
795 } else {
796 wxJSON_ASSERT(0); // should never happen
797 }
798 }
799 value.SetType(wxJSONTYPE_INVALID);
800 value.ClearComments();
801}
802
804
819void wxJSONReader::AddError(const wxString& msg) {
820 wxString err;
821 err.Printf("Error: line %d, col %d - %s", m_lineNo, m_colNo, msg.c_str());
822
823 wxLogTrace(traceMask, "(%s) %s", __PRETTY_FUNCTION__, err.c_str());
824
825 if ((int)m_errors.size() < m_maxErrors) {
826 m_errors.Add(err);
827 } else if ((int)m_errors.size() == m_maxErrors) {
828 m_errors.Add("ERROR: too many error messages - ignoring further errors");
829 }
830 // else if ( m_errors > m_maxErrors ) do nothing, thus ignore the error
831 // message
832}
833
835void wxJSONReader::AddError(const wxString& fmt, const wxString& str) {
836 wxString s;
837 s.Printf(fmt.c_str(), str.c_str());
838 AddError(s);
839}
840
842void wxJSONReader::AddError(const wxString& fmt, wxChar c) {
843 wxString s;
844 s.Printf(fmt.c_str(), c);
845 AddError(s);
846}
847
849
871void wxJSONReader::AddWarning(int type, const wxString& msg) {
872 // if 'type' AND 'm_flags' == 1 than the extension is
873 // ON. Otherwise it is OFF anf the function calls AddError()
874 if (type != 0) {
875 if ((type & m_flags) == 0) {
876 AddError(msg);
877 return;
878 }
879 }
880
881 wxString err;
882 err.Printf(_T( "Warning: line %d, col %d - %s"), m_lineNo, m_colNo,
883 msg.c_str());
884
885 wxLogTrace(traceMask, "(%s) %s", __PRETTY_FUNCTION__, err.c_str());
886 if ((int)m_warnings.size() < m_maxErrors) {
887 m_warnings.Add(err);
888 } else if ((int)m_warnings.size() == m_maxErrors) {
889 m_warnings.Add(
890 "Error: too many warning messages - ignoring further warnings");
891 }
892 // else do nothing, thus ignore the warning message
893}
894
896
904int wxJSONReader::SkipWhiteSpace(wxInputStream& is) {
905 // just read one byte at a time and check for whitespaces
906 int ch;
907 do {
908 ch = ReadChar(is);
909 if (ch < 0) {
910 break;
911 }
912 } while (ch == ' ' || ch == '\n' || ch == '\t');
913 wxLogTrace(traceMask, "(%s) end whitespaces line=%d col=%d",
914 __PRETTY_FUNCTION__, m_lineNo, m_colNo);
915 return ch;
916}
917
919
930int wxJSONReader::SkipComment(wxInputStream& is) {
931 static const wxChar* warn =
932 "Comments may be tolerated in JSON text but they are not part of "
933 "JSON syntax";
934
935 // if it is a comment, then a warning is added to the array
936 // otherwise it is an error: values cannot start with a '/'
937 // read the char next to the first slash
938 int ch = ReadChar(is);
939 if (ch < 0) {
940 return -1;
941 }
942
943 wxLogTrace(storeTraceMask, "(%s) start comment line=%d col=%d",
944 __PRETTY_FUNCTION__, m_lineNo, m_colNo);
945
946 // the temporary UTF-8/ANSI buffer that holds the comment string. This will be
947 // converted to a wxString object using wxString::FromUTF8() or From8BitData()
948 wxMemoryBuffer utf8Buff;
949 unsigned char c;
950
951 if (ch == '/') { // C++ comment, read until end-of-line
952 // C++ comment strings are in UTF-8 format. we store all
953 // UTF-8 code units until the first LF or CR+LF
954 AddWarning(wxJSONREADER_ALLOW_COMMENTS, warn);
956 utf8Buff.AppendData("//", 2);
957
958 while (ch >= 0) {
959 if (ch == '\n') {
960 break;
961 }
962 if (ch == '\r') {
963 ch = PeekChar(is);
964 if (ch == '\n') {
965 ch = ReadChar(is);
966 }
967 break;
968 } else {
969 // store the char in the UTF8 temporary buffer
970 c = (unsigned char)ch;
971 utf8Buff.AppendByte(c);
972 }
973 ch = ReadChar(is);
974 }
975 // now convert the temporary UTF-8 buffer
976 m_comment = wxString::FromUTF8((const char*)utf8Buff.GetData(),
977 utf8Buff.GetDataLen());
978 }
979
980 // check if a C-style comment
981 else if (ch == '*') { // C-style comment
982 AddWarning(wxJSONREADER_ALLOW_COMMENTS, warn);
984 utf8Buff.AppendData("/*", 2);
985 while (ch >= 0) {
986 // check the END-COMMENT chars ('*/')
987 if (ch == '*') {
988 ch = PeekChar(is);
989 if (ch == '/') {
990 ch = ReadChar(is); // read the '/' char
991 ch = ReadChar(is); // read the next char that will be returned
992 utf8Buff.AppendData("*/", 2);
993 break;
994 }
995 }
996 // store the char in the UTF8 temporary buffer
997 c = (unsigned char)ch;
998 utf8Buff.AppendByte(c);
999 ch = ReadChar(is);
1000 }
1001 // now convert the temporary buffer in a wxString object
1002 if (m_noUtf8) {
1003 m_comment = wxString::From8BitData((const char*)utf8Buff.GetData(),
1004 utf8Buff.GetDataLen());
1005 } else {
1006 m_comment = wxString::FromUTF8((const char*)utf8Buff.GetData(),
1007 utf8Buff.GetDataLen());
1008 }
1009 }
1010
1011 else { // it is not a comment, return the character next the first '/'
1012 AddError(_T( "Strange '/' (did you want to insert a comment?)"));
1013 // we read until end-of-line OR end of C-style comment OR EOF
1014 // because a '/' should be a start comment
1015 while (ch >= 0) {
1016 ch = ReadChar(is);
1017 if (ch == '*' && PeekChar(is) == '/') {
1018 break;
1019 }
1020 if (ch == '\n') {
1021 break;
1022 }
1023 }
1024 // read the next char that will be returned
1025 ch = ReadChar(is);
1026 }
1027 wxLogTrace(traceMask, "(%s) end comment line=%d col=%d", __PRETTY_FUNCTION__,
1028 m_lineNo, m_colNo);
1029 wxLogTrace(storeTraceMask, "(%s) end comment line=%d col=%d",
1030 __PRETTY_FUNCTION__, m_lineNo, m_colNo);
1031 wxLogTrace(storeTraceMask, "(%s) comment=%s", __PRETTY_FUNCTION__,
1032 m_comment.c_str());
1033 return ch;
1034}
1035
1037
1080int wxJSONReader::ReadString(wxInputStream& is, wxJSONValue& val) {
1081 // the char last read is the opening qoutes (")
1082
1083 wxMemoryBuffer utf8Buff;
1084 char ues[8]; // stores a Unicode Escaped Esquence: \uXXXX
1085
1086 int ch = 0;
1087 while (ch >= 0) {
1088 ch = ReadChar(is);
1089 unsigned char c = (unsigned char)ch;
1090 if (ch == '\\') { // an escape sequence
1091 ch = ReadChar(is);
1092 switch (ch) {
1093 case -1: // EOF
1094 break;
1095 case 't':
1096 utf8Buff.AppendByte('\t');
1097 break;
1098 case 'n':
1099 utf8Buff.AppendByte('\n');
1100 break;
1101 case 'b':
1102 utf8Buff.AppendByte('\b');
1103 break;
1104 case 'r':
1105 utf8Buff.AppendByte('\r');
1106 break;
1107 case '\"':
1108 utf8Buff.AppendByte('\"');
1109 break;
1110 case '\\':
1111 utf8Buff.AppendByte('\\');
1112 break;
1113 case '/':
1114 utf8Buff.AppendByte('/');
1115 break;
1116 case 'f':
1117 utf8Buff.AppendByte('\f');
1118 break;
1119 case 'u':
1120 ch = ReadUES(is, ues);
1121 if (ch < 0) { // if EOF, returns
1122 return ch;
1123 }
1124 // append the escaped character to the UTF8 buffer
1125 AppendUES(utf8Buff, ues);
1126 // many thanks to Bryan Ashby who discovered this bug
1127 continue;
1128 // break;
1129 default:
1130 AddError(_T( "Unknow escaped character \'\\%c\'"), ch);
1131 }
1132 } else {
1133 // we have read a non-escaped character so we have to append it to
1134 // the temporary UTF-8 buffer until the next quote char
1135 if (ch == '\"') {
1136 break;
1137 }
1138 utf8Buff.AppendByte(c);
1139 }
1140 }
1141
1142 // if UTF-8 conversion is disabled (ANSI builds only) we just copy the
1143 // bit data to a wxString object
1144 wxString s;
1145 if (m_noUtf8) {
1146 s = wxString::From8BitData((const char*)utf8Buff.GetData(),
1147 utf8Buff.GetDataLen());
1148 } else {
1149 // perform UTF-8 conversion
1150 // first we check that the UTF-8 buffer is correct, i.e. it contains valid
1151 // UTF-8 code points.
1152 // this works in both ANSI and Unicode builds.
1153 size_t convLen =
1154 wxConvUTF8.ToWChar(0, // wchar_t destination
1155 0, // size_t destLenght
1156 (const char*)utf8Buff.GetData(), // char_t source
1157 utf8Buff.GetDataLen()); // size_t sourceLenght
1158
1159 if (convLen == wxCONV_FAILED) {
1160 AddError(_T( "String value: the UTF-8 stream is invalid"));
1161 s.append(_T( "<UTF-8 stream not valid>"));
1162 } else {
1163#if defined(wxJSON_USE_UNICODE)
1164 // in Unicode just convert to wxString
1165 s = wxString::FromUTF8((const char*)utf8Buff.GetData(),
1166 utf8Buff.GetDataLen());
1167#else
1168 // in ANSI, the conversion may fail and an empty string is returned
1169 // in this case, the reader do a char-by-char conversion storing
1170 // unicode escaped sequences of unrepresentable characters
1171 s = wxString::FromUTF8((const char*)utf8Buff.GetData(),
1172 utf8Buff.GetDataLen());
1173 if (s.IsEmpty()) {
1174 int r = ConvertCharByChar(
1175 s, utf8Buff); // return number of escaped sequences
1176 if (r > 0) {
1177 AddWarning(
1178 0,
1179 _T( "The string value contains unrepresentable Unicode characters"));
1180 }
1181 }
1182#endif
1183 }
1184 }
1185 wxLogTrace(traceMask, "(%s) line=%d col=%d", __PRETTY_FUNCTION__, m_lineNo,
1186 m_colNo);
1187 wxLogTrace(traceMask, "(%s) string read=%s", __PRETTY_FUNCTION__, s.c_str());
1188 wxLogTrace(traceMask, "(%s) value=%s", __PRETTY_FUNCTION__,
1189 val.AsString().c_str());
1190
1191 // now assign the string to the JSON-value 'value'
1192 // must check that:
1193 // 'value' is empty
1194 // 'value' is a string; concatenate it but emit warning
1195 if (!val.IsValid()) {
1196 wxLogTrace(traceMask, "(%s) assigning the string to value",
1197 __PRETTY_FUNCTION__);
1198 val = s;
1199 } else if (val.IsString()) {
1200 AddWarning(wxJSONREADER_MULTISTRING,
1201 "Multiline strings are not allowed by JSON syntax");
1202 wxLogTrace(traceMask, "(%s) concatenate the string to value",
1203 __PRETTY_FUNCTION__);
1204 val.Cat(s);
1205 } else {
1206 AddError(_T( "String value \'%s\' cannot follow another value"), s);
1207 }
1208
1209 // store the input text's line number when the string was stored in 'val'
1210 val.SetLineNo(m_lineNo);
1211
1212 // read the next char after the closing quotes and returns it
1213 if (ch >= 0) {
1214 ch = ReadChar(is);
1215 }
1216 return ch;
1217}
1218
1220
1239int wxJSONReader::ReadToken(wxInputStream& is, int ch, wxString& s) {
1240 int nextCh = ch;
1241 while (nextCh >= 0) {
1242 switch (nextCh) {
1243 case ' ':
1244 case ',':
1245 case ':':
1246 case '[':
1247 case ']':
1248 case '{':
1249 case '}':
1250 case '\t':
1251 case '\n':
1252 case '\r':
1253 case '\b':
1254 wxLogTrace(traceMask, "(%s) line=%d col=%d", __PRETTY_FUNCTION__,
1255 m_lineNo, m_colNo);
1256 wxLogTrace(traceMask, "(%s) token read=%s", __PRETTY_FUNCTION__,
1257 s.c_str());
1258 return nextCh;
1259 break;
1260 default:
1261 s.Append((unsigned char)nextCh, 1);
1262 break;
1263 }
1264 // read the next character
1265 nextCh = ReadChar(is);
1266 }
1267 wxLogTrace(traceMask, "(%s) EOF on line=%d col=%d", __PRETTY_FUNCTION__,
1268 m_lineNo, m_colNo);
1269 wxLogTrace(traceMask, "(%s) EOF - token read=%s", __PRETTY_FUNCTION__,
1270 s.c_str());
1271 return nextCh;
1272}
1273
1275
1298int wxJSONReader::ReadValue(wxInputStream& is, int ch, wxJSONValue& val) {
1299 wxString s;
1300 int nextCh = ReadToken(is, ch, s);
1301 wxLogTrace(traceMask, "(%s) value=%s", __PRETTY_FUNCTION__,
1302 val.AsString().c_str());
1303
1304 if (val.IsValid()) {
1305 AddError(_T( "Value \'%s\' cannot follow a value: \',\' or \':\' missing?"),
1306 s);
1307 return nextCh;
1308 }
1309
1310 // variables used for converting numeric values
1311 bool r;
1312 double d;
1313#if defined(wxJSON_64BIT_INT)
1314 wxInt64 i64;
1315 wxUint64 ui64;
1316#else
1317 unsigned long int ul;
1318 long int l;
1319#endif
1320
1321 // first try the literal strings lowercase and nocase
1322 if (s == "null") {
1323 val.SetType(wxJSONTYPE_NULL);
1324 wxLogTrace(traceMask, "(%s) value = nullptr", __PRETTY_FUNCTION__);
1325 return nextCh;
1326 } else if (s.CmpNoCase(_T( "null" )) == 0) {
1327 wxLogTrace(traceMask, "(%s) value = nullptr", __PRETTY_FUNCTION__);
1328 AddWarning(wxJSONREADER_CASE,
1329 _T( "the \'null\' literal must be lowercase" ));
1330 val.SetType(wxJSONTYPE_NULL);
1331 return nextCh;
1332 } else if (s == "true") {
1333 wxLogTrace(traceMask, "(%s) value = TRUE", __PRETTY_FUNCTION__);
1334 val = true;
1335 return nextCh;
1336 } else if (s.CmpNoCase(_T( "true" )) == 0) {
1337 wxLogTrace(traceMask, "(%s) value = TRUE", __PRETTY_FUNCTION__);
1338 AddWarning(wxJSONREADER_CASE,
1339 _T( "the \'true\' literal must be lowercase" ));
1340 val = true;
1341 return nextCh;
1342 } else if (s == "false") {
1343 wxLogTrace(traceMask, "(%s) value = FALSE", __PRETTY_FUNCTION__);
1344 val = false;
1345 return nextCh;
1346 } else if (s.CmpNoCase(_T( "false" )) == 0) {
1347 wxLogTrace(traceMask, "(%s) value = FALSE", __PRETTY_FUNCTION__);
1348 AddWarning(wxJSONREADER_CASE,
1349 _T( "the \'false\' literal must be lowercase" ));
1350 val = false;
1351 return nextCh;
1352 }
1353
1354 // try to convert to a number if the token starts with a digit, a plus or a
1355 // minus sign. The function first states what type of conversion are tested:
1356 // 1. first signed integer (not if 'ch' == '+')
1357 // 2. unsigned integer (not if 'ch' == '-')
1358 // 3. finally double
1359 bool tSigned = true, tUnsigned = true, tDouble = true;
1360 switch (ch) {
1361 case '0':
1362 case '1':
1363 case '2':
1364 case '3':
1365 case '4':
1366 case '5':
1367 case '6':
1368 case '7':
1369 case '8':
1370 case '9':
1371 // first try a signed integer, then a unsigned integer, then a double
1372 break;
1373
1374 case '+':
1375 // the plus sign forces a unsigned integer
1376 tSigned = false;
1377 break;
1378
1379 case '-':
1380 // try signed and double
1381 tUnsigned = false;
1382 break;
1383 default:
1384 AddError(_T( "Literal \'%s\' is incorrect (did you forget quotes?)"), s);
1385 return nextCh;
1386 }
1387
1388 if (tSigned) {
1389#if defined(wxJSON_64BIT_INT)
1390 r = Strtoll(s, &i64);
1391 wxLogTrace(traceMask, "(%s) convert to wxInt64 result=%d",
1392 __PRETTY_FUNCTION__, r);
1393 if (r) {
1394 // store the value
1395 val = i64;
1396 return nextCh;
1397 }
1398#else
1399 r = s.ToLong(&l);
1400 wxLogTrace(traceMask, "(%s) convert to int result=%d", __PRETTY_FUNCTION__,
1401 r);
1402 if (r) {
1403 // store the value
1404 val = (int)l;
1405 return nextCh;
1406 }
1407#endif
1408 }
1409
1410 if (tUnsigned) {
1411#if defined(wxJSON_64BIT_INT)
1412 r = Strtoull(s, &ui64);
1413 wxLogTrace(traceMask, "(%s) convert to wxUint64 result=%d",
1414 __PRETTY_FUNCTION__, r);
1415 if (r) {
1416 // store the value
1417 val = ui64;
1418 return nextCh;
1419 }
1420#else
1421 r = s.ToULong(&ul);
1422 wxLogTrace(traceMask, "(%s) convert to int result=%d", __PRETTY_FUNCTION__,
1423 r);
1424 if (r) {
1425 // store the value
1426 val = (unsigned int)ul;
1427 return nextCh;
1428 }
1429#endif
1430 }
1431
1432 if (tDouble) {
1433 r = s.ToDouble(&d);
1434 wxLogTrace(traceMask, "(%s) convert to double result=%d",
1435 __PRETTY_FUNCTION__, r);
1436 if (r) {
1437 // store the value
1438 val = d;
1439 return nextCh;
1440 }
1441 }
1442
1443 // the value is not syntactically correct
1444 AddError(_T( "Literal \'%s\' is incorrect (did you forget quotes?)"), s);
1445 return nextCh;
1446 return nextCh;
1447}
1448
1450
1468int wxJSONReader::ReadUES(wxInputStream& is, char* uesBuffer) {
1469 int ch;
1470 for (int i = 0; i < 4; i++) {
1471 ch = ReadChar(is);
1472 if (ch < 0) {
1473 return ch;
1474 }
1475 uesBuffer[i] = (unsigned char)ch;
1476 }
1477 uesBuffer[4] = 0; // makes a ASCIIZ string
1478
1479 return 0;
1480}
1481
1483
1509int wxJSONReader::AppendUES(wxMemoryBuffer& utf8Buff, const char* uesBuffer) {
1510 unsigned long l;
1511 int r = sscanf(uesBuffer, "%lx", &l); // r is the assigned items
1512 if (r != 1) {
1513 AddError(_T( "Invalid Unicode Escaped Sequence"));
1514 return -1;
1515 }
1516 wxLogTrace(traceMask, "(%s) unicode sequence=%s code=%ld",
1517 __PRETTY_FUNCTION__, uesBuffer, l);
1518
1519 wchar_t ch = (wchar_t)l;
1520 char buffer[16];
1521 size_t len = wxConvUTF8.FromWChar(buffer, 10, &ch, 1);
1522
1523 // seems that the wxMBConv classes always appends a nullptr byte to
1524 // the converted buffer
1525 if (len > 1) {
1526 len = len - 1;
1527 }
1528 utf8Buff.AppendData(buffer, len);
1529
1530 // sould never fail
1531 wxASSERT(len != wxCONV_FAILED);
1532 return 0;
1533}
1534
1536
1562 wxLogTrace(storeTraceMask, "(%s) m_comment=%s", __PRETTY_FUNCTION__,
1563 m_comment.c_str());
1564 wxLogTrace(storeTraceMask, "(%s) m_flags=%d m_commentLine=%d",
1565 __PRETTY_FUNCTION__, m_flags, m_commentLine);
1566 wxLogTrace(storeTraceMask, "(%s) m_current=%p", __PRETTY_FUNCTION__,
1567 m_current);
1568 wxLogTrace(storeTraceMask, "(%s) m_next=%p", __PRETTY_FUNCTION__, m_next);
1569 wxLogTrace(storeTraceMask, "(%s) m_lastStored=%p", __PRETTY_FUNCTION__,
1570 m_lastStored);
1571
1572 // first check if the 'store comment' bit is on
1573 if ((m_flags & wxJSONREADER_STORE_COMMENTS) == 0) {
1574 m_comment.clear();
1575 return;
1576 }
1577
1578 // check if the comment is on the same line of one of the
1579 // 'current', 'next' or 'lastStored' value
1580 if (m_current != 0) {
1581 wxLogTrace(storeTraceMask, "(%s) m_current->lineNo=%d", __PRETTY_FUNCTION__,
1582 m_current->GetLineNo());
1583 if (m_current->GetLineNo() == m_commentLine) {
1584 wxLogTrace(storeTraceMask, "(%s) comment added to \'m_current\' INLINE",
1585 __PRETTY_FUNCTION__);
1586 m_current->AddComment(m_comment, wxJSONVALUE_COMMENT_INLINE);
1587 m_comment.clear();
1588 return;
1589 }
1590 }
1591 if (m_next != 0) {
1592 wxLogTrace(storeTraceMask, "(%s) m_next->lineNo=%d", __PRETTY_FUNCTION__,
1593 m_next->GetLineNo());
1594 if (m_next->GetLineNo() == m_commentLine) {
1595 wxLogTrace(storeTraceMask, "(%s) comment added to \'m_next\' INLINE",
1596 __PRETTY_FUNCTION__);
1597 m_next->AddComment(m_comment, wxJSONVALUE_COMMENT_INLINE);
1598 m_comment.clear();
1599 return;
1600 }
1601 }
1602 if (m_lastStored != 0) {
1603 wxLogTrace(storeTraceMask, "(%s) m_lastStored->lineNo=%d",
1604 __PRETTY_FUNCTION__, m_lastStored->GetLineNo());
1606 wxLogTrace(storeTraceMask,
1607 "(%s) comment added to \'m_lastStored\' INLINE",
1608 __PRETTY_FUNCTION__);
1609 m_lastStored->AddComment(m_comment, wxJSONVALUE_COMMENT_INLINE);
1610 m_comment.clear();
1611 return;
1612 }
1613 }
1614
1615 // if comment is BEFORE, store the comment in the 'm_next'
1616 // or 'm_current' value
1617 // if comment is AFTER, store the comment in the 'm_lastStored'
1618 // or 'm_current' value
1619
1620 if (m_flags & wxJSONREADER_COMMENTS_AFTER) { // comment AFTER
1621 if (m_current) {
1622 if (m_current == parent || !m_current->IsValid()) {
1623 AddError("Cannot find a value for storing the comment (flag AFTER)");
1624 } else {
1625 wxLogTrace(storeTraceMask, "(%s) comment added to m_current (AFTER)",
1626 __PRETTY_FUNCTION__);
1627 m_current->AddComment(m_comment, wxJSONVALUE_COMMENT_AFTER);
1628 }
1629 } else if (m_lastStored) {
1630 wxLogTrace(storeTraceMask, "(%s) comment added to m_lastStored (AFTER)",
1631 __PRETTY_FUNCTION__);
1632 m_lastStored->AddComment(m_comment, wxJSONVALUE_COMMENT_AFTER);
1633 } else {
1634 wxLogTrace(storeTraceMask,
1635 "(%s) cannot find a value for storing the AFTER comment",
1636 __PRETTY_FUNCTION__);
1637 AddError("Cannot find a value for storing the comment (flag AFTER)");
1638 }
1639 } else { // comment BEFORE can only be added to the 'next' value
1640 if (m_next) {
1641 wxLogTrace(storeTraceMask, "(%s) comment added to m_next (BEFORE)",
1642 __PRETTY_FUNCTION__);
1643 m_next->AddComment(m_comment, wxJSONVALUE_COMMENT_BEFORE);
1644 } else {
1645 // cannot find a value for storing the comment
1646 AddError("Cannot find a value for storing the comment (flag BEFORE)");
1647 }
1648 }
1649 m_comment.clear();
1650}
1651
1653
1663 int n = UTF8NumBytes(ch);
1664 return n;
1665}
1666
1668
1689 int num = 0; // the counter of '1' bits
1690 for (int i = 0; i < 8; i++) {
1691 if ((ch & 0x80) == 0) {
1692 break;
1693 }
1694 ++num;
1695 ch = ch << 1;
1696 }
1697
1698 // note that if the char contains more than six '1' bits it is not
1699 // a valid UTF-8 encoded character
1700 if (num > 6) {
1701 num = -1;
1702 } else if (num == 0) {
1703 num = 1;
1704 }
1705 return num;
1706}
1707
1709
1725 const wxMemoryBuffer& utf8Buffer) {
1726 size_t len = utf8Buffer.GetDataLen();
1727 char* buff = (char*)utf8Buffer.GetData();
1728 char* buffEnd = buff + len;
1729
1730 int result = 0;
1731 char temp[16]; // the UTF-8 code-point
1732
1733 while (buff < buffEnd) {
1734 temp[0] = *buff; // the first UTF-8 code-unit
1735 // compute the number of code-untis that make one UTF-8 code-point
1736 int numBytes = NumBytes(*buff);
1737 ++buff;
1738 for (int i = 1; i < numBytes; i++) {
1739 if (buff >= buffEnd) {
1740 break;
1741 }
1742 temp[i] = *buff; // the first UTF-8 code-unit
1743 ++buff;
1744 }
1745 // if ( buff >= buffEnd ) {
1746 // break;
1747 //}
1748 // now convert 'temp' to a wide-character
1749 wchar_t dst[10];
1750 size_t outLength = wxConvUTF8.ToWChar(dst, 10, temp, numBytes);
1751
1752 // now convert the wide char to a locale dependent character
1753 // len = wxConvLocal.FromWChar( temp, 16, dst, outLength );
1754 // len = wxConviso8859_1.FromWChar( temp, 16, dst, outLength );
1755 len = wxConvLibc.FromWChar(temp, 16, dst, outLength);
1756 if (len == wxCONV_FAILED) {
1757 ++result;
1758 wxString t;
1759 t.Printf(_T( "\\u%04X"), (int)dst[0]);
1760 s.Append(t);
1761 } else {
1762 s.Append(temp[0], 1);
1763 }
1764 } // end while
1765 return result;
1766}
1767
1769
1785 unsigned char cu[2];
1786 short int bu;
1787};
1788
1789int wxJSONReader::ReadMemoryBuff(wxInputStream& is, wxJSONValue& val) {
1790 static const wxChar* membuffError =
1791 _T("the \'memory buffer\' type contains %d invalid digits" );
1792
1793 AddWarning(wxJSONREADER_MEMORYBUFF,
1794 _T( "the \'memory buffer\' type is not valid JSON text" ));
1795
1796 wxMemoryBuffer buff;
1797 int ch = 0;
1798 int errors = 0;
1799 unsigned char byte = 0;
1800 while (ch >= 0) {
1801 ch = ReadChar(is);
1802 if (ch < 0) {
1803 break;
1804 }
1805 if (ch == '\'') {
1806 break;
1807 }
1808 // the conversion is done two chars at a time
1809 unsigned char c1 = (unsigned char)ch;
1810 ch = ReadChar(is);
1811 if (ch < 0) {
1812 break;
1813 }
1814 unsigned char c2 = (unsigned char)ch;
1815 c1 -= '0';
1816 c2 -= '0';
1817 if (c1 > 9) {
1818 c1 -= 7;
1819 }
1820 if (c2 > 9) {
1821 c2 -= 7;
1822 }
1823 if (c1 > 15) {
1824 ++errors;
1825 } else if (c2 > 15) {
1826 ++errors;
1827 } else {
1828 byte = (c1 * 16) + c2;
1829 buff.AppendByte(byte);
1830 }
1831 } // end while
1832
1833 if (errors > 0) {
1834 wxString err;
1835 err.Printf(membuffError, errors);
1836 AddError(err);
1837 }
1838
1839 // now assign the memory buffer object to the JSON-value 'value'
1840 // must check that:
1841 // 'value' is invalid OR
1842 // 'value' is a memory buffer; concatenate it
1843 if (!val.IsValid()) {
1844 wxLogTrace(traceMask, "(%s) assigning the memory buffer to value",
1845 __PRETTY_FUNCTION__);
1846 val = buff;
1847 } else if (val.IsMemoryBuff()) {
1848 wxLogTrace(traceMask, "(%s) concatenate memory buffer to value",
1849 __PRETTY_FUNCTION__);
1850 val.Cat(buff);
1851 } else {
1852 AddError(_T( "Memory buffer value cannot follow another value"));
1853 }
1854
1855 // store the input text's line number when the string was stored in 'val'
1856 val.SetLineNo(m_lineNo);
1857
1858 // read the next char after the closing quotes and returns it
1859 if (ch >= 0) {
1860 ch = ReadChar(is);
1861 }
1862 return ch;
1863}
1864
1865#if defined(wxJSON_64BIT_INT)
1867
1893bool wxJSONReader::Strtoll(const wxString& str, wxInt64* i64) {
1894 wxChar sign = ' ';
1895 wxUint64 ui64;
1896 bool r = DoStrto_ll(str, &ui64, &sign);
1897
1898 if (r) {
1899 // check overflow for signed long long
1900 switch (sign) {
1901 case '-':
1902 if (ui64 > (wxUint64)LLONG_MAX + 1) {
1903 r = false;
1904 } else {
1905 *i64 = (wxInt64)(ui64 * -1);
1906 }
1907 break;
1908
1909 // case '+' :
1910 default:
1911 if (ui64 > LLONG_MAX) {
1912 r = false;
1913 } else {
1914 *i64 = (wxInt64)ui64;
1915 }
1916 break;
1917 }
1918 }
1919 return r;
1920}
1921
1923
1926bool wxJSONReader::Strtoull(const wxString& str, wxUint64* ui64) {
1927 wxChar sign = ' ';
1928 bool r = DoStrto_ll(str, ui64, &sign);
1929 if (sign == '-') {
1930 r = false;
1931 }
1932 return r;
1933}
1934
1936
1947bool wxJSONReader::DoStrto_ll(const wxString& str, wxUint64* ui64,
1948 wxChar* sign) {
1949 // the conversion is done by multiplying the individual digits
1950 // in reverse order to the corresponding power of 10
1951 //
1952 // 10's power: 987654321.9876543210
1953 //
1954 // LLONG_MAX: 9223372036854775807
1955 // LLONG_MIN: -9223372036854775808
1956 // ULLONG_MAX: 18446744073709551615
1957 //
1958 // the function does not take into account the sign: only a
1959 // unsigned long long int is returned
1960
1961 int maxDigits = 20; // 20 + 1 (for the sign)
1962
1963 wxUint64 power10[] = {wxULL(1),
1964 wxULL(10),
1965 wxULL(100),
1966 wxULL(1000),
1967 wxULL(10000),
1968 wxULL(100000),
1969 wxULL(1000000),
1970 wxULL(10000000),
1971 wxULL(100000000),
1972 wxULL(1000000000),
1973 wxULL(10000000000),
1974 wxULL(100000000000),
1975 wxULL(1000000000000),
1976 wxULL(10000000000000),
1977 wxULL(100000000000000),
1978 wxULL(1000000000000000),
1979 wxULL(10000000000000000),
1980 wxULL(100000000000000000),
1981 wxULL(1000000000000000000),
1982 wxULL(10000000000000000000)};
1983
1984 wxUint64 temp1 = wxULL(0); // the temporary converted integer
1985
1986 int strLen = str.length();
1987 if (strLen == 0) {
1988 // an empty string is converted to a ZERO value: the function succeeds
1989 *ui64 = wxLL(0);
1990 return true;
1991 }
1992
1993 int index = 0;
1994 wxChar ch = str[0];
1995 if (ch == '+' || ch == '-') {
1996 *sign = ch;
1997 ++index;
1998 ++maxDigits;
1999 }
2000
2001 if (strLen > maxDigits) {
2002 return false;
2003 }
2004
2005 // check the overflow: check the string length and the individual digits
2006 // of the string; the overflow is checked for unsigned long long
2007 if (strLen == maxDigits) {
2008 wxString uLongMax("18446744073709551615");
2009 int j = 0;
2010 for (int i = index; i < strLen - 1; i++) {
2011 ch = str[i];
2012 if (ch < '0' || ch > '9') {
2013 return false;
2014 }
2015 if (ch > uLongMax[j]) {
2016 return false;
2017 }
2018 if (ch < uLongMax[j]) {
2019 break;
2020 }
2021 ++j;
2022 }
2023 }
2024
2025 // get the digits in the reverse order and multiply them by the
2026 // corresponding power of 10
2027 int exponent = 0;
2028 for (int i = strLen - 1; i >= index; i--) {
2029 wxChar ch = str[i];
2030 if (ch < '0' || ch > '9') {
2031 return false;
2032 }
2033 ch = ch - '0';
2034 // compute the new temporary value
2035 temp1 += ch * power10[exponent];
2036 ++exponent;
2037 }
2038 *ui64 = temp1;
2039 return true;
2040}
2041
2042#endif // defined( wxJSON_64BIT_INT )
2043
2044/*
2045{
2046}
2047*/
int m_colNo
The current column number (start at 1).
Definition jsonreader.h:100
int ReadToken(wxInputStream &is, int ch, wxString &s)
Reads a token string.
int DoRead(wxInputStream &doc, wxJSONValue &val)
Reads the JSON text document (internal use)
void AddWarning(int type, const wxString &descr)
Add a warning message to the warning's array.
int ConvertCharByChar(wxString &s, const wxMemoryBuffer &utf8Buffer)
Convert a UTF-8 memory buffer one char at a time.
int m_maxErrors
Maximum number of errors stored in the error's array.
Definition jsonreader.h:94
bool m_noUtf8
ANSI: do not convert UTF-8 strings.
Definition jsonreader.h:133
wxJSONValue * m_lastStored
The pointer to the value object that was last stored.
Definition jsonreader.h:112
int AppendUES(wxMemoryBuffer &utf8Buff, const char *uesBuffer)
The function appends a Unice Escaped Sequence to the temporary UTF8 buffer.
int ReadChar(wxInputStream &is)
Read a character from the input JSON document.
int SkipComment(wxInputStream &is)
Skip a comment.
int ReadString(wxInputStream &is, wxJSONValue &val)
Read a string value.
int m_flags
Flag that control the parser behaviour,.
Definition jsonreader.h:91
int ReadUES(wxInputStream &is, char *uesBuffer)
Read a 4-hex-digit unicode character.
wxJSONReader(int flags=wxJSONREADER_TOLERANT, int maxErrors=30)
Ctor.
void StoreComment(const wxJSONValue *parent)
Store the comment string in the value it refers to.
static int UTF8NumBytes(char ch)
Compute the number of bytes that makes a UTF-8 encoded wide character.
int m_lineNo
The current line number (start at 1).
Definition jsonreader.h:97
int GetDepth() const
Return the depth of the JSON input text.
int m_commentLine
The starting line of the comment string.
Definition jsonreader.h:121
int m_depth
The depth level of the read JSON text.
Definition jsonreader.h:106
wxJSONValue * m_current
The pointer to the value object that is being read.
Definition jsonreader.h:109
int m_level
The current level of object/array annidation (start at ZERO).
Definition jsonreader.h:103
void StoreValue(int ch, const wxString &key, wxJSONValue &value, wxJSONValue &parent)
Store a value in the parent object.
const wxArrayString & GetWarnings() const
Return a reference to the warning message's array.
const wxArrayString & GetErrors() const
Return a reference to the error message's array.
wxArrayString m_errors
The array of error messages.
Definition jsonreader.h:124
wxArrayString m_warnings
The array of warning messages.
Definition jsonreader.h:127
int GetErrorCount() const
Return the size of the error message's array.
void AddError(const wxString &descr)
Add a error message to the error's array.
wxJSONValue * m_next
The pointer to the value object that will be read.
Definition jsonreader.h:115
int GetWarningCount() const
Return the size of the warning message's array.
wxString m_comment
The comment string read by SkipComment().
Definition jsonreader.h:118
int ReadValue(wxInputStream &is, int ch, wxJSONValue &val)
Read a value from input stream.
int Parse(const wxString &doc, wxJSONValue *val)
Parse the JSON document.
int ReadMemoryBuff(wxInputStream &is, wxJSONValue &val)
Read a memory buffer type.
virtual ~wxJSONReader()
Dtor - does nothing.
int GetStart(wxInputStream &is)
Returns the start of the document.
int NumBytes(char ch)
Return the number of bytes that make a character in stream input.
int SkipWhiteSpace(wxInputStream &is)
Skip all whitespaces.
int m_peekChar
The character read by the PeekChar() function (-1 none)
Definition jsonreader.h:130
int PeekChar(wxInputStream &is)
Peek a character from the input JSON document.
The JSON value class implementation.
Definition jsonval.h:79
bool IsArray() const
Return TRUE if the type of the value stored is an array type.
Definition jsonval.cpp:749
int AddComment(const wxString &str, int position=wxJSONVALUE_COMMENT_DEFAULT)
Add a comment to this JSON value object.
Definition jsonval.cpp:2345
bool IsString() const
Return TRUE if the type of the value stored is a wxString object.
Definition jsonval.cpp:720
wxJSONValue & Append(const wxJSONValue &value)
Append the specified value in the array.
Definition jsonval.cpp:1386
wxString AsString() const
Return the stored value as a wxWidget's string.
Definition jsonval.cpp:875
int GetLineNo() const
Return the line number of this JSON value object.
Definition jsonval.cpp:2615
bool IsValid() const
Return TRUE if the value stored is valid.
Definition jsonval.cpp:524
bool IsMemoryBuff() const
Return TRUE if the type of this value is a binary memory buffer.
Definition jsonval.cpp:769
void SetLineNo(int num)
Set the line number of this JSON value object.
Definition jsonval.cpp:2626
bool IsObject() const
Return TRUE if the type of this value is a key/value map.
Definition jsonval.cpp:759
wxJSONRefData * SetType(wxJSONType type)
Set the type of the stored value.
Definition jsonval.cpp:2533
const wxJSONInternalArray * AsArray() const
Return the stored value as an array object.
Definition jsonval.cpp:1282
Read a memory buffer type.