defuze.me  Client
jsonparser.cpp
00001 #include "jsonparser.hpp"
00002 #include <QDebug>
00003 
00004 using namespace Network;
00005 
00006 JsonParser::JsonParser()
00007 {
00008 }
00009 
00010 QVariant    JsonParser::parse(const QByteArray& data) const
00011 {
00012     QScriptValue    value;
00013     QScriptEngine   engine;
00014     value = engine.evaluate(QString("(") + QString(data) + ")");
00015 
00016     if (engine.hasUncaughtException())
00017         return QVariant();
00018     return partialParse(value);
00019 }
00020 
00021 
00022 QVariant    JsonParser::partialParse(const QScriptValue& value) const
00023 {
00024     if (value.isArray())
00025     {
00026         QScriptValueIterator    it(value);
00027         QVariantList            list;
00028 
00029         while (it.hasNext())
00030         {
00031             it.next();
00032             if (!it.hasNext() && it.value().isNumber() && it.value().toInteger() == list.size())
00033                 break;
00034             list << partialParse(it.value());
00035         }
00036         return list;
00037     }
00038     if (value.isObject())
00039     {
00040         QScriptValueIterator    it(value);
00041         QVariantMap             map;
00042 
00043         while (it.hasNext())
00044         {
00045             it.next();
00046             map[it.name()] = partialParse(it.value());
00047         }
00048         return map;
00049     }
00050     else
00051     {
00052         return value.toVariant();
00053     }
00054 }
00055 
00056 QByteArray  JsonParser::serialize(const QVariant& data) const
00057 {
00058     return partialSerialize(data, 0);
00059 }
00060 
00061 QByteArray  JsonParser::partialSerialize(const QVariant& value, const short spaces) const
00062 {
00063     QByteArray  out;
00064 
00065     if ( ! value.isValid() ) {
00066         out = "null";
00067     }
00068     else if (value.type() == QVariant::List || value.type() == QVariant::StringList)
00069     {
00070         const QVariantList &list = value.toList();
00071         QList<QByteArray> values;
00072         Q_FOREACH( const QVariant& var, list)
00073         {
00074             values << partialSerialize(var, spaces + 1);
00075         }
00076         out = "[\n" + indent(spaces + 1) + join( values, ",\n" + indent(spaces + 1)) + "\n" + indent(spaces) + "]";
00077     }
00078     else if (value.type() == QVariant::Map)
00079     {
00080         QVariantMap::const_iterator it;
00081 
00082         out += "{\n";
00083         for(it = value.toMap().constBegin(); it != value.toMap().constEnd(); it++)
00084         {
00085             if (it != value.toMap().constBegin())
00086                 out += ",\n";
00087             out += indent(spaces + 1) + sanitizeString(it.key()) + ": " + partialSerialize(it.value(), spaces + 1);
00088         }
00089         out += "\n" + indent(spaces) + "}";
00090     }
00091     else if (value.type() == QVariant::Bool)
00092     {
00093         out = (value.toBool() ? "true" : "false");
00094     }
00095     else if (value.type() == QVariant::String ||
00096              value.type() == QVariant::DateTime ||
00097              value.type() == QVariant::ByteArray)
00098     {
00099         out += sanitizeString(value.toString());
00100     }
00101     else
00102     {
00103         out += value.toString();
00104     }
00105     return out;
00106 }
00107 
00108 QByteArray  JsonParser::indent(const short spaces) const
00109 {
00110     return QByteArray(spaces * 2, ' ');
00111 }
00112 
00113 
00114 QByteArray  JsonParser::join( const QList<QByteArray>& list, const QByteArray& sep ) const
00115 {
00116     QByteArray res;
00117     Q_FOREACH( const QByteArray& i, list )
00118     {
00119         if ( !res.isEmpty() )
00120             res += sep;
00121         res += i;
00122     }
00123     return res;
00124 }
00125 
00126 QString     JsonParser::sanitizeString(const QString& input) const
00127 {
00128     QString str = input;
00129 
00130     str.replace( QLatin1String( "\\" ), QLatin1String( "\\\\" ) );
00131     // escape unicode chars
00132     QString result;
00133     const ushort* unicode = str.utf16();
00134     unsigned int i = 0;
00135     while ( unicode[ i ] ) {
00136         if ( unicode[ i ] < 128 ) {
00137             result.append( QChar( unicode[ i ] ) );
00138         }
00139         else {
00140             QString hexCode = QString::number( unicode[ i ], 16 ).rightJustified( 4, QLatin1Char('0') );
00141             result.append( QLatin1String ("\\u") ).append( hexCode );
00142         }
00143         ++i;
00144     }
00145     str = result;
00146     str.replace( QLatin1String( "\"" ), QLatin1String( "\\\"" ) );
00147     str.replace( QLatin1String( "\b" ), QLatin1String( "\\b" ) );
00148     str.replace( QLatin1String( "\f" ), QLatin1String( "\\f" ) );
00149     str.replace( QLatin1String( "\n" ), QLatin1String( "\\n" ) );
00150     str.replace( QLatin1String( "\r" ), QLatin1String( "\\r" ) );
00151     str.replace( QLatin1String( "\t" ), QLatin1String( "\\t" ) );
00152     return QString( QLatin1String( "\"%1\"" ) ).arg( str );
00153 }
00154 
00155 void        JsonParser::test()
00156 {
00157     JsonParser          p;
00158     QVariant            value;
00159     QByteArray          result;
00160     const QByteArray    json =
00161     "[\n"
00162     "  {\n"
00163     "    \"address\": {\n"
00164     "      \"city\": \"New York\",\n"
00165     "      \"main\": true,\n"
00166     "      \"postalCode\": \"10021\",\n"
00167     "      \"state\": \"NY\",\n"
00168     "      \"streetAddress\": \"21 2nd Street\"\n"
00169     "    },\n"
00170     "    \"age\": 25,\n"
00171     "    \"firstName\": \"John\",\n"
00172     "    \"lastName\": \"Smith\",\n"
00173     "    \"phoneNumber\": [\n"
00174     "      {\n"
00175     "        \"number\": \"212 555-1234\",\n"
00176     "        \"type\": \"home\"\n"
00177     "      },\n"
00178     "      {\n"
00179     "        \"number\": \"646 555-4567\",\n"
00180     "        \"type\": \"fax\"\n"
00181     "      }\n"
00182     "    ]\n"
00183     "  }\n"
00184     "]";
00185 
00186     value = p.parse(json);
00187     //qDebug() << value;
00188     result = p.serialize(value);
00189     //qDebug() << result;
00190     Q_ASSERT_X(result == json, "JsonParser::test", "serialization does not match original");
00191 }