smf/smfservermodule/util/qjson/src/json_scanner.cpp
changeset 7 be09cf1f39dd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smf/smfservermodule/util/qjson/src/json_scanner.cpp	Tue May 18 17:37:12 2010 +0530
@@ -0,0 +1,329 @@
+/* This file is part of QJson
+ *
+ * Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "qjson_debug.h"
+#include "json_scanner.h"
+#include "json_parser.hh"
+
+#include <ctype.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QRegExp>
+
+#include <cassert>
+
+bool ishexnstring(const QString& string) {
+  for (int i = 0; i < string.length(); i++) {
+    if (isxdigit(string[i] == 0))
+      return false;
+  }
+  return true;
+}
+
+JSonScanner::JSonScanner(QIODevice* io)
+  : m_io (io)
+{
+  m_quotmarkClosed = true;
+  m_quotmarkCount = 0;
+}
+
+static QString unescape( const QByteArray& ba, bool* ok ) {
+  assert( ok );
+  *ok = false;
+  QString res;
+  QByteArray seg;
+  bool bs = false;
+  for ( int i = 0, size = ba.size(); i < size; ++i ) {
+    const char ch = ba[i];
+    if ( !bs ) {
+      if ( ch == '\\' )
+        bs = true;
+      else
+        seg += ch;
+    } else {
+      bs = false;
+      switch ( ch ) {
+        case 'b':
+          seg += '\b';
+          break;
+        case 'f':
+          seg += '\f';
+          break;
+        case 'n':
+          seg += '\n';
+          break;
+        case 'r':
+          seg += '\r';
+          break;
+        case 't':
+          seg += '\t';
+          break;
+        case 'u':
+        {
+          res += QString::fromUtf8( seg );
+          seg.clear();
+
+          if ( i > size - 5 ) {
+            //error
+            return QString();
+          }
+
+          const QString hex_digit1 = QString::fromUtf8( ba.mid( i + 1, 2 ) );
+          const QString hex_digit2 = QString::fromUtf8( ba.mid( i + 3, 2 ) );
+          i += 4;
+
+          if ( !ishexnstring( hex_digit1 ) || !ishexnstring( hex_digit2 ) ) {
+            qCritical() << "Not an hex string:" << hex_digit1 << hex_digit2;
+            return QString();
+          }
+          bool hexOk;
+          const ushort hex_code1 = hex_digit1.toShort( &hexOk, 16 );
+          if (!hexOk) {
+            qCritical() << "error converting hex value to short:" << hex_digit1;
+            return QString();
+          }
+          const ushort hex_code2 = hex_digit2.toShort( &hexOk, 16 );
+          if (!hexOk) {
+            qCritical() << "error converting hex value to short:" << hex_digit2;
+            return QString();
+          }
+
+          res += QChar(hex_code2, hex_code1);
+          break;
+        }
+        case '\\':
+          seg  += '\\';
+          break;
+        default:
+          seg += ch;
+          break;
+      }
+    }
+  }
+  res += QString::fromUtf8( seg );
+  *ok = true;
+  return res;
+}
+
+int JSonScanner::yylex(YYSTYPE* yylval, yy::location *yylloc)
+{
+  char ch;
+  
+  if (!m_io->isOpen()) {
+    qCritical() << "JSonScanner::yylex - io device is not open";
+    return -1;
+  }
+
+  yylloc->step();
+
+  do {
+    bool ret;
+    if (m_io->atEnd()) {
+      qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::END";
+      return yy::json_parser::token::END;
+    }
+    else
+      ret = m_io->getChar(&ch);
+
+    if (!ret) {
+      qCritical() << "JSonScanner::yylex - error reading from io device";
+      return -1;
+    }
+
+    qjsonDebug() << "JSonScanner::yylex - got |" << ch << "|";
+    
+    yylloc->columns();
+    
+    if (ch == '\n' || ch == '\r')
+      yylloc->lines();
+      
+  } while (m_quotmarkClosed && (isspace(ch) != 0));
+
+  if (m_quotmarkClosed && ((ch == 't') || (ch == 'T')
+      || (ch == 'n') || (ch == 'N'))) {
+    // check true & null value
+    const QByteArray buf = m_io->peek(3).toLower();
+
+    if (buf.length() == 3) {
+      if (buf == "rue") {
+        m_io->read (3);
+        yylloc->columns(3);
+        qjsonDebug() << "JSonScanner::yylex - TRUE_VAL";
+        return yy::json_parser::token::TRUE_VAL;
+      }
+      else if (buf == "ull") {
+        m_io->read (3);
+        yylloc->columns(3);
+        qjsonDebug() << "JSonScanner::yylex - NULL_VAL";
+        return yy::json_parser::token::NULL_VAL;
+      }
+    }
+  }
+  else if (m_quotmarkClosed && ((ch == 'f') || (ch == 'F'))) {
+    // check false value
+    const QByteArray buf = m_io->peek(4).toLower();
+    if (buf.length() == 4) {
+      if (buf == "alse") {
+        m_io->read (4);
+        yylloc->columns(4);
+        qjsonDebug() << "JSonScanner::yylex - FALSE_VAL";
+        return yy::json_parser::token::FALSE_VAL;
+      }
+    }
+  }
+  else if (m_quotmarkClosed && ((ch == 'e') || (ch == 'E'))) {
+    QByteArray ret(1, ch);
+    const QByteArray buf = m_io->peek(1);
+    if (!buf.isEmpty()) {
+      if ((buf[0] == '+' ) || (buf[0] == '-' )) {
+        ret += m_io->read (1);  
+        yylloc->columns();
+      }
+    }
+    *yylval = QVariant(QString::fromUtf8(ret));
+    return yy::json_parser::token::E;
+  }
+  
+  if (ch != '"' && !m_quotmarkClosed) {
+    // we're inside a " " block
+    QByteArray raw;
+    raw += ch;
+    char prevCh = ch;
+    bool escape_on = (ch == '\\') ? true : false;
+
+    while ( true ) {
+      char nextCh;
+      qint64 ret = m_io->peek(&nextCh, 1);
+      if (ret != 1) {
+        if (m_io->atEnd())
+          return yy::json_parser::token::END;
+        else
+          return -1;
+      } else if ( !escape_on && nextCh == '\"' ) {
+        bool ok;
+        const QString str = unescape( raw, &ok );
+        *yylval = ok ? str : QString();
+        return ok ? yy::json_parser::token::STRING : -1;
+      }
+#if 0
+      if ( prevCh == '\\' && nextCh != '"' && nextCh != '\\' && nextCh != '/' &&
+           nextCh != 'b' && nextCh != 'f' && nextCh != 'n' &&
+           nextCh != 'r' && nextCh != 't' && nextCh != 'u') {
+        qjsonDebug() << "Just read" << nextCh;
+        qjsonDebug() << "JSonScanner::yylex - error decoding escaped sequence";
+        return -1;
+       }
+#endif
+      m_io->read(1); // consume
+      raw += nextCh;
+      prevCh = nextCh;
+      if (escape_on)
+        escape_on = false;
+      else
+        escape_on = (prevCh == '\\') ? true : false;
+#if 0
+      if (nextCh == '\\') {
+        char buf;
+        if (m_io->getChar (&buf)) {
+          yylloc->columns();
+          if (((buf != '"') && (buf != '\\') && (buf != '/') &&
+              (buf != 'b') && (buf != 'f') && (buf != 'n') &&
+              (buf != 'r') && (buf != 't') && (buf != 'u'))) {
+                qjsonDebug() << "Just read" << buf;
+                qjsonDebug() << "JSonScanner::yylex - error decoding escaped sequence";
+                return -1;
+          }
+        } else {
+          qCritical() << "JSonScanner::yylex - error decoding escaped sequence : io error";
+          return -1;
+        }
+      }
+#endif
+    }
+  }
+  else if (isdigit(ch) != 0 && m_quotmarkClosed) {
+    *yylval = QVariant(QString::fromLatin1(QByteArray(&ch,1)));
+    qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::DIGIT";
+    return yy::json_parser::token::DIGIT;
+  }
+  else if (isalnum(ch) != 0) {
+    *yylval = QVariant(QString(QChar::fromLatin1(ch)));
+    qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::WORD ("
+             << ch << ")";
+    return yy::json_parser::token::STRING;
+  }
+  else if (ch == ':') {
+    // set yylval
+    qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::COLON";
+    return yy::json_parser::token::COLON;
+  }
+  else if (ch == '"') {
+    // yy::json_parser::token::QUOTMARK (")
+
+    // set yylval
+    m_quotmarkCount++;
+    if (m_quotmarkCount %2 == 0) {
+      m_quotmarkClosed = true;
+      m_quotmarkCount = 0;
+      qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::QUOTMARKCLOSE";
+      return yy::json_parser::token::QUOTMARKCLOSE;
+    }
+    else {
+      m_quotmarkClosed = false;
+      qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::QUOTMARKOPEN";
+      return yy::json_parser::token::QUOTMARKOPEN;
+    }
+  }
+  else if (ch == ',') {
+    qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::COMMA";
+    return yy::json_parser::token::COMMA;
+  }
+  else if (ch == '.') {
+    qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::DOT";
+    return yy::json_parser::token::DOT;
+  }
+  else if (ch == '-') {
+    qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::MINUS";
+    return yy::json_parser::token::MINUS;
+  }
+  else if (ch == '[') {
+    qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::SQUARE_BRACKET_OPEN";
+    return yy::json_parser::token::SQUARE_BRACKET_OPEN;
+  }
+  else if (ch == ']') {
+    qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::SQUARE_BRACKET_CLOSE";
+    return yy::json_parser::token::SQUARE_BRACKET_CLOSE;
+  }
+  else if (ch == '{') {
+    qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::CURLY_BRACKET_OPEN";
+    return yy::json_parser::token::CURLY_BRACKET_OPEN;
+  }
+  else if (ch == '}') {
+    qjsonDebug() << "JSonScanner::yylex - yy::json_parser::token::CURLY_BRACKET_CLOSE";
+    return yy::json_parser::token::CURLY_BRACKET_CLOSE;
+  }
+
+  //unknown char!
+  //TODO yyerror?
+  qCritical() << "JSonScanner::yylex - unknown char, returning -1";
+  return -1;
+}
+
+