17#define wxDEBUG_LEVEL 0
20#include <wx/jsonreader.h>
22#include <wx/mstream.h>
23#include <wx/sstream.h>
177static const wxChar* traceMask =
"traceReader";
178static const wxChar* storeTraceMask =
"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(
"\'{\' is not allowed here (\'name\' is missing");
581 if (value.IsValid()) {
582 AddError(
"\'{\' cannot follow a \'value\'");
585 if (value.IsValid()) {
586 AddError(
"\'{\' 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(
"\'[\' is not allowed here (\'name\' is missing");
617 if (value.IsValid()) {
618 AddError(
"\'[\' cannot follow a \'value\' text");
621 if (value.IsValid()) {
622 AddError(
"\'[\' 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,
"\']\' missing at end of file");
702 AddWarning(wxJSONREADER_MISSING,
"\'}\' missing at end of file");
735 wxLogTrace(traceMask,
"(%s) ch=%d char=%c", __PRETTY_FUNCTION__, ch,
737 wxLogTrace(traceMask,
"(%s) value=%s", __PRETTY_FUNCTION__,
738 value.AsString().c_str());
745 if (!value.IsValid() && key.empty()) {
747 if (ch ==
'}' || ch ==
']') {
749 wxLogTrace(traceMask,
"(%s) key and value are empty, returning",
750 __PRETTY_FUNCTION__);
752 AddError(
"key or value is missing for JSON value");
757 if (!value.IsValid()) {
759 "cannot store the value: \'value\' is missing for JSON object "
761 }
else if (key.empty()) {
763 "cannot store the value: \'key\' is missing for JSON object "
767 wxLogTrace(traceMask,
"(%s) adding value to key:%s",
768 __PRETTY_FUNCTION__, key.c_str());
774 if (!value.IsValid()) {
776 "cannot store the item: \'value\' is missing for JSON array "
781 "cannot store the item: \'key\' (\'%s\') is not permitted in "
785 wxLogTrace(traceMask,
"(%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(
"Error: line %d, col %d - %s",
m_lineNo,
m_colNo, msg.c_str());
820 wxLogTrace(traceMask,
"(%s) %s", __PRETTY_FUNCTION__, err.c_str());
825 m_errors.Add(
"ERROR: too many error messages - ignoring further errors");
834 s.Printf(fmt.c_str(), str.c_str());
841 s.Printf(fmt.c_str(), c);
882 wxLogTrace(traceMask,
"(%s) %s", __PRETTY_FUNCTION__, err.c_str());
887 "Error: too many warning messages - ignoring further warnings");
909 }
while (ch ==
' ' || ch ==
'\n' || ch ==
'\t');
910 wxLogTrace(traceMask,
"(%s) end whitespaces line=%d col=%d",
928 static const wxChar* warn =
929 "Comments may be tolerated in JSON text but they are not part of "
940 wxLogTrace(storeTraceMask,
"(%s) start comment line=%d col=%d",
945 wxMemoryBuffer utf8Buff;
951 AddWarning(wxJSONREADER_ALLOW_COMMENTS, warn);
953 utf8Buff.AppendData(
"//", 2);
967 c = (
unsigned char)ch;
968 utf8Buff.AppendByte(c);
973 m_comment = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
974 utf8Buff.GetDataLen());
978 else if (ch ==
'*') {
979 AddWarning(wxJSONREADER_ALLOW_COMMENTS, warn);
981 utf8Buff.AppendData(
"/*", 2);
989 utf8Buff.AppendData(
"*/", 2);
994 c = (
unsigned char)ch;
995 utf8Buff.AppendByte(c);
1000 m_comment = wxString::From8BitData((
const char*)utf8Buff.GetData(),
1001 utf8Buff.GetDataLen());
1003 m_comment = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1004 utf8Buff.GetDataLen());
1009 AddError(_T(
"Strange '/' (did you want to insert a comment?)"));
1014 if (ch ==
'*' &&
PeekChar(is) ==
'/') {
1024 wxLogTrace(traceMask,
"(%s) end comment line=%d col=%d", __PRETTY_FUNCTION__,
1026 wxLogTrace(storeTraceMask,
"(%s) end comment line=%d col=%d",
1028 wxLogTrace(storeTraceMask,
"(%s) comment=%s", __PRETTY_FUNCTION__,
1080 wxMemoryBuffer utf8Buff;
1086 unsigned char c = (
unsigned char)ch;
1093 utf8Buff.AppendByte(
'\t');
1096 utf8Buff.AppendByte(
'\n');
1099 utf8Buff.AppendByte(
'\b');
1102 utf8Buff.AppendByte(
'\r');
1105 utf8Buff.AppendByte(
'\"');
1108 utf8Buff.AppendByte(
'\\');
1111 utf8Buff.AppendByte(
'/');
1114 utf8Buff.AppendByte(
'\f');
1127 AddError(_T(
"Unknow escaped character \'\\%c\'"), ch);
1135 utf8Buff.AppendByte(c);
1143 s = wxString::From8BitData((
const char*)utf8Buff.GetData(),
1144 utf8Buff.GetDataLen());
1151 wxConvUTF8.ToWChar(0,
1153 (
const char*)utf8Buff.GetData(),
1154 utf8Buff.GetDataLen());
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>"));
1160#if defined(wxJSON_USE_UNICODE)
1162 s = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1163 utf8Buff.GetDataLen());
1168 s = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1169 utf8Buff.GetDataLen());
1176 _T(
"The string value contains unrepresentable Unicode characters"));
1182 wxLogTrace(traceMask,
"(%s) line=%d col=%d", __PRETTY_FUNCTION__,
m_lineNo,
1184 wxLogTrace(traceMask,
"(%s) string read=%s", __PRETTY_FUNCTION__, s.c_str());
1185 wxLogTrace(traceMask,
"(%s) value=%s", __PRETTY_FUNCTION__,
1193 wxLogTrace(traceMask,
"(%s) assigning the string to value",
1194 __PRETTY_FUNCTION__);
1198 "Multiline strings are not allowed by JSON syntax");
1199 wxLogTrace(traceMask,
"(%s) concatenate the string to value",
1200 __PRETTY_FUNCTION__);
1203 AddError(_T(
"String value \'%s\' cannot follow another value"), s);
1238 while (nextCh >= 0) {
1251 wxLogTrace(traceMask,
"(%s) line=%d col=%d", __PRETTY_FUNCTION__,
1253 wxLogTrace(traceMask,
"(%s) token read=%s", __PRETTY_FUNCTION__,
1258 s.Append((
unsigned char)nextCh, 1);
1264 wxLogTrace(traceMask,
"(%s) EOF on line=%d col=%d", __PRETTY_FUNCTION__,
1266 wxLogTrace(traceMask,
"(%s) EOF - token read=%s", __PRETTY_FUNCTION__,
1298 wxLogTrace(traceMask,
"(%s) value=%s", __PRETTY_FUNCTION__,
1302 AddError(_T(
"Value \'%s\' cannot follow a value: \',\' or \':\' missing?"),
1310#if defined(wxJSON_64BIT_INT)
1314 unsigned long int ul;
1321 wxLogTrace(traceMask,
"(%s) value = nullptr", __PRETTY_FUNCTION__);
1323 }
else if (s.CmpNoCase(_T(
"null" )) == 0) {
1324 wxLogTrace(traceMask,
"(%s) value = nullptr", __PRETTY_FUNCTION__);
1326 _T(
"the \'null\' literal must be lowercase" ));
1329 }
else if (s ==
"true") {
1330 wxLogTrace(traceMask,
"(%s) value = TRUE", __PRETTY_FUNCTION__);
1333 }
else if (s.CmpNoCase(_T(
"true" )) == 0) {
1334 wxLogTrace(traceMask,
"(%s) value = TRUE", __PRETTY_FUNCTION__);
1336 _T(
"the \'true\' literal must be lowercase" ));
1339 }
else if (s ==
"false") {
1340 wxLogTrace(traceMask,
"(%s) value = FALSE", __PRETTY_FUNCTION__);
1343 }
else if (s.CmpNoCase(_T(
"false" )) == 0) {
1344 wxLogTrace(traceMask,
"(%s) value = FALSE", __PRETTY_FUNCTION__);
1346 _T(
"the \'false\' literal must be lowercase" ));
1356 bool tSigned =
true, tUnsigned =
true, tDouble =
true;
1381 AddError(_T(
"Literal \'%s\' is incorrect (did you forget quotes?)"), s);
1386#if defined(wxJSON_64BIT_INT)
1387 r = Strtoll(s, &i64);
1388 wxLogTrace(traceMask,
"(%s) convert to wxInt64 result=%d",
1389 __PRETTY_FUNCTION__, r);
1397 wxLogTrace(traceMask,
"(%s) convert to int result=%d", __PRETTY_FUNCTION__,
1408#if defined(wxJSON_64BIT_INT)
1409 r = Strtoull(s, &ui64);
1410 wxLogTrace(traceMask,
"(%s) convert to wxUint64 result=%d",
1411 __PRETTY_FUNCTION__, r);
1419 wxLogTrace(traceMask,
"(%s) convert to int result=%d", __PRETTY_FUNCTION__,
1423 val = (
unsigned int)ul;
1431 wxLogTrace(traceMask,
"(%s) convert to double result=%d",
1432 __PRETTY_FUNCTION__, r);
1441 AddError(_T(
"Literal \'%s\' is incorrect (did you forget quotes?)"), s);
1467 for (
int i = 0; i < 4; i++) {
1472 uesBuffer[i] = (
unsigned char)ch;
1508 int r = sscanf(uesBuffer,
"%lx", &l);
1510 AddError(_T(
"Invalid Unicode Escaped Sequence"));
1513 wxLogTrace(traceMask,
"(%s) unicode sequence=%s code=%ld",
1514 __PRETTY_FUNCTION__, uesBuffer, l);
1516 wchar_t ch = (wchar_t)l;
1518 size_t len = wxConvUTF8.FromWChar(buffer, 10, &ch, 1);
1525 utf8Buff.AppendData(buffer, len);
1528 wxASSERT(len != wxCONV_FAILED);
1559 wxLogTrace(storeTraceMask,
"(%s) m_comment=%s", __PRETTY_FUNCTION__,
1561 wxLogTrace(storeTraceMask,
"(%s) m_flags=%d m_commentLine=%d",
1563 wxLogTrace(storeTraceMask,
"(%s) m_current=%p", __PRETTY_FUNCTION__,
1565 wxLogTrace(storeTraceMask,
"(%s) m_next=%p", __PRETTY_FUNCTION__,
m_next);
1566 wxLogTrace(storeTraceMask,
"(%s) m_lastStored=%p", __PRETTY_FUNCTION__,
1570 if ((
m_flags & wxJSONREADER_STORE_COMMENTS) == 0) {
1578 wxLogTrace(storeTraceMask,
"(%s) m_current->lineNo=%d", __PRETTY_FUNCTION__,
1581 wxLogTrace(storeTraceMask,
"(%s) comment added to \'m_current\' INLINE",
1582 __PRETTY_FUNCTION__);
1589 wxLogTrace(storeTraceMask,
"(%s) m_next->lineNo=%d", __PRETTY_FUNCTION__,
1592 wxLogTrace(storeTraceMask,
"(%s) comment added to \'m_next\' INLINE",
1593 __PRETTY_FUNCTION__);
1600 wxLogTrace(storeTraceMask,
"(%s) m_lastStored->lineNo=%d",
1603 wxLogTrace(storeTraceMask,
1604 "(%s) comment added to \'m_lastStored\' INLINE",
1605 __PRETTY_FUNCTION__);
1617 if (
m_flags & wxJSONREADER_COMMENTS_AFTER) {
1620 AddError(
"Cannot find a value for storing the comment (flag AFTER)");
1622 wxLogTrace(storeTraceMask,
"(%s) comment added to m_current (AFTER)",
1623 __PRETTY_FUNCTION__);
1627 wxLogTrace(storeTraceMask,
"(%s) comment added to m_lastStored (AFTER)",
1628 __PRETTY_FUNCTION__);
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)");
1638 wxLogTrace(storeTraceMask,
"(%s) comment added to m_next (BEFORE)",
1639 __PRETTY_FUNCTION__);
1643 AddError(
"Cannot find a value for storing the comment (flag BEFORE)");
1687 for (
int i = 0; i < 8; i++) {
1688 if ((ch & 0x80) == 0) {
1699 }
else if (num == 0) {
1722 const wxMemoryBuffer& utf8Buffer) {
1723 size_t len = utf8Buffer.GetDataLen();
1724 char* buff = (
char*)utf8Buffer.GetData();
1725 char* buffEnd = buff + len;
1730 while (buff < buffEnd) {
1735 for (
int i = 1; i < numBytes; i++) {
1736 if (buff >= buffEnd) {
1747 size_t outLength = wxConvUTF8.ToWChar(dst, 10, temp, numBytes);
1752 len = wxConvLibc.FromWChar(temp, 16, dst, outLength);
1753 if (len == wxCONV_FAILED) {
1756 t.Printf(_T(
"\\u%04X"), (
int)dst[0]);
1759 s.Append(temp[0], 1);
1782 unsigned char cu[2];
1787 static const wxChar* membuffError =
1788 _T(
"the \'memory buffer\' type contains %d invalid digits" );
1791 _T(
"the \'memory buffer\' type is not valid JSON text" ));
1793 wxMemoryBuffer buff;
1796 unsigned char byte = 0;
1806 unsigned char c1 = (
unsigned char)ch;
1811 unsigned char c2 = (
unsigned char)ch;
1822 }
else if (c2 > 15) {
1825 byte = (c1 * 16) + c2;
1826 buff.AppendByte(
byte);
1832 err.Printf(membuffError, errors);
1841 wxLogTrace(traceMask,
"(%s) assigning the memory buffer to value",
1842 __PRETTY_FUNCTION__);
1845 wxLogTrace(traceMask,
"(%s) concatenate memory buffer to value",
1846 __PRETTY_FUNCTION__);
1849 AddError(_T(
"Memory buffer value cannot follow another value"));
1862#if defined(wxJSON_64BIT_INT)
1890bool wxJSONReader::Strtoll(
const wxString& str, wxInt64* i64) {
1893 bool r = DoStrto_ll(str, &ui64, &sign);
1899 if (ui64 > (wxUint64)LLONG_MAX + 1) {
1902 *i64 = (wxInt64)(ui64 * -1);
1908 if (ui64 > LLONG_MAX) {
1911 *i64 = (wxInt64)ui64;
1923bool wxJSONReader::Strtoull(
const wxString& str, wxUint64* ui64) {
1925 bool r = DoStrto_ll(str, ui64, &sign);
1944bool wxJSONReader::DoStrto_ll(
const wxString& str, wxUint64* ui64,
1960 wxUint64 power10[] = {wxULL(1),
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)};
1981 wxUint64 temp1 = wxULL(0);
1983 int strLen = str.length();
1992 if (ch ==
'+' || ch ==
'-') {
1998 if (strLen > maxDigits) {
2004 if (strLen == maxDigits) {
2005 wxString uLongMax(
"18446744073709551615");
2007 for (
int i = index; i < strLen - 1; i++) {
2009 if (ch <
'0' || ch >
'9') {
2012 if (ch > uLongMax[j]) {
2015 if (ch < uLongMax[j]) {
2025 for (
int i = strLen - 1; i >= index; i--) {
2027 if (ch <
'0' || ch >
'9') {
2032 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.