20#define wxDEBUG_LEVEL 0
23#include <wx/mstream.h>
24#include <wx/sstream.h>
28#include "jsonreader.h"
180static const wxChar* traceMask =
"traceReader";
181static const wxChar* storeTraceMask =
"StoreComment";
247#if !defined(wxJSON_USE_UNICODE)
250 if (
m_flags & wxJSONREADER_NOUTF8_STREAM) {
306#if !defined(wxJSON_USE_UNICODE)
314 char* readBuff =
nullptr;
315 wxCharBuffer utf8CB = doc.ToUTF8();
316#if !defined(wxJSON_USE_UNICODE)
317 wxCharBuffer ansiCB(doc.c_str());
319 readBuff = ansiCB.data();
321 readBuff = utf8CB.data();
324 readBuff = utf8CB.data();
328 size_t len = strlen(readBuff);
329 wxMemoryInputStream is(readBuff, len);
331 int numErr =
Parse(is, val);
332#if !defined(wxJSON_USE_UNICODE)
353 if (val ==
nullptr) {
367 val->
SetType(wxJSONTYPE_OBJECT);
370 val->
SetType(wxJSONTYPE_ARRAY);
373 AddError(_T(
"Cannot find a start object/array character" ));
466 unsigned char ch = is.GetC();
467 size_t last = is.LastRead();
479 if (nextChar == -1) {
481 }
else if (nextChar ==
'\n') {
582 AddError(
"\'{\' is not allowed here (\'name\' is missing");
584 if (value.IsValid()) {
585 AddError(
"\'{\' cannot follow a \'value\'");
588 if (value.IsValid()) {
589 AddError(
"\'{\' cannot follow a \'value\' in JSON array");
596 value.SetType(wxJSONTYPE_OBJECT);
603 wxJSONREADER_MISSING,
604 _T(
"Trying to close an array using the \'}\' (close-object) char" ));
618 AddError(
"\'[\' is not allowed here (\'name\' is missing");
620 if (value.IsValid()) {
621 AddError(
"\'[\' cannot follow a \'value\' text");
624 if (value.IsValid()) {
625 AddError(
"\'[\' cannot follow a \'value\'");
631 value.SetType(wxJSONTYPE_ARRAY);
639 wxJSONREADER_MISSING,
640 _T(
"Trying to close an object using the \']\' (close-array) char" ));
673 AddError(_T(
"\':\' can only used in object's values" ));
674 }
else if (!value.IsString()) {
676 _T(
"\':\' follows a value which is not of type \'string\'" ));
677 }
else if (!key.empty()) {
679 _T(
"\':\' not allowed where a \'name\' string was already available" ));
682 key = value.AsString();
683 value.SetType(wxJSONTYPE_INVALID);
703 AddWarning(wxJSONREADER_MISSING,
"\']\' missing at end of file");
705 AddWarning(wxJSONREADER_MISSING,
"\'}\' missing at end of file");
738 wxLogTrace(traceMask,
"(%s) ch=%d char=%c", __PRETTY_FUNCTION__, ch,
740 wxLogTrace(traceMask,
"(%s) value=%s", __PRETTY_FUNCTION__,
741 value.AsString().c_str());
748 if (!value.IsValid() && key.empty()) {
750 if (ch ==
'}' || ch ==
']') {
752 wxLogTrace(traceMask,
"(%s) key and value are empty, returning",
753 __PRETTY_FUNCTION__);
755 AddError(
"key or value is missing for JSON value");
760 if (!value.IsValid()) {
762 "cannot store the value: \'value\' is missing for JSON object "
764 }
else if (key.empty()) {
766 "cannot store the value: \'key\' is missing for JSON object "
770 wxLogTrace(traceMask,
"(%s) adding value to key:%s",
771 __PRETTY_FUNCTION__, key.c_str());
777 if (!value.IsValid()) {
779 "cannot store the item: \'value\' is missing for JSON array "
784 "cannot store the item: \'key\' (\'%s\') is not permitted in "
788 wxLogTrace(traceMask,
"(%s) appending value to parent array",
789 __PRETTY_FUNCTION__);
791 const wxJSONInternalArray* arr = parent.
AsArray();
799 value.SetType(wxJSONTYPE_INVALID);
800 value.ClearComments();
821 err.Printf(
"Error: line %d, col %d - %s",
m_lineNo,
m_colNo, msg.c_str());
823 wxLogTrace(traceMask,
"(%s) %s", __PRETTY_FUNCTION__, err.c_str());
828 m_errors.Add(
"ERROR: too many error messages - ignoring further errors");
837 s.Printf(fmt.c_str(), str.c_str());
844 s.Printf(fmt.c_str(), c);
885 wxLogTrace(traceMask,
"(%s) %s", __PRETTY_FUNCTION__, err.c_str());
890 "Error: too many warning messages - ignoring further warnings");
912 }
while (ch ==
' ' || ch ==
'\n' || ch ==
'\t');
913 wxLogTrace(traceMask,
"(%s) end whitespaces line=%d col=%d",
931 static const wxChar* warn =
932 "Comments may be tolerated in JSON text but they are not part of "
943 wxLogTrace(storeTraceMask,
"(%s) start comment line=%d col=%d",
948 wxMemoryBuffer utf8Buff;
954 AddWarning(wxJSONREADER_ALLOW_COMMENTS, warn);
956 utf8Buff.AppendData(
"//", 2);
970 c = (
unsigned char)ch;
971 utf8Buff.AppendByte(c);
976 m_comment = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
977 utf8Buff.GetDataLen());
981 else if (ch ==
'*') {
982 AddWarning(wxJSONREADER_ALLOW_COMMENTS, warn);
984 utf8Buff.AppendData(
"/*", 2);
992 utf8Buff.AppendData(
"*/", 2);
997 c = (
unsigned char)ch;
998 utf8Buff.AppendByte(c);
1003 m_comment = wxString::From8BitData((
const char*)utf8Buff.GetData(),
1004 utf8Buff.GetDataLen());
1006 m_comment = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1007 utf8Buff.GetDataLen());
1012 AddError(_T(
"Strange '/' (did you want to insert a comment?)"));
1017 if (ch ==
'*' &&
PeekChar(is) ==
'/') {
1027 wxLogTrace(traceMask,
"(%s) end comment line=%d col=%d", __PRETTY_FUNCTION__,
1029 wxLogTrace(storeTraceMask,
"(%s) end comment line=%d col=%d",
1031 wxLogTrace(storeTraceMask,
"(%s) comment=%s", __PRETTY_FUNCTION__,
1083 wxMemoryBuffer utf8Buff;
1089 unsigned char c = (
unsigned char)ch;
1096 utf8Buff.AppendByte(
'\t');
1099 utf8Buff.AppendByte(
'\n');
1102 utf8Buff.AppendByte(
'\b');
1105 utf8Buff.AppendByte(
'\r');
1108 utf8Buff.AppendByte(
'\"');
1111 utf8Buff.AppendByte(
'\\');
1114 utf8Buff.AppendByte(
'/');
1117 utf8Buff.AppendByte(
'\f');
1130 AddError(_T(
"Unknow escaped character \'\\%c\'"), ch);
1138 utf8Buff.AppendByte(c);
1146 s = wxString::From8BitData((
const char*)utf8Buff.GetData(),
1147 utf8Buff.GetDataLen());
1154 wxConvUTF8.ToWChar(0,
1156 (
const char*)utf8Buff.GetData(),
1157 utf8Buff.GetDataLen());
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>"));
1163#if defined(wxJSON_USE_UNICODE)
1165 s = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1166 utf8Buff.GetDataLen());
1171 s = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1172 utf8Buff.GetDataLen());
1179 _T(
"The string value contains unrepresentable Unicode characters"));
1185 wxLogTrace(traceMask,
"(%s) line=%d col=%d", __PRETTY_FUNCTION__,
m_lineNo,
1187 wxLogTrace(traceMask,
"(%s) string read=%s", __PRETTY_FUNCTION__, s.c_str());
1188 wxLogTrace(traceMask,
"(%s) value=%s", __PRETTY_FUNCTION__,
1196 wxLogTrace(traceMask,
"(%s) assigning the string to value",
1197 __PRETTY_FUNCTION__);
1201 "Multiline strings are not allowed by JSON syntax");
1202 wxLogTrace(traceMask,
"(%s) concatenate the string to value",
1203 __PRETTY_FUNCTION__);
1206 AddError(_T(
"String value \'%s\' cannot follow another value"), s);
1241 while (nextCh >= 0) {
1254 wxLogTrace(traceMask,
"(%s) line=%d col=%d", __PRETTY_FUNCTION__,
1256 wxLogTrace(traceMask,
"(%s) token read=%s", __PRETTY_FUNCTION__,
1261 s.Append((
unsigned char)nextCh, 1);
1267 wxLogTrace(traceMask,
"(%s) EOF on line=%d col=%d", __PRETTY_FUNCTION__,
1269 wxLogTrace(traceMask,
"(%s) EOF - token read=%s", __PRETTY_FUNCTION__,
1301 wxLogTrace(traceMask,
"(%s) value=%s", __PRETTY_FUNCTION__,
1305 AddError(_T(
"Value \'%s\' cannot follow a value: \',\' or \':\' missing?"),
1313#if defined(wxJSON_64BIT_INT)
1317 unsigned long int ul;
1324 wxLogTrace(traceMask,
"(%s) value = nullptr", __PRETTY_FUNCTION__);
1326 }
else if (s.CmpNoCase(_T(
"null" )) == 0) {
1327 wxLogTrace(traceMask,
"(%s) value = nullptr", __PRETTY_FUNCTION__);
1329 _T(
"the \'null\' literal must be lowercase" ));
1332 }
else if (s ==
"true") {
1333 wxLogTrace(traceMask,
"(%s) value = TRUE", __PRETTY_FUNCTION__);
1336 }
else if (s.CmpNoCase(_T(
"true" )) == 0) {
1337 wxLogTrace(traceMask,
"(%s) value = TRUE", __PRETTY_FUNCTION__);
1339 _T(
"the \'true\' literal must be lowercase" ));
1342 }
else if (s ==
"false") {
1343 wxLogTrace(traceMask,
"(%s) value = FALSE", __PRETTY_FUNCTION__);
1346 }
else if (s.CmpNoCase(_T(
"false" )) == 0) {
1347 wxLogTrace(traceMask,
"(%s) value = FALSE", __PRETTY_FUNCTION__);
1349 _T(
"the \'false\' literal must be lowercase" ));
1359 bool tSigned =
true, tUnsigned =
true, tDouble =
true;
1384 AddError(_T(
"Literal \'%s\' is incorrect (did you forget quotes?)"), s);
1389#if defined(wxJSON_64BIT_INT)
1390 r = Strtoll(s, &i64);
1391 wxLogTrace(traceMask,
"(%s) convert to wxInt64 result=%d",
1392 __PRETTY_FUNCTION__, r);
1400 wxLogTrace(traceMask,
"(%s) convert to int result=%d", __PRETTY_FUNCTION__,
1411#if defined(wxJSON_64BIT_INT)
1412 r = Strtoull(s, &ui64);
1413 wxLogTrace(traceMask,
"(%s) convert to wxUint64 result=%d",
1414 __PRETTY_FUNCTION__, r);
1422 wxLogTrace(traceMask,
"(%s) convert to int result=%d", __PRETTY_FUNCTION__,
1426 val = (
unsigned int)ul;
1434 wxLogTrace(traceMask,
"(%s) convert to double result=%d",
1435 __PRETTY_FUNCTION__, r);
1444 AddError(_T(
"Literal \'%s\' is incorrect (did you forget quotes?)"), s);
1470 for (
int i = 0; i < 4; i++) {
1475 uesBuffer[i] = (
unsigned char)ch;
1511 int r = sscanf(uesBuffer,
"%lx", &l);
1513 AddError(_T(
"Invalid Unicode Escaped Sequence"));
1516 wxLogTrace(traceMask,
"(%s) unicode sequence=%s code=%ld",
1517 __PRETTY_FUNCTION__, uesBuffer, l);
1519 wchar_t ch = (wchar_t)l;
1521 size_t len = wxConvUTF8.FromWChar(buffer, 10, &ch, 1);
1528 utf8Buff.AppendData(buffer, len);
1531 wxASSERT(len != wxCONV_FAILED);
1562 wxLogTrace(storeTraceMask,
"(%s) m_comment=%s", __PRETTY_FUNCTION__,
1564 wxLogTrace(storeTraceMask,
"(%s) m_flags=%d m_commentLine=%d",
1566 wxLogTrace(storeTraceMask,
"(%s) m_current=%p", __PRETTY_FUNCTION__,
1568 wxLogTrace(storeTraceMask,
"(%s) m_next=%p", __PRETTY_FUNCTION__,
m_next);
1569 wxLogTrace(storeTraceMask,
"(%s) m_lastStored=%p", __PRETTY_FUNCTION__,
1573 if ((
m_flags & wxJSONREADER_STORE_COMMENTS) == 0) {
1581 wxLogTrace(storeTraceMask,
"(%s) m_current->lineNo=%d", __PRETTY_FUNCTION__,
1584 wxLogTrace(storeTraceMask,
"(%s) comment added to \'m_current\' INLINE",
1585 __PRETTY_FUNCTION__);
1592 wxLogTrace(storeTraceMask,
"(%s) m_next->lineNo=%d", __PRETTY_FUNCTION__,
1595 wxLogTrace(storeTraceMask,
"(%s) comment added to \'m_next\' INLINE",
1596 __PRETTY_FUNCTION__);
1603 wxLogTrace(storeTraceMask,
"(%s) m_lastStored->lineNo=%d",
1606 wxLogTrace(storeTraceMask,
1607 "(%s) comment added to \'m_lastStored\' INLINE",
1608 __PRETTY_FUNCTION__);
1620 if (
m_flags & wxJSONREADER_COMMENTS_AFTER) {
1623 AddError(
"Cannot find a value for storing the comment (flag AFTER)");
1625 wxLogTrace(storeTraceMask,
"(%s) comment added to m_current (AFTER)",
1626 __PRETTY_FUNCTION__);
1630 wxLogTrace(storeTraceMask,
"(%s) comment added to m_lastStored (AFTER)",
1631 __PRETTY_FUNCTION__);
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)");
1641 wxLogTrace(storeTraceMask,
"(%s) comment added to m_next (BEFORE)",
1642 __PRETTY_FUNCTION__);
1646 AddError(
"Cannot find a value for storing the comment (flag BEFORE)");
1690 for (
int i = 0; i < 8; i++) {
1691 if ((ch & 0x80) == 0) {
1702 }
else if (num == 0) {
1725 const wxMemoryBuffer& utf8Buffer) {
1726 size_t len = utf8Buffer.GetDataLen();
1727 char* buff = (
char*)utf8Buffer.GetData();
1728 char* buffEnd = buff + len;
1733 while (buff < buffEnd) {
1738 for (
int i = 1; i < numBytes; i++) {
1739 if (buff >= buffEnd) {
1750 size_t outLength = wxConvUTF8.ToWChar(dst, 10, temp, numBytes);
1755 len = wxConvLibc.FromWChar(temp, 16, dst, outLength);
1756 if (len == wxCONV_FAILED) {
1759 t.Printf(_T(
"\\u%04X"), (
int)dst[0]);
1762 s.Append(temp[0], 1);
1785 unsigned char cu[2];
1790 static const wxChar* membuffError =
1791 _T(
"the \'memory buffer\' type contains %d invalid digits" );
1794 _T(
"the \'memory buffer\' type is not valid JSON text" ));
1796 wxMemoryBuffer buff;
1799 unsigned char byte = 0;
1809 unsigned char c1 = (
unsigned char)ch;
1814 unsigned char c2 = (
unsigned char)ch;
1825 }
else if (c2 > 15) {
1828 byte = (c1 * 16) + c2;
1829 buff.AppendByte(
byte);
1835 err.Printf(membuffError, errors);
1844 wxLogTrace(traceMask,
"(%s) assigning the memory buffer to value",
1845 __PRETTY_FUNCTION__);
1848 wxLogTrace(traceMask,
"(%s) concatenate memory buffer to value",
1849 __PRETTY_FUNCTION__);
1852 AddError(_T(
"Memory buffer value cannot follow another value"));
1865#if defined(wxJSON_64BIT_INT)
1893bool wxJSONReader::Strtoll(
const wxString& str, wxInt64* i64) {
1896 bool r = DoStrto_ll(str, &ui64, &sign);
1902 if (ui64 > (wxUint64)LLONG_MAX + 1) {
1905 *i64 = (wxInt64)(ui64 * -1);
1911 if (ui64 > LLONG_MAX) {
1914 *i64 = (wxInt64)ui64;
1926bool wxJSONReader::Strtoull(
const wxString& str, wxUint64* ui64) {
1928 bool r = DoStrto_ll(str, ui64, &sign);
1947bool wxJSONReader::DoStrto_ll(
const wxString& str, wxUint64* ui64,
1963 wxUint64 power10[] = {wxULL(1),
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)};
1984 wxUint64 temp1 = wxULL(0);
1986 int strLen = str.length();
1995 if (ch ==
'+' || ch ==
'-') {
2001 if (strLen > maxDigits) {
2007 if (strLen == maxDigits) {
2008 wxString uLongMax(
"18446744073709551615");
2010 for (
int i = index; i < strLen - 1; i++) {
2012 if (ch <
'0' || ch >
'9') {
2015 if (ch > uLongMax[j]) {
2018 if (ch < uLongMax[j]) {
2028 for (
int i = strLen - 1; i >= index; i--) {
2030 if (ch <
'0' || ch >
'9') {
2035 temp1 += ch * power10[exponent];
int m_colNo
The current column number (start at 1).
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.
bool m_noUtf8
ANSI: do not convert UTF-8 strings.
wxJSONValue * m_lastStored
The pointer to the value object that was last stored.
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,.
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).
int GetDepth() const
Return the depth of the JSON input text.
int m_commentLine
The starting line of the comment string.
int m_depth
The depth level of the read JSON text.
wxJSONValue * m_current
The pointer to the value object that is being read.
int m_level
The current level of object/array annidation (start at ZERO).
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.
wxArrayString m_warnings
The array of warning messages.
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.
int GetWarningCount() const
Return the size of the warning message's array.
wxString m_comment
The comment string read by SkipComment().
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)
int PeekChar(wxInputStream &is)
Peek a character from the input JSON document.
The JSON value class implementation.
bool IsArray() const
Return TRUE if the type of the value stored is an array type.
int AddComment(const wxString &str, int position=wxJSONVALUE_COMMENT_DEFAULT)
Add a comment to this JSON value object.
bool IsString() const
Return TRUE if the type of the value stored is a wxString object.
wxJSONValue & Append(const wxJSONValue &value)
Append the specified value in the array.
wxString AsString() const
Return the stored value as a wxWidget's string.
int GetLineNo() const
Return the line number of this JSON value object.
bool IsValid() const
Return TRUE if the value stored is valid.
bool IsMemoryBuff() const
Return TRUE if the type of this value is a binary memory buffer.
void SetLineNo(int num)
Set the line number of this JSON value object.
bool IsObject() const
Return TRUE if the type of this value is a key/value map.
wxJSONRefData * SetType(wxJSONType type)
Set the type of the stored value.
const wxJSONInternalArray * AsArray() const
Return the stored value as an array object.
Read a memory buffer type.