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