12#pragma implementation "jsonreader.cpp"
18#define wxDEBUG_LEVEL 0
21#include "jsonreader.h"
23#include <wx/mstream.h>
24#include <wx/sstream.h>
178static const wxChar* traceMask = _T(
"traceReader");
179static const wxChar* storeTraceMask = _T(
"StoreComment");
245#if !defined(wxJSON_USE_UNICODE)
248 if (
m_flags & wxJSONREADER_NOUTF8_STREAM) {
304#if !defined(wxJSON_USE_UNICODE)
313 wxCharBuffer utf8CB = doc.ToUTF8();
314#if !defined(wxJSON_USE_UNICODE)
315 wxCharBuffer ansiCB(doc.c_str());
317 readBuff = ansiCB.data();
319 readBuff = utf8CB.data();
322 readBuff = utf8CB.data();
326 size_t len = strlen(readBuff);
327 wxMemoryInputStream is(readBuff, len);
329 int numErr =
Parse(is, val);
330#if !defined(wxJSON_USE_UNICODE)
365 val->
SetType(wxJSONTYPE_OBJECT);
368 val->
SetType(wxJSONTYPE_ARRAY);
371 AddError(_T(
"Cannot find a start object/array character" ));
464 unsigned char ch = is.GetC();
465 size_t last = is.LastRead();
477 if (nextChar == -1) {
479 }
else if (nextChar ==
'\n') {
580 AddError(_T(
"\'{\' is not allowed here (\'name\' is missing"));
582 if (value.IsValid()) {
583 AddError(_T(
"\'{\' cannot follow a \'value\'"));
586 if (value.IsValid()) {
587 AddError(_T(
"\'{\' cannot follow a \'value\' in JSON array"));
594 value.SetType(wxJSONTYPE_OBJECT);
601 wxJSONREADER_MISSING,
602 _T(
"Trying to close an array using the \'}\' (close-object) char" ));
616 AddError(_T(
"\'[\' is not allowed here (\'name\' is missing"));
618 if (value.IsValid()) {
619 AddError(_T(
"\'[\' cannot follow a \'value\' text"));
622 if (value.IsValid()) {
623 AddError(_T(
"\'[\' cannot follow a \'value\'"));
629 value.SetType(wxJSONTYPE_ARRAY);
637 wxJSONREADER_MISSING,
638 _T(
"Trying to close an object using the \']\' (close-array) char" ));
671 AddError(_T(
"\':\' can only used in object's values" ));
672 }
else if (!value.IsString()) {
674 _T(
"\':\' follows a value which is not of type \'string\'" ));
675 }
else if (!key.empty()) {
677 _T(
"\':\' not allowed where a \'name\' string was already available" ));
680 key = value.AsString();
681 value.SetType(wxJSONTYPE_INVALID);
701 AddWarning(wxJSONREADER_MISSING, _T(
"\']\' missing at end of file"));
703 AddWarning(wxJSONREADER_MISSING, _T(
"\'}\' missing at end of file"));
736 wxLogTrace(traceMask, _T(
"(%s) ch=%d char=%c"), __PRETTY_FUNCTION__, ch,
738 wxLogTrace(traceMask, _T(
"(%s) value=%s"), __PRETTY_FUNCTION__,
739 value.AsString().c_str());
746 if (!value.IsValid() && key.empty()) {
748 if (ch ==
'}' || ch ==
']') {
750 wxLogTrace(traceMask, _T(
"(%s) key and value are empty, returning"),
751 __PRETTY_FUNCTION__);
753 AddError(_T(
"key or value is missing for JSON value"));
758 if (!value.IsValid()) {
760 _T(
"cannot store the value: \'value\' is missing for JSON object ")
762 }
else if (key.empty()) {
764 _T(
"cannot store the value: \'key\' is missing for JSON object ")
768 wxLogTrace(traceMask, _T(
"(%s) adding value to key:%s"),
769 __PRETTY_FUNCTION__, key.c_str());
775 if (!value.IsValid()) {
777 _T(
"cannot store the item: \'value\' is missing for JSON array ")
782 _T(
"cannot store the item: \'key\' (\'%s\') is not permitted in ")
783 _T(
"JSON array type"),
786 wxLogTrace(traceMask, _T(
"(%s) appending value to parent array"),
787 __PRETTY_FUNCTION__);
789 const wxJSONInternalArray* arr = parent.
AsArray();
797 value.SetType(wxJSONTYPE_INVALID);
798 value.ClearComments();
819 err.Printf(_T(
"Error: line %d, col %d - %s"),
m_lineNo,
m_colNo, msg.c_str());
821 wxLogTrace(traceMask, _T(
"(%s) %s"), __PRETTY_FUNCTION__, err.c_str());
827 _T(
"ERROR: too many error messages - ignoring further errors"));
836 s.Printf(fmt.c_str(), str.c_str());
843 s.Printf(fmt.c_str(), c);
884 wxLogTrace(traceMask, _T(
"(%s) %s"), __PRETTY_FUNCTION__, err.c_str());
889 _T(
"Error: too many warning messages - ignoring further warnings"));
911 }
while (ch ==
' ' || ch ==
'\n' || ch ==
'\t');
912 wxLogTrace(traceMask, _T(
"(%s) end whitespaces line=%d col=%d"),
930 static const wxChar* warn =
931 _T(
"Comments may be tolerated in JSON text but they are not part of ")
942 wxLogTrace(storeTraceMask, _T(
"(%s) start comment line=%d col=%d"),
947 wxMemoryBuffer utf8Buff;
953 AddWarning(wxJSONREADER_ALLOW_COMMENTS, warn);
955 utf8Buff.AppendData(
"//", 2);
969 c = (
unsigned char)ch;
970 utf8Buff.AppendByte(c);
975 m_comment = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
976 utf8Buff.GetDataLen());
980 else if (ch ==
'*') {
981 AddWarning(wxJSONREADER_ALLOW_COMMENTS, warn);
983 utf8Buff.AppendData(
"/*", 2);
991 utf8Buff.AppendData(
"*/", 2);
996 c = (
unsigned char)ch;
997 utf8Buff.AppendByte(c);
1002 m_comment = wxString::From8BitData((
const char*)utf8Buff.GetData(),
1003 utf8Buff.GetDataLen());
1005 m_comment = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1006 utf8Buff.GetDataLen());
1011 AddError(_T(
"Strange '/' (did you want to insert a comment?)"));
1016 if (ch ==
'*' &&
PeekChar(is) ==
'/') {
1026 wxLogTrace(traceMask, _T(
"(%s) end comment line=%d col=%d"),
1028 wxLogTrace(storeTraceMask, _T(
"(%s) end comment line=%d col=%d"),
1030 wxLogTrace(storeTraceMask, _T(
"(%s) comment=%s"), __PRETTY_FUNCTION__,
1082 wxMemoryBuffer utf8Buff;
1088 unsigned char c = (
unsigned char)ch;
1095 utf8Buff.AppendByte(
'\t');
1098 utf8Buff.AppendByte(
'\n');
1101 utf8Buff.AppendByte(
'\b');
1104 utf8Buff.AppendByte(
'\r');
1107 utf8Buff.AppendByte(
'\"');
1110 utf8Buff.AppendByte(
'\\');
1113 utf8Buff.AppendByte(
'/');
1116 utf8Buff.AppendByte(
'\f');
1129 AddError(_T(
"Unknow escaped character \'\\%c\'"), ch);
1137 utf8Buff.AppendByte(c);
1145 s = wxString::From8BitData((
const char*)utf8Buff.GetData(),
1146 utf8Buff.GetDataLen());
1153 wxConvUTF8.ToWChar(0,
1155 (
const char*)utf8Buff.GetData(),
1156 utf8Buff.GetDataLen());
1158 if (convLen == wxCONV_FAILED) {
1159 AddError(_T(
"String value: the UTF-8 stream is invalid"));
1160 s.append(_T(
"<UTF-8 stream not valid>"));
1162#if defined(wxJSON_USE_UNICODE)
1164 s = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1165 utf8Buff.GetDataLen());
1170 s = wxString::FromUTF8((
const char*)utf8Buff.GetData(),
1171 utf8Buff.GetDataLen());
1178 _T(
"The string value contains unrepresentable Unicode characters"));
1184 wxLogTrace(traceMask, _T(
"(%s) line=%d col=%d"), __PRETTY_FUNCTION__,
1186 wxLogTrace(traceMask, _T(
"(%s) string read=%s"), __PRETTY_FUNCTION__,
1188 wxLogTrace(traceMask, _T(
"(%s) value=%s"), __PRETTY_FUNCTION__,
1196 wxLogTrace(traceMask, _T(
"(%s) assigning the string to value"),
1197 __PRETTY_FUNCTION__);
1201 _T(
"Multiline strings are not allowed by JSON syntax"));
1202 wxLogTrace(traceMask, _T(
"(%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, _T(
"(%s) line=%d col=%d"), __PRETTY_FUNCTION__,
1256 wxLogTrace(traceMask, _T(
"(%s) token read=%s"), __PRETTY_FUNCTION__,
1261 s.Append((
unsigned char)nextCh, 1);
1267 wxLogTrace(traceMask, _T(
"(%s) EOF on line=%d col=%d"), __PRETTY_FUNCTION__,
1269 wxLogTrace(traceMask, _T(
"(%s) EOF - token read=%s"), __PRETTY_FUNCTION__,
1301 wxLogTrace(traceMask, _T(
"(%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;
1322 if (s == _T(
"null")) {
1324 wxLogTrace(traceMask, _T(
"(%s) value = NULL"), __PRETTY_FUNCTION__);
1326 }
else if (s.CmpNoCase(_T(
"null" )) == 0) {
1327 wxLogTrace(traceMask, _T(
"(%s) value = NULL"), __PRETTY_FUNCTION__);
1329 _T(
"the \'null\' literal must be lowercase" ));
1332 }
else if (s == _T(
"true")) {
1333 wxLogTrace(traceMask, _T(
"(%s) value = TRUE"), __PRETTY_FUNCTION__);
1336 }
else if (s.CmpNoCase(_T(
"true" )) == 0) {
1337 wxLogTrace(traceMask, _T(
"(%s) value = TRUE"), __PRETTY_FUNCTION__);
1339 _T(
"the \'true\' literal must be lowercase" ));
1342 }
else if (s == _T(
"false")) {
1343 wxLogTrace(traceMask, _T(
"(%s) value = FALSE"), __PRETTY_FUNCTION__);
1346 }
else if (s.CmpNoCase(_T(
"false" )) == 0) {
1347 wxLogTrace(traceMask, _T(
"(%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, _T(
"(%s) convert to wxInt64 result=%d"),
1392 __PRETTY_FUNCTION__, r);
1400 wxLogTrace(traceMask, _T(
"(%s) convert to int result=%d"),
1401 __PRETTY_FUNCTION__, r);
1411#if defined(wxJSON_64BIT_INT)
1412 r = Strtoull(s, &ui64);
1413 wxLogTrace(traceMask, _T(
"(%s) convert to wxUint64 result=%d"),
1414 __PRETTY_FUNCTION__, r);
1422 wxLogTrace(traceMask, _T(
"(%s) convert to int result=%d"),
1423 __PRETTY_FUNCTION__, r);
1426 val = (
unsigned int)ul;
1434 wxLogTrace(traceMask, _T(
"(%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, _T(
"(%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, _T(
"(%s) m_comment=%s"), __PRETTY_FUNCTION__,
1564 wxLogTrace(storeTraceMask, _T(
"(%s) m_flags=%d m_commentLine=%d"),
1566 wxLogTrace(storeTraceMask, _T(
"(%s) m_current=%p"), __PRETTY_FUNCTION__,
1568 wxLogTrace(storeTraceMask, _T(
"(%s) m_next=%p"), __PRETTY_FUNCTION__,
m_next);
1569 wxLogTrace(storeTraceMask, _T(
"(%s) m_lastStored=%p"), __PRETTY_FUNCTION__,
1573 if ((
m_flags & wxJSONREADER_STORE_COMMENTS) == 0) {
1581 wxLogTrace(storeTraceMask, _T(
"(%s) m_current->lineNo=%d"),
1584 wxLogTrace(storeTraceMask,
1585 _T(
"(%s) comment added to \'m_current\' INLINE"),
1586 __PRETTY_FUNCTION__);
1593 wxLogTrace(storeTraceMask, _T(
"(%s) m_next->lineNo=%d"),
1596 wxLogTrace(storeTraceMask, _T(
"(%s) comment added to \'m_next\' INLINE"),
1597 __PRETTY_FUNCTION__);
1604 wxLogTrace(storeTraceMask, _T(
"(%s) m_lastStored->lineNo=%d"),
1607 wxLogTrace(storeTraceMask,
1608 _T(
"(%s) comment added to \'m_lastStored\' INLINE"),
1609 __PRETTY_FUNCTION__);
1621 if (
m_flags & wxJSONREADER_COMMENTS_AFTER) {
1625 _T(
"Cannot find a value for storing the comment (flag AFTER)"));
1627 wxLogTrace(storeTraceMask,
1628 _T(
"(%s) comment added to m_current (AFTER)"),
1629 __PRETTY_FUNCTION__);
1633 wxLogTrace(storeTraceMask,
1634 _T(
"(%s) comment added to m_lastStored (AFTER)"),
1635 __PRETTY_FUNCTION__);
1638 wxLogTrace(storeTraceMask,
1639 _T(
"(%s) cannot find a value for storing the AFTER comment"),
1640 __PRETTY_FUNCTION__);
1641 AddError(_T(
"Cannot find a value for storing the comment (flag AFTER)"));
1645 wxLogTrace(storeTraceMask, _T(
"(%s) comment added to m_next (BEFORE)"),
1646 __PRETTY_FUNCTION__);
1650 AddError(_T(
"Cannot find a value for storing the comment (flag BEFORE)"));
1694 for (
int i = 0; i < 8; i++) {
1695 if ((ch & 0x80) == 0) {
1706 }
else if (num == 0) {
1729 const wxMemoryBuffer& utf8Buffer) {
1730 size_t len = utf8Buffer.GetDataLen();
1731 char* buff = (
char*)utf8Buffer.GetData();
1732 char* buffEnd = buff + len;
1737 while (buff < buffEnd) {
1742 for (
int i = 1; i < numBytes; i++) {
1743 if (buff >= buffEnd) {
1754 size_t outLength = wxConvUTF8.ToWChar(dst, 10, temp, numBytes);
1759 len = wxConvLibc.FromWChar(temp, 16, dst, outLength);
1760 if (len == wxCONV_FAILED) {
1763 t.Printf(_T(
"\\u%04X"), (
int)dst[0]);
1766 s.Append(temp[0], 1);
1795 static const wxChar* membuffError =
1796 _T(
"the \'memory buffer\' type contains %d invalid digits" );
1799 _T(
"the \'memory buffer\' type is not valid JSON text" ));
1801 wxMemoryBuffer buff;
1804 unsigned char byte = 0;
1814 unsigned char c1 = (
unsigned char)ch;
1819 unsigned char c2 = (
unsigned char)ch;
1830 }
else if (c2 > 15) {
1833 byte = (c1 * 16) + c2;
1834 buff.AppendByte(
byte);
1840 err.Printf(membuffError, errors);
1849 wxLogTrace(traceMask, _T(
"(%s) assigning the memory buffer to value"),
1850 __PRETTY_FUNCTION__);
1853 wxLogTrace(traceMask, _T(
"(%s) concatenate memory buffer to value"),
1854 __PRETTY_FUNCTION__);
1857 AddError(_T(
"Memory buffer value cannot follow another value"));
1870#if defined(wxJSON_64BIT_INT)
1898bool wxJSONReader::Strtoll(
const wxString& str, wxInt64* i64) {
1901 bool r = DoStrto_ll(str, &ui64, &sign);
1906 if (ui64 > (wxUint64)LLONG_MAX + 1) {
1909 *i64 = (wxInt64)(ui64 * -1);
1915 if (ui64 > LLONG_MAX) {
1918 *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.