1 /* This file is part of QJson
3 * Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
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)
43 m_quotmarkClosed = true;
47 static QString unescape( const QByteArray& ba, bool* ok ) {
53 for ( int i = 0, size = ba.size(); i < size; ++i ) {
54 const char ch = ba[i];
80 res += QString::fromUtf8( seg );
88 const QString hex_digit1 = QString::fromUtf8( ba.mid( i + 1, 2 ) );
89 const QString hex_digit2 = QString::fromUtf8( ba.mid( i + 3, 2 ) );
92 if ( !ishexnstring( hex_digit1 ) || !ishexnstring( hex_digit2 ) ) {
93 qCritical() << "Not an hex string:" << hex_digit1 << hex_digit2;
97 const ushort hex_code1 = hex_digit1.toShort( &hexOk, 16 );
99 qCritical() << "error converting hex value to short:" << hex_digit1;
102 const ushort hex_code2 = hex_digit2.toShort( &hexOk, 16 );
104 qCritical() << "error converting hex value to short:" << hex_digit2;
108 res += QChar(hex_code2, hex_code1);
120 res += QString::fromUtf8( seg );
125 int JSonScanner::yylex(YYSTYPE* yylval, yy::location *yylloc)
129 if (!m_io->isOpen()) {
130 qCritical() << "JSonScanner::yylex - io device is not open";
139 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::END";
140 return yy::json_parser::token::END;
143 ret = m_io->getChar(&ch);
146 qCritical() << "JSonScanner::yylex - error reading from io device";
150 qjsonDebug() << "JSonScanner::yylex - got |" << ch << "|";
154 if (ch == '\n' || ch == '\r')
157 } while (m_quotmarkClosed && (isspace(ch) != 0));
159 if (m_quotmarkClosed && ((ch == 't') || (ch == 'T')
160 || (ch == 'n') || (ch == 'N'))) {
161 // check true & null value
162 const QByteArray buf = m_io->peek(3).toLower();
164 if (buf.length() == 3) {
168 qjsonDebug() << "JSonScanner::yylex - TRUE_VAL";
169 return yy::json_parser::token::TRUE_VAL;
171 else if (buf == "ull") {
174 qjsonDebug() << "JSonScanner::yylex - NULL_VAL";
175 return yy::json_parser::token::NULL_VAL;
179 else if (m_quotmarkClosed && ((ch == 'f') || (ch == 'F'))) {
181 const QByteArray buf = m_io->peek(4).toLower();
182 if (buf.length() == 4) {
186 qjsonDebug() << "JSonScanner::yylex - FALSE_VAL";
187 return yy::json_parser::token::FALSE_VAL;
191 else if (m_quotmarkClosed && ((ch == 'e') || (ch == 'E'))) {
192 QByteArray ret(1, ch);
193 const QByteArray buf = m_io->peek(1);
194 if (!buf.isEmpty()) {
195 if ((buf[0] == '+' ) || (buf[0] == '-' )) {
196 ret += m_io->read (1);
200 *yylval = QVariant(QString::fromUtf8(ret));
201 return yy::json_parser::token::E;
204 if (ch != '"' && !m_quotmarkClosed) {
205 // we're inside a " " block
209 bool escape_on = (ch == '\\') ? true : false;
213 qint64 ret = m_io->peek(&nextCh, 1);
216 return yy::json_parser::token::END;
219 } else if ( !escape_on && nextCh == '\"' ) {
221 const QString str = unescape( raw, &ok );
222 *yylval = ok ? str : QString();
223 return ok ? yy::json_parser::token::STRING : -1;
226 if ( prevCh == '\\' && nextCh != '"' && nextCh != '\\' && nextCh != '/' &&
227 nextCh != 'b' && nextCh != 'f' && nextCh != 'n' &&
228 nextCh != 'r' && nextCh != 't' && nextCh != 'u') {
229 qjsonDebug() << "Just read" << nextCh;
230 qjsonDebug() << "JSonScanner::yylex - error decoding escaped sequence";
234 m_io->read(1); // consume
240 escape_on = (prevCh == '\\') ? true : false;
242 if (nextCh == '\\') {
244 if (m_io->getChar (&buf)) {
246 if (((buf != '"') && (buf != '\\') && (buf != '/') &&
247 (buf != 'b') && (buf != 'f') && (buf != 'n') &&
248 (buf != 'r') && (buf != 't') && (buf != 'u'))) {
249 qjsonDebug() << "Just read" << buf;
250 qjsonDebug() << "JSonScanner::yylex - error decoding escaped sequence";
254 qCritical() << "JSonScanner::yylex - error decoding escaped sequence : io error";
261 else if (isdigit(ch) != 0 && m_quotmarkClosed) {
262 *yylval = QVariant(QString::fromLatin1(QByteArray(&ch,1)));
263 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::DIGIT";
264 return yy::json_parser::token::DIGIT;
266 else if (isalnum(ch) != 0) {
267 *yylval = QVariant(QString(QChar::fromLatin1(ch)));
268 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::WORD ("
270 return yy::json_parser::token::STRING;
272 else if (ch == ':') {
274 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::COLON";
275 return yy::json_parser::token::COLON;
277 else if (ch == '"') {
278 // yy::json_parser::token::QUOTMARK (")
282 if (m_quotmarkCount %2 == 0) {
283 m_quotmarkClosed = true;
285 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::QUOTMARKCLOSE";
286 return yy::json_parser::token::QUOTMARKCLOSE;
289 m_quotmarkClosed = false;
290 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::QUOTMARKOPEN";
291 return yy::json_parser::token::QUOTMARKOPEN;
294 else if (ch == ',') {
295 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::COMMA";
296 return yy::json_parser::token::COMMA;
298 else if (ch == '.') {
299 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::DOT";
300 return yy::json_parser::token::DOT;
302 else if (ch == '-') {
303 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::MINUS";
304 return yy::json_parser::token::MINUS;
306 else if (ch == '[') {
307 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::SQUARE_BRACKET_OPEN";
308 return yy::json_parser::token::SQUARE_BRACKET_OPEN;
310 else if (ch == ']') {
311 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::SQUARE_BRACKET_CLOSE";
312 return yy::json_parser::token::SQUARE_BRACKET_CLOSE;
314 else if (ch == '{') {
315 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::CURLY_BRACKET_OPEN";
316 return yy::json_parser::token::CURLY_BRACKET_OPEN;
318 else if (ch == '}') {
319 qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::CURLY_BRACKET_CLOSE";
320 return yy::json_parser::token::CURLY_BRACKET_CLOSE;
325 qCritical() << "JSonScanner::yylex - unknown char, returning -1";