21 #include "qjson_debug.h"
22 #include "json_scanner.h"
23 #include "json_parser.hh"
27 #include <QtCore/QDebug>
28 #include <QtCore/QRegExp>
32 bool ishexnstring(
const QString&
string) {
33 for (
int i = 0; i <
string.length(); i++) {
34 if (isxdigit(
string[i] == 0))
40 JSonScanner::JSonScanner(QIODevice* io)
41 : m_allowSpecialNumbers(false),
44 m_quotmarkClosed =
true;
48 void JSonScanner::allowSpecialNumbers(
bool allow) {
49 m_allowSpecialNumbers = allow;
52 static QString unescape(
const QByteArray& ba,
bool* ok ) {
58 for (
int i = 0, size = ba.size(); i < size; ++i ) {
59 const char ch = ba[i];
85 res += QString::fromUtf8( seg );
93 const QString hex_digit1 = QString::fromUtf8( ba.mid( i + 1, 2 ) );
94 const QString hex_digit2 = QString::fromUtf8( ba.mid( i + 3, 2 ) );
97 if ( !ishexnstring( hex_digit1 ) || !ishexnstring( hex_digit2 ) ) {
98 qCritical() <<
"Not an hex string:" << hex_digit1 << hex_digit2;
102 const ushort hex_code1 = hex_digit1.toShort( &hexOk, 16 );
104 qCritical() <<
"error converting hex value to short:" << hex_digit1;
107 const ushort hex_code2 = hex_digit2.toShort( &hexOk, 16 );
109 qCritical() <<
"error converting hex value to short:" << hex_digit2;
113 res += QChar(hex_code2, hex_code1);
125 res += QString::fromUtf8( seg );
130 int JSonScanner::yylex(YYSTYPE* yylval,
yy::location *yylloc)
134 if (!m_io->isOpen()) {
135 qCritical() <<
"JSonScanner::yylex - io device is not open";
144 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::END";
145 return yy::json_parser::token::END;
148 ret = m_io->getChar(&ch);
151 qCritical() <<
"JSonScanner::yylex - error reading from io device";
155 qjsonDebug() <<
"JSonScanner::yylex - got |" << ch <<
"|";
158 if (ch ==
'\n' || ch ==
'\r')
160 }
while (m_quotmarkClosed && (isspace(ch) != 0));
162 if (m_quotmarkClosed && ((ch ==
't') || (ch ==
'T'))) {
163 const QByteArray buf = m_io->peek(3).toLower();
167 qjsonDebug() <<
"JSonScanner::yylex - TRUE_VAL";
168 return yy::json_parser::token::TRUE_VAL;
171 else if (m_quotmarkClosed && ((ch ==
'n') || (ch ==
'N'))) {
172 const QByteArray buf = m_io->peek(3).toLower();
176 qjsonDebug() <<
"JSonScanner::yylex - NULL_VAL";
177 return yy::json_parser::token::NULL_VAL;
178 }
else if (buf.startsWith(
"an") && m_allowSpecialNumbers) {
181 qjsonDebug() <<
"JSonScanner::yylex - NAN_VAL";
182 return yy::json_parser::token::NAN_VAL;
186 else if (m_quotmarkClosed && ((ch ==
'f') || (ch ==
'F'))) {
188 const QByteArray buf = m_io->peek(4).toLower();
189 if (buf.length() == 4) {
193 qjsonDebug() <<
"JSonScanner::yylex - FALSE_VAL";
194 return yy::json_parser::token::FALSE_VAL;
198 else if (m_quotmarkClosed && ((ch ==
'e') || (ch ==
'E'))) {
199 QByteArray ret(1, ch);
200 const QByteArray buf = m_io->peek(1);
201 if (!buf.isEmpty()) {
202 if ((buf[0] ==
'+' ) || (buf[0] ==
'-' )) {
203 ret += m_io->read (1);
207 *yylval = QVariant(QString::fromUtf8(ret));
208 return yy::json_parser::token::E;
210 else if (m_allowSpecialNumbers && m_quotmarkClosed && ((ch ==
'I') || (ch ==
'i'))) {
211 QByteArray ret(1, ch);
212 const QByteArray buf = m_io->peek(7);
213 if (buf ==
"nfinity") {
216 qjsonDebug() <<
"JSonScanner::yylex - INFINITY_VAL";
217 return yy::json_parser::token::INFINITY_VAL;
221 if (ch !=
'"' && !m_quotmarkClosed) {
226 bool escape_on = (ch ==
'\\') ?
true :
false;
230 qint64 ret = m_io->peek(&nextCh, 1);
233 return yy::json_parser::token::END;
236 }
else if ( !escape_on && nextCh ==
'\"' ) {
238 const QString str = unescape( raw, &ok );
239 *yylval = ok ? str : QString();
240 return ok ? yy::json_parser::token::STRING : -1;
243 if ( prevCh ==
'\\' && nextCh !=
'"' && nextCh !=
'\\' && nextCh !=
'/' &&
244 nextCh !=
'b' && nextCh !=
'f' && nextCh !=
'n' &&
245 nextCh !=
'r' && nextCh !=
't' && nextCh !=
'u') {
246 qjsonDebug() <<
"Just read" << nextCh;
247 qjsonDebug() <<
"JSonScanner::yylex - error decoding escaped sequence";
257 escape_on = (prevCh ==
'\\') ?
true :
false;
259 if (nextCh ==
'\\') {
261 if (m_io->getChar (&buf)) {
263 if (((buf !=
'"') && (buf !=
'\\') && (buf !=
'/') &&
264 (buf !=
'b') && (buf !=
'f') && (buf !=
'n') &&
265 (buf !=
'r') && (buf !=
't') && (buf !=
'u'))) {
266 qjsonDebug() <<
"Just read" << buf;
267 qjsonDebug() <<
"JSonScanner::yylex - error decoding escaped sequence";
271 qCritical() <<
"JSonScanner::yylex - error decoding escaped sequence : io error";
278 else if (isdigit(ch) != 0 && m_quotmarkClosed) {
280 QByteArray numArray = QByteArray::fromRawData( &ch, 1 *
sizeof(
char) );
281 qulonglong number = numArray.toULongLong(&ok);
284 qCritical() <<
"JSonScanner::yylex - error while converting char to ulonglong, returning -1";
290 *yylval = QVariant(number);
291 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::DIGIT";
292 return yy::json_parser::token::DIGIT;
296 qint64 ret = m_io->peek(&nextCh, 1);
297 while (ret == 1 && isdigit(nextCh)) {
300 numArray = QByteArray::fromRawData( &nextCh, 1 *
sizeof(
char) );
301 number = number * 10 + numArray.toULongLong(&ok);
304 qCritical() <<
"JSonScanner::yylex - error while converting char to ulonglong, returning -1";
307 ret = m_io->peek(&nextCh, 1);
310 *yylval = QVariant(number);
311 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::DIGIT";
312 return yy::json_parser::token::DIGIT;
314 else if (isalnum(ch) != 0) {
315 *yylval = QVariant(QString(QChar::fromLatin1(ch)));
316 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::WORD ("
318 return yy::json_parser::token::STRING;
320 else if (ch ==
':') {
322 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::COLON";
323 return yy::json_parser::token::COLON;
325 else if (ch ==
'"') {
330 if (m_quotmarkCount %2 == 0) {
331 m_quotmarkClosed =
true;
333 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::QUOTMARKCLOSE";
334 return yy::json_parser::token::QUOTMARKCLOSE;
337 m_quotmarkClosed =
false;
338 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::QUOTMARKOPEN";
339 return yy::json_parser::token::QUOTMARKOPEN;
342 else if (ch ==
',') {
343 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::COMMA";
344 return yy::json_parser::token::COMMA;
346 else if (ch ==
'.') {
347 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::DOT";
348 return yy::json_parser::token::DOT;
350 else if (ch ==
'-') {
351 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::MINUS";
352 return yy::json_parser::token::MINUS;
354 else if (ch ==
'[') {
355 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::SQUARE_BRACKET_OPEN";
356 return yy::json_parser::token::SQUARE_BRACKET_OPEN;
358 else if (ch ==
']') {
359 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::SQUARE_BRACKET_CLOSE";
360 return yy::json_parser::token::SQUARE_BRACKET_CLOSE;
362 else if (ch ==
'{') {
363 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::CURLY_BRACKET_OPEN";
364 return yy::json_parser::token::CURLY_BRACKET_OPEN;
366 else if (ch ==
'}') {
367 qjsonDebug() <<
"JSonScanner::yylex - yy::json_parser::token::CURLY_BRACKET_CLOSE";
368 return yy::json_parser::token::CURLY_BRACKET_CLOSE;
373 qCritical() <<
"JSonScanner::yylex - unknown char, returning -1";