17#define wxDEBUG_LEVEL 0
20#include <wx/jsonreader.h>
22#include <wx/mstream.h>
23#include <wx/sstream.h>
177static const wxChar* traceMask = _T(
"traceReader");
178static const wxChar* storeTraceMask = _T(
"StoreComment");
244#if !defined(wxJSON_USE_UNICODE)
247 if (
m_flags & wxJSONREADER_NOUTF8_STREAM) {
303#if !defined(wxJSON_USE_UNICODE)
311 char* readBuff =
nullptr;
312 wxCharBuffer utf8CB = doc.ToUTF8();
313#if !defined(wxJSON_USE_UNICODE)
314 wxCharBuffer ansiCB(doc.c_str());
316 readBuff = ansiCB.data();
318 readBuff = utf8CB.data();
321 readBuff = utf8CB.data();
325 size_t len = strlen(readBuff);
326 wxMemoryInputStream is(readBuff, len);
328 int numErr =
Parse(is, val);
329#if !defined(wxJSON_USE_UNICODE)
350 if (val ==
nullptr) {
364 val->
SetType(wxJSONTYPE_OBJECT);
367 val->
SetType(wxJSONTYPE_ARRAY);
370 AddError(_T(
"Cannot find a start object/array character" ));
463 unsigned char ch = is.GetC();
464 size_t last = is.LastRead();
476 if (nextChar == -1) {
478 }
else if (nextChar ==
'\n') {
579 AddError(_T(
"\'{\' is not allowed here (\'name\' is missing"));
581 if (value.IsValid()) {
582 AddError(_T(
"\'{\' cannot follow a \'value\'"));
585 if (value.IsValid()) {
586 AddError(_T(
"\'{\' cannot follow a \'value\' in JSON array"));
593 value.SetType(wxJSONTYPE_OBJECT);
600 wxJSONREADER_MISSING,
601 _T(
"Trying to close an array using the \'}\' (close-object) char" ));
615 AddError(_T(
"\'[\' is not allowed here (\'name\' is missing"));
617 if (value.IsValid()) {
618 AddError(_T(
"\'[\' cannot follow a \'value\' text"));
621 if (value.IsValid()) {
622 AddError(_T(
"\'[\' cannot follow a \'value\'"));
628 value.SetType(wxJSONTYPE_ARRAY);
636 wxJSONREADER_MISSING,
637 _T(
"Trying to close an object using the \']\' (close-array) char" ));
670 AddError(_T(
"\':\' can only used in object's values" ));
671 }
else if (!value.IsString()) {
673 _T(
"\':\' follows a value which is not of type \'string\'" ));
674 }
else if (!key.empty()) {
676 _T(
"\':\' not allowed where a \'name\' string was already available" ));
679 key = value.AsString();
680 value.SetType(wxJSONTYPE_INVALID);
700 AddWarning(wxJSONREADER_MISSING, _T(
"\']\' missing at end of file"));
702 AddWarning(wxJSONREADER_MISSING, _T(
"\'}\' missing at end of file"));
735 wxLogTrace(traceMask, _T(
"(%s) ch=%d char=%c"), __PRETTY_FUNCTION__, ch,
737 wxLogTrace(traceMask, _T(
"(%s) value=%s"), __PRETTY_FUNCTION__,
738 value.AsString().c_str());
745 if (!value.IsValid() && key.empty()) {
747 if (ch ==
'}' || ch ==
']') {
749 wxLogTrace(traceMask, _T(
"(%s) key and value are empty, returning"),
750 __PRETTY_FUNCTION__);
752 AddError(_T(
"key or value is missing for JSON value"));
757 if (!value.IsValid()) {
759 _T(
"cannot store the value: \'value\' is missing for JSON object ")
761 }
else if (key.empty()) {
763 _T(
"cannot store the value: \'key\' is missing for JSON object ")
767 wxLogTrace(traceMask, _T(
"(%s) adding value to key:%s"),
768 __PRETTY_FUNCTION__, key.c_str());
774 if (!value.IsValid()) {
776 _T(
"cannot store the item: \'value\' is missing for JSON array ")
781 _T(
"cannot store the item: \'key\' (\'%s\') is not permitted in ")
782 _T(
"JSON array type"),
785 wxLogTrace(traceMask, _T(
"(%s) appending value to parent array"),
786 __PRETTY_FUNCTION__);
788 const wxJSONInternalArray* arr = parent.
AsArray();
796 value.SetType(wxJSONTYPE_INVALID);
797 value.ClearComments();
818 err.Printf(_T(
"Error: line %d, col %d - %s"),
m_lineNo,
m_colNo, msg.c_str());
820 wxLogTrace(traceMask, _T(
"(%s) %s"), __PRETTY_FUNCTION__, err.c_str());
826 _T(
"ERROR: too many error messages - ignoring further errors"));
835 s.Printf(fmt.c_str(), str.c_str());
842 s.Printf(fmt.c_str(), c);
883 wxLogTrace(traceMask, _T(
"(%s) %s"), __PRETTY_FUNCTION__, err.c_str());
888 _T(
"Error: too many warning messages - ignoring further warnings"));
910 }
while (ch ==
' ' || ch ==
'\n' || ch ==
'\t');
911 wxLogTrace(traceMask, _T(
"(%s) end whitespaces line=%d col=%d"),
929 static const wxChar* warn =
930 _T(
"Comments may be tolerated in JSON text but they are not part of ")
941 wxLogTrace(storeTraceMask, _T(
"(%s) start comment line=%d col=%d"),
946 wxMemoryBuffer utf8Buff;
952 AddWarning(wxJSONREADER_ALLOW_COMMENTS, warn);
954 utf8Buff.AppendData(
"//", 2);
968 c = (
unsigned char)ch;
969 utf8Buff.AppendByte(c);
974 m_comment = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
975 utf8Buff.GetDataLen());
979 else if (ch ==
'*') {
980 AddWarning(wxJSONREADER_ALLOW_COMMENTS, warn);
982 utf8Buff.AppendData(
"/*", 2);
990 utf8Buff.AppendData(
"*/", 2);
995 c = (
unsigned char)ch;
996 utf8Buff.AppendByte(c);
1001 m_comment = wxString::From8BitData((
const char*)utf8Buff.GetData(),
1002 utf8Buff.GetDataLen());
1004 m_comment = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1005 utf8Buff.GetDataLen());
1010 AddError(_T(
"Strange '/' (did you want to insert a comment?)"));
1015 if (ch ==
'*' &&
PeekChar(is) ==
'/') {
1025 wxLogTrace(traceMask, _T(
"(%s) end comment line=%d col=%d"),
1027 wxLogTrace(storeTraceMask, _T(
"(%s) end comment line=%d col=%d"),
1029 wxLogTrace(storeTraceMask, _T(
"(%s) comment=%s"), __PRETTY_FUNCTION__,
1081 wxMemoryBuffer utf8Buff;
1087 unsigned char c = (
unsigned char)ch;
1094 utf8Buff.AppendByte(
'\t');
1097 utf8Buff.AppendByte(
'\n');
1100 utf8Buff.AppendByte(
'\b');
1103 utf8Buff.AppendByte(
'\r');
1106 utf8Buff.AppendByte(
'\"');
1109 utf8Buff.AppendByte(
'\\');
1112 utf8Buff.AppendByte(
'/');
1115 utf8Buff.AppendByte(
'\f');
1128 AddError(_T(
"Unknow escaped character \'\\%c\'"), ch);
1136 utf8Buff.AppendByte(c);
1144 s = wxString::From8BitData((
const char*)utf8Buff.GetData(),
1145 utf8Buff.GetDataLen());
1152 wxConvUTF8.ToWChar(0,
1154 (
const char*)utf8Buff.GetData(),
1155 utf8Buff.GetDataLen());
1157 if (convLen == wxCONV_FAILED) {
1158 AddError(_T(
"String value: the UTF-8 stream is invalid"));
1159 s.append(_T(
"<UTF-8 stream not valid>"));
1161#if defined(wxJSON_USE_UNICODE)
1163 s = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1164 utf8Buff.GetDataLen());
1169 s = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1170 utf8Buff.GetDataLen());
1177 _T(
"The string value contains unrepresentable Unicode characters"));
1183 wxLogTrace(traceMask, _T(
"(%s) line=%d col=%d"), __PRETTY_FUNCTION__,
1185 wxLogTrace(traceMask, _T(
"(%s) string read=%s"), __PRETTY_FUNCTION__,
1187 wxLogTrace(traceMask, _T(
"(%s) value=%s"), __PRETTY_FUNCTION__,
1195 wxLogTrace(traceMask, _T(
"(%s) assigning the string to value"),
1196 __PRETTY_FUNCTION__);
1200 _T(
"Multiline strings are not allowed by JSON syntax"));
1201 wxLogTrace(traceMask, _T(
"(%s) concatenate the string to value"),
1202 __PRETTY_FUNCTION__);
1205 AddError(_T(
"String value \'%s\' cannot follow another value"), s);
1240 while (nextCh >= 0) {
1253 wxLogTrace(traceMask, _T(
"(%s) line=%d col=%d"), __PRETTY_FUNCTION__,
1255 wxLogTrace(traceMask, _T(
"(%s) token read=%s"), __PRETTY_FUNCTION__,
1260 s.Append((
unsigned char)nextCh, 1);
1266 wxLogTrace(traceMask, _T(
"(%s) EOF on line=%d col=%d"), __PRETTY_FUNCTION__,
1268 wxLogTrace(traceMask, _T(
"(%s) EOF - token read=%s"), __PRETTY_FUNCTION__,
1300 wxLogTrace(traceMask, _T(
"(%s) value=%s"), __PRETTY_FUNCTION__,
1304 AddError(_T(
"Value \'%s\' cannot follow a value: \',\' or \':\' missing?"),
1312#if defined(wxJSON_64BIT_INT)
1316 unsigned long int ul;
1321 if (s == _T(
"null")) {
1323 wxLogTrace(traceMask, _T(
"(%s) value = nullptr"), __PRETTY_FUNCTION__);
1325 }
else if (s.CmpNoCase(_T(
"null" )) == 0) {
1326 wxLogTrace(traceMask, _T(
"(%s) value = nullptr"), __PRETTY_FUNCTION__);
1328 _T(
"the \'null\' literal must be lowercase" ));
1331 }
else if (s == _T(
"true")) {
1332 wxLogTrace(traceMask, _T(
"(%s) value = TRUE"), __PRETTY_FUNCTION__);
1335 }
else if (s.CmpNoCase(_T(
"true" )) == 0) {
1336 wxLogTrace(traceMask, _T(
"(%s) value = TRUE"), __PRETTY_FUNCTION__);
1338 _T(
"the \'true\' literal must be lowercase" ));
1341 }
else if (s == _T(
"false")) {
1342 wxLogTrace(traceMask, _T(
"(%s) value = FALSE"), __PRETTY_FUNCTION__);
1345 }
else if (s.CmpNoCase(_T(
"false" )) == 0) {
1346 wxLogTrace(traceMask, _T(
"(%s) value = FALSE"), __PRETTY_FUNCTION__);
1348 _T(
"the \'false\' literal must be lowercase" ));
1358 bool tSigned =
true, tUnsigned =
true, tDouble =
true;
1383 AddError(_T(
"Literal \'%s\' is incorrect (did you forget quotes?)"), s);
1388#if defined(wxJSON_64BIT_INT)
1389 r = Strtoll(s, &i64);
1390 wxLogTrace(traceMask, _T(
"(%s) convert to wxInt64 result=%d"),
1391 __PRETTY_FUNCTION__, r);
1399 wxLogTrace(traceMask, _T(
"(%s) convert to int result=%d"),
1400 __PRETTY_FUNCTION__, r);
1410#if defined(wxJSON_64BIT_INT)
1411 r = Strtoull(s, &ui64);
1412 wxLogTrace(traceMask, _T(
"(%s) convert to wxUint64 result=%d"),
1413 __PRETTY_FUNCTION__, r);
1421 wxLogTrace(traceMask, _T(
"(%s) convert to int result=%d"),
1422 __PRETTY_FUNCTION__, r);
1425 val = (
unsigned int)ul;
1433 wxLogTrace(traceMask, _T(
"(%s) convert to double result=%d"),
1434 __PRETTY_FUNCTION__, r);
1443 AddError(_T(
"Literal \'%s\' is incorrect (did you forget quotes?)"), s);
1469 for (
int i = 0; i < 4; i++) {
1474 uesBuffer[i] = (
unsigned char)ch;
1510 int r = sscanf(uesBuffer,
"%lx", &l);
1512 AddError(_T(
"Invalid Unicode Escaped Sequence"));
1515 wxLogTrace(traceMask, _T(
"(%s) unicode sequence=%s code=%ld"),
1516 __PRETTY_FUNCTION__, uesBuffer, l);
1518 wchar_t ch = (wchar_t)l;
1520 size_t len = wxConvUTF8.FromWChar(buffer, 10, &ch, 1);
1527 utf8Buff.AppendData(buffer, len);
1530 wxASSERT(len != wxCONV_FAILED);
1561 wxLogTrace(storeTraceMask, _T(
"(%s) m_comment=%s"), __PRETTY_FUNCTION__,
1563 wxLogTrace(storeTraceMask, _T(
"(%s) m_flags=%d m_commentLine=%d"),
1565 wxLogTrace(storeTraceMask, _T(
"(%s) m_current=%p"), __PRETTY_FUNCTION__,
1567 wxLogTrace(storeTraceMask, _T(
"(%s) m_next=%p"), __PRETTY_FUNCTION__,
m_next);
1568 wxLogTrace(storeTraceMask, _T(
"(%s) m_lastStored=%p"), __PRETTY_FUNCTION__,
1572 if ((
m_flags & wxJSONREADER_STORE_COMMENTS) == 0) {
1580 wxLogTrace(storeTraceMask, _T(
"(%s) m_current->lineNo=%d"),
1583 wxLogTrace(storeTraceMask,
1584 _T(
"(%s) comment added to \'m_current\' INLINE"),
1585 __PRETTY_FUNCTION__);
1592 wxLogTrace(storeTraceMask, _T(
"(%s) m_next->lineNo=%d"),
1595 wxLogTrace(storeTraceMask, _T(
"(%s) comment added to \'m_next\' INLINE"),
1596 __PRETTY_FUNCTION__);
1603 wxLogTrace(storeTraceMask, _T(
"(%s) m_lastStored->lineNo=%d"),
1606 wxLogTrace(storeTraceMask,
1607 _T(
"(%s) comment added to \'m_lastStored\' INLINE"),
1608 __PRETTY_FUNCTION__);
1620 if (
m_flags & wxJSONREADER_COMMENTS_AFTER) {
1624 _T(
"Cannot find a value for storing the comment (flag AFTER)"));
1626 wxLogTrace(storeTraceMask,
1627 _T(
"(%s) comment added to m_current (AFTER)"),
1628 __PRETTY_FUNCTION__);
1632 wxLogTrace(storeTraceMask,
1633 _T(
"(%s) comment added to m_lastStored (AFTER)"),
1634 __PRETTY_FUNCTION__);
1637 wxLogTrace(storeTraceMask,
1638 _T(
"(%s) cannot find a value for storing the AFTER comment"),
1639 __PRETTY_FUNCTION__);
1640 AddError(_T(
"Cannot find a value for storing the comment (flag AFTER)"));
1644 wxLogTrace(storeTraceMask, _T(
"(%s) comment added to m_next (BEFORE)"),
1645 __PRETTY_FUNCTION__);
1649 AddError(_T(
"Cannot find a value for storing the comment (flag BEFORE)"));
1693 for (
int i = 0; i < 8; i++) {
1694 if ((ch & 0x80) == 0) {
1705 }
else if (num == 0) {
1728 const wxMemoryBuffer& utf8Buffer) {
1729 size_t len = utf8Buffer.GetDataLen();
1730 char* buff = (
char*)utf8Buffer.GetData();
1731 char* buffEnd = buff + len;
1736 while (buff < buffEnd) {
1741 for (
int i = 1; i < numBytes; i++) {
1742 if (buff >= buffEnd) {
1753 size_t outLength = wxConvUTF8.ToWChar(dst, 10, temp, numBytes);
1758 len = wxConvLibc.FromWChar(temp, 16, dst, outLength);
1759 if (len == wxCONV_FAILED) {
1762 t.Printf(_T(
"\\u%04X"), (
int)dst[0]);
1765 s.Append(temp[0], 1);
1788 unsigned char cu[2];
1793 static const wxChar* membuffError =
1794 _T(
"the \'memory buffer\' type contains %d invalid digits" );
1797 _T(
"the \'memory buffer\' type is not valid JSON text" ));
1799 wxMemoryBuffer buff;
1802 unsigned char byte = 0;
1812 unsigned char c1 = (
unsigned char)ch;
1817 unsigned char c2 = (
unsigned char)ch;
1828 }
else if (c2 > 15) {
1831 byte = (c1 * 16) + c2;
1832 buff.AppendByte(
byte);
1838 err.Printf(membuffError, errors);
1847 wxLogTrace(traceMask, _T(
"(%s) assigning the memory buffer to value"),
1848 __PRETTY_FUNCTION__);
1851 wxLogTrace(traceMask, _T(
"(%s) concatenate memory buffer to value"),
1852 __PRETTY_FUNCTION__);
1855 AddError(_T(
"Memory buffer value cannot follow another value"));
1868#if defined(wxJSON_64BIT_INT)
1896bool wxJSONReader::Strtoll(
const wxString& str, wxInt64* i64) {
1899 bool r = DoStrto_ll(str, &ui64, &sign);
1905 if (ui64 > (wxUint64)LLONG_MAX + 1) {
1908 *i64 = (wxInt64)(ui64 * -1);
1914 if (ui64 > LLONG_MAX) {
1917 *i64 = (wxInt64)ui64;
1929bool wxJSONReader::Strtoull(
const wxString& str, wxUint64* ui64) {
1931 bool r = DoStrto_ll(str, ui64, &sign);
1950bool wxJSONReader::DoStrto_ll(
const wxString& str, wxUint64* ui64,
1966 wxUint64 power10[] = {wxULL(1),
1977 wxULL(100000000000),
1978 wxULL(1000000000000),
1979 wxULL(10000000000000),
1980 wxULL(100000000000000),
1981 wxULL(1000000000000000),
1982 wxULL(10000000000000000),
1983 wxULL(100000000000000000),
1984 wxULL(1000000000000000000),
1985 wxULL(10000000000000000000)};
1987 wxUint64 temp1 = wxULL(0);
1989 int strLen = str.length();
1998 if (ch ==
'+' || ch ==
'-') {
2004 if (strLen > maxDigits) {
2010 if (strLen == maxDigits) {
2011 wxString uLongMax(_T(
"18446744073709551615"));
2013 for (
int i = index; i < strLen - 1; i++) {
2015 if (ch <
'0' || ch >
'9') {
2018 if (ch > uLongMax[j]) {
2021 if (ch < uLongMax[j]) {
2031 for (
int i = strLen - 1; i >= index; i--) {
2033 if (ch <
'0' || ch >
'9') {
2038 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.