Converted PriceUpdater from QScriptEngine to Qt-Json. I don't feel comfortable running unchecked JS code from an external source.
This commit is contained in:
parent
50f7560033
commit
25b97d1e56
7 changed files with 964 additions and 25 deletions
|
@ -77,6 +77,7 @@ SET(cockatrice_SOURCES
|
||||||
src/localserverinterface.cpp
|
src/localserverinterface.cpp
|
||||||
src/localclient.cpp
|
src/localclient.cpp
|
||||||
src/priceupdater.cpp
|
src/priceupdater.cpp
|
||||||
|
src/qt-json/json.cpp
|
||||||
src/soundengine.cpp
|
src/soundengine.cpp
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp
|
${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp
|
||||||
)
|
)
|
||||||
|
@ -194,7 +195,6 @@ if(APPLE)
|
||||||
set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns)
|
set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns)
|
||||||
ENDIF(APPLE)
|
ENDIF(APPLE)
|
||||||
SET(QT_USE_QTNETWORK TRUE)
|
SET(QT_USE_QTNETWORK TRUE)
|
||||||
SET(QT_USE_QTSCRIPT TRUE)
|
|
||||||
SET(QT_USE_QTMULTIMEDIA TRUE)
|
SET(QT_USE_QTMULTIMEDIA TRUE)
|
||||||
SET(QT_USE_QTXML TRUE)
|
SET(QT_USE_QTXML TRUE)
|
||||||
SET(QT_USE_QTSVG TRUE)
|
SET(QT_USE_QTSVG TRUE)
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
/**
|
/**
|
||||||
* @author Marcio Ribeiro <mmr@b1n.org>
|
* @author Marcio Ribeiro <mmr@b1n.org>, Max-Wilhelm Bruker <brukie@gmx.net>
|
||||||
* @version 1.0
|
* @version 1.1
|
||||||
*/
|
*/
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
|
||||||
#include <QScriptEngine>
|
#include "qt-json/json.h"
|
||||||
#include <QScriptValueIterator>
|
|
||||||
#include "priceupdater.h"
|
#include "priceupdater.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,27 +40,25 @@ void PriceUpdater::updatePrices()
|
||||||
*/
|
*/
|
||||||
void PriceUpdater::downloadFinished()
|
void PriceUpdater::downloadFinished()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||||
QByteArray result = reply->readAll();
|
bool ok;
|
||||||
QScriptValue sc;
|
QVariantMap resultMap = QtJson::Json::parse(QString(reply->readAll()), ok).toMap();
|
||||||
QScriptEngine engine;
|
if (!ok) {
|
||||||
sc = engine.evaluate("value = " + result);
|
reply->deleteLater();
|
||||||
|
deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QMap<QString, float> cardsPrice;
|
QMap<QString, float> cardsPrice;
|
||||||
|
|
||||||
if (sc.property("cards").isArray()) {
|
QListIterator<QVariant> it(resultMap.value("cards").toList());
|
||||||
QScriptValueIterator it(sc.property("cards"));
|
while (it.hasNext()) {
|
||||||
while (it.hasNext()) {
|
QVariantMap map = it.next().toMap();
|
||||||
it.next();
|
QString name = map.value("name").toString().toLower();
|
||||||
QString name = it.value().property("name").toString().toLower();
|
float price = map.value("average").toString().toFloat();
|
||||||
float price = it.value().property("average").toString().toFloat();
|
cardsPrice.insert(name, price);
|
||||||
cardsPrice.insert(name, price);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InnerDecklistNode *listRoot = deck->getRoot();
|
InnerDecklistNode *listRoot = deck->getRoot();
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
for (int i = 0; i < listRoot->size(); i++) {
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||||
|
@ -72,7 +69,7 @@ void PriceUpdater::downloadFinished()
|
||||||
currentCard->setPrice(cardsPrice[currentCard->getName().toLower()]);
|
currentCard->setPrice(cardsPrice[currentCard->getName().toLower()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
deleteLater();
|
deleteLater();
|
||||||
emit finishedUpdate();
|
emit finishedUpdate();
|
||||||
|
|
3
cockatrice/src/qt-json/AUTHORS
Normal file
3
cockatrice/src/qt-json/AUTHORS
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Eeli Reilin <eeli@emicode.fi>
|
||||||
|
Luis Gustavo S. Barreto <gustavosbarreto@gmail.com>
|
||||||
|
Stephen Kockentiedt <Stephen@Kockentiedt.name>
|
27
cockatrice/src/qt-json/LICENSE
Normal file
27
cockatrice/src/qt-json/LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright 2011 Eeli Reilin. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
The views and conclusions contained in the software and documentation
|
||||||
|
are those of the authors and should not be interpreted as representing
|
||||||
|
official policies, either expressed or implied, of Eeli Reilin.
|
||||||
|
|
96
cockatrice/src/qt-json/README
Normal file
96
cockatrice/src/qt-json/README
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
########################################################################
|
||||||
|
1. INTRODUCTION
|
||||||
|
|
||||||
|
The Json class is a simple class for parsing JSON data into a QVariant
|
||||||
|
hierarchies. Now, we can also reverse the process and serialize
|
||||||
|
QVariant hierarchies into valid JSON data.
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
2. HOW TO USE
|
||||||
|
|
||||||
|
The parser is really easy to use. Let's say we have the following
|
||||||
|
QString of JSON data:
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
"encoding" : "UTF-8",
|
||||||
|
"plug-ins" : [
|
||||||
|
"python",
|
||||||
|
"c++",
|
||||||
|
"ruby"
|
||||||
|
],
|
||||||
|
"indent" : {
|
||||||
|
"length" : 3,
|
||||||
|
"use_space" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
We would first call the parse-method:
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
//Say that we're using the QtJson namespace
|
||||||
|
using namespace QtJson;
|
||||||
|
bool ok;
|
||||||
|
//json is a QString containing the JSON data
|
||||||
|
QVariantMap result = Json::parse(json, ok).toMap();
|
||||||
|
|
||||||
|
if(!ok) {
|
||||||
|
qFatal("An error occurred during parsing");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Assuming the parsing process completed without errors, we would then
|
||||||
|
go through the hierarchy:
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
qDebug() << "encoding:" << result["encoding"].toString();
|
||||||
|
qDebug() << "plugins:";
|
||||||
|
|
||||||
|
foreach(QVariant plugin, result["plug-ins"].toList()) {
|
||||||
|
qDebug() << "\t-" << plugin.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap nestedMap = result["indent"].toMap();
|
||||||
|
qDebug() << "length:" << nestedMap["length"].toInt();
|
||||||
|
qDebug() << "use_space:" << nestedMap["use_space"].toBool();
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The previous code would print out the following:
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
encoding: "UTF-8"
|
||||||
|
plugins:
|
||||||
|
- "python"
|
||||||
|
- "c++"
|
||||||
|
- "ruby"
|
||||||
|
length: 3
|
||||||
|
use_space: true
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
To write JSON data from Qt object is as simple as parsing:
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
QVariantMap map;
|
||||||
|
map["name"] = "Name";
|
||||||
|
map["age"] = 22;
|
||||||
|
|
||||||
|
QByteArray data = Json::serialize(map);
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The byte array 'data' contains valid JSON data:
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
name: "Luis Gustavo",
|
||||||
|
age: 22,
|
||||||
|
}
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
4. CONTRIBUTING
|
||||||
|
|
||||||
|
The code is available to download at GitHub. Contribute if you dare!
|
612
cockatrice/src/qt-json/json.cpp
Normal file
612
cockatrice/src/qt-json/json.cpp
Normal file
|
@ -0,0 +1,612 @@
|
||||||
|
/* Copyright 2011 Eeli Reilin. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The views and conclusions contained in the software and documentation
|
||||||
|
* are those of the authors and should not be interpreted as representing
|
||||||
|
* official policies, either expressed or implied, of Eeli Reilin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file json.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace QtJson
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
static QString sanitizeString(QString str)
|
||||||
|
{
|
||||||
|
str.replace(QLatin1String("\\"), QLatin1String("\\\\"));
|
||||||
|
str.replace(QLatin1String("\""), QLatin1String("\\\""));
|
||||||
|
str.replace(QLatin1String("\b"), QLatin1String("\\b"));
|
||||||
|
str.replace(QLatin1String("\f"), QLatin1String("\\f"));
|
||||||
|
str.replace(QLatin1String("\n"), QLatin1String("\\n"));
|
||||||
|
str.replace(QLatin1String("\r"), QLatin1String("\\r"));
|
||||||
|
str.replace(QLatin1String("\t"), QLatin1String("\\t"));
|
||||||
|
return QString(QLatin1String("\"%1\"")).arg(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QByteArray join(const QList<QByteArray> &list, const QByteArray &sep)
|
||||||
|
{
|
||||||
|
QByteArray res;
|
||||||
|
Q_FOREACH(const QByteArray &i, list)
|
||||||
|
{
|
||||||
|
if(!res.isEmpty())
|
||||||
|
{
|
||||||
|
res += sep;
|
||||||
|
}
|
||||||
|
res += i;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse
|
||||||
|
*/
|
||||||
|
QVariant Json::parse(const QString &json)
|
||||||
|
{
|
||||||
|
bool success = true;
|
||||||
|
return Json::parse(json, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse
|
||||||
|
*/
|
||||||
|
QVariant Json::parse(const QString &json, bool &success)
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
|
||||||
|
//Return an empty QVariant if the JSON data is either null or empty
|
||||||
|
if(!json.isNull() || !json.isEmpty())
|
||||||
|
{
|
||||||
|
QString data = json;
|
||||||
|
//We'll start from index 0
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
//Parse the first value
|
||||||
|
QVariant value = Json::parseValue(data, index, success);
|
||||||
|
|
||||||
|
//Return the parsed value
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Return the empty QVariant
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray Json::serialize(const QVariant &data)
|
||||||
|
{
|
||||||
|
bool success = true;
|
||||||
|
return Json::serialize(data, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray Json::serialize(const QVariant &data, bool &success)
|
||||||
|
{
|
||||||
|
QByteArray str;
|
||||||
|
success = true;
|
||||||
|
|
||||||
|
if(!data.isValid()) // invalid or null?
|
||||||
|
{
|
||||||
|
str = "null";
|
||||||
|
}
|
||||||
|
else if((data.type() == QVariant::List) || (data.type() == QVariant::StringList)) // variant is a list?
|
||||||
|
{
|
||||||
|
QList<QByteArray> values;
|
||||||
|
const QVariantList list = data.toList();
|
||||||
|
Q_FOREACH(const QVariant& v, list)
|
||||||
|
{
|
||||||
|
QByteArray serializedValue = serialize(v);
|
||||||
|
if(serializedValue.isNull())
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
values << serializedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = "[ " + join( values, ", " ) + " ]";
|
||||||
|
}
|
||||||
|
else if(data.type() == QVariant::Hash) // variant is a hash?
|
||||||
|
{
|
||||||
|
const QVariantHash vhash = data.toHash();
|
||||||
|
QHashIterator<QString, QVariant> it( vhash );
|
||||||
|
str = "{ ";
|
||||||
|
QList<QByteArray> pairs;
|
||||||
|
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
it.next();
|
||||||
|
QByteArray serializedValue = serialize(it.value());
|
||||||
|
|
||||||
|
if(serializedValue.isNull())
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
str += join(pairs, ", ");
|
||||||
|
str += " }";
|
||||||
|
}
|
||||||
|
else if(data.type() == QVariant::Map) // variant is a map?
|
||||||
|
{
|
||||||
|
const QVariantMap vmap = data.toMap();
|
||||||
|
QMapIterator<QString, QVariant> it( vmap );
|
||||||
|
str = "{ ";
|
||||||
|
QList<QByteArray> pairs;
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
it.next();
|
||||||
|
QByteArray serializedValue = serialize(it.value());
|
||||||
|
if(serializedValue.isNull())
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue;
|
||||||
|
}
|
||||||
|
str += join(pairs, ", ");
|
||||||
|
str += " }";
|
||||||
|
}
|
||||||
|
else if((data.type() == QVariant::String) || (data.type() == QVariant::ByteArray)) // a string or a byte array?
|
||||||
|
{
|
||||||
|
str = sanitizeString(data.toString()).toUtf8();
|
||||||
|
}
|
||||||
|
else if(data.type() == QVariant::Double) // double?
|
||||||
|
{
|
||||||
|
str = QByteArray::number(data.toDouble(), 'g', 20);
|
||||||
|
if(!str.contains(".") && ! str.contains("e"))
|
||||||
|
{
|
||||||
|
str += ".0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (data.type() == QVariant::Bool) // boolean value?
|
||||||
|
{
|
||||||
|
str = data.toBool() ? "true" : "false";
|
||||||
|
}
|
||||||
|
else if (data.type() == QVariant::ULongLong) // large unsigned number?
|
||||||
|
{
|
||||||
|
str = QByteArray::number(data.value<qulonglong>());
|
||||||
|
}
|
||||||
|
else if ( data.canConvert<qlonglong>() ) // any signed number?
|
||||||
|
{
|
||||||
|
str = QByteArray::number(data.value<qlonglong>());
|
||||||
|
}
|
||||||
|
else if (data.canConvert<long>())
|
||||||
|
{
|
||||||
|
str = QString::number(data.value<long>()).toUtf8();
|
||||||
|
}
|
||||||
|
else if (data.canConvert<QString>()) // can value be converted to string?
|
||||||
|
{
|
||||||
|
// this will catch QDate, QDateTime, QUrl, ...
|
||||||
|
str = sanitizeString(data.toString()).toUtf8();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseValue
|
||||||
|
*/
|
||||||
|
QVariant Json::parseValue(const QString &json, int &index, bool &success)
|
||||||
|
{
|
||||||
|
//Determine what kind of data we should parse by
|
||||||
|
//checking out the upcoming token
|
||||||
|
switch(Json::lookAhead(json, index))
|
||||||
|
{
|
||||||
|
case JsonTokenString:
|
||||||
|
return Json::parseString(json, index, success);
|
||||||
|
case JsonTokenNumber:
|
||||||
|
return Json::parseNumber(json, index);
|
||||||
|
case JsonTokenCurlyOpen:
|
||||||
|
return Json::parseObject(json, index, success);
|
||||||
|
case JsonTokenSquaredOpen:
|
||||||
|
return Json::parseArray(json, index, success);
|
||||||
|
case JsonTokenTrue:
|
||||||
|
Json::nextToken(json, index);
|
||||||
|
return QVariant(true);
|
||||||
|
case JsonTokenFalse:
|
||||||
|
Json::nextToken(json, index);
|
||||||
|
return QVariant(false);
|
||||||
|
case JsonTokenNull:
|
||||||
|
Json::nextToken(json, index);
|
||||||
|
return QVariant();
|
||||||
|
case JsonTokenNone:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If there were no tokens, flag the failure and return an empty QVariant
|
||||||
|
success = false;
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseObject
|
||||||
|
*/
|
||||||
|
QVariant Json::parseObject(const QString &json, int &index, bool &success)
|
||||||
|
{
|
||||||
|
QVariantMap map;
|
||||||
|
int token;
|
||||||
|
|
||||||
|
//Get rid of the whitespace and increment index
|
||||||
|
Json::nextToken(json, index);
|
||||||
|
|
||||||
|
//Loop through all of the key/value pairs of the object
|
||||||
|
bool done = false;
|
||||||
|
while(!done)
|
||||||
|
{
|
||||||
|
//Get the upcoming token
|
||||||
|
token = Json::lookAhead(json, index);
|
||||||
|
|
||||||
|
if(token == JsonTokenNone)
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
return QVariantMap();
|
||||||
|
}
|
||||||
|
else if(token == JsonTokenComma)
|
||||||
|
{
|
||||||
|
Json::nextToken(json, index);
|
||||||
|
}
|
||||||
|
else if(token == JsonTokenCurlyClose)
|
||||||
|
{
|
||||||
|
Json::nextToken(json, index);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Parse the key/value pair's name
|
||||||
|
QString name = Json::parseString(json, index, success).toString();
|
||||||
|
|
||||||
|
if(!success)
|
||||||
|
{
|
||||||
|
return QVariantMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the next token
|
||||||
|
token = Json::nextToken(json, index);
|
||||||
|
|
||||||
|
//If the next token is not a colon, flag the failure
|
||||||
|
//return an empty QVariant
|
||||||
|
if(token != JsonTokenColon)
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
return QVariant(QVariantMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Parse the key/value pair's value
|
||||||
|
QVariant value = Json::parseValue(json, index, success);
|
||||||
|
|
||||||
|
if(!success)
|
||||||
|
{
|
||||||
|
return QVariantMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Assign the value to the key in the map
|
||||||
|
map[name] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return the map successfully
|
||||||
|
return QVariant(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseArray
|
||||||
|
*/
|
||||||
|
QVariant Json::parseArray(const QString &json, int &index, bool &success)
|
||||||
|
{
|
||||||
|
QVariantList list;
|
||||||
|
|
||||||
|
Json::nextToken(json, index);
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
while(!done)
|
||||||
|
{
|
||||||
|
int token = Json::lookAhead(json, index);
|
||||||
|
|
||||||
|
if(token == JsonTokenNone)
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
return QVariantList();
|
||||||
|
}
|
||||||
|
else if(token == JsonTokenComma)
|
||||||
|
{
|
||||||
|
Json::nextToken(json, index);
|
||||||
|
}
|
||||||
|
else if(token == JsonTokenSquaredClose)
|
||||||
|
{
|
||||||
|
Json::nextToken(json, index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QVariant value = Json::parseValue(json, index, success);
|
||||||
|
|
||||||
|
if(!success)
|
||||||
|
{
|
||||||
|
return QVariantList();
|
||||||
|
}
|
||||||
|
|
||||||
|
list.push_back(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseString
|
||||||
|
*/
|
||||||
|
QVariant Json::parseString(const QString &json, int &index, bool &success)
|
||||||
|
{
|
||||||
|
QString s;
|
||||||
|
QChar c;
|
||||||
|
|
||||||
|
Json::eatWhitespace(json, index);
|
||||||
|
|
||||||
|
c = json[index++];
|
||||||
|
|
||||||
|
bool complete = false;
|
||||||
|
while(!complete)
|
||||||
|
{
|
||||||
|
if(index == json.size())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = json[index++];
|
||||||
|
|
||||||
|
if(c == '\"')
|
||||||
|
{
|
||||||
|
complete = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(c == '\\')
|
||||||
|
{
|
||||||
|
if(index == json.size())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = json[index++];
|
||||||
|
|
||||||
|
if(c == '\"')
|
||||||
|
{
|
||||||
|
s.append('\"');
|
||||||
|
}
|
||||||
|
else if(c == '\\')
|
||||||
|
{
|
||||||
|
s.append('\\');
|
||||||
|
}
|
||||||
|
else if(c == '/')
|
||||||
|
{
|
||||||
|
s.append('/');
|
||||||
|
}
|
||||||
|
else if(c == 'b')
|
||||||
|
{
|
||||||
|
s.append('\b');
|
||||||
|
}
|
||||||
|
else if(c == 'f')
|
||||||
|
{
|
||||||
|
s.append('\f');
|
||||||
|
}
|
||||||
|
else if(c == 'n')
|
||||||
|
{
|
||||||
|
s.append('\n');
|
||||||
|
}
|
||||||
|
else if(c == 'r')
|
||||||
|
{
|
||||||
|
s.append('\r');
|
||||||
|
}
|
||||||
|
else if(c == 't')
|
||||||
|
{
|
||||||
|
s.append('\t');
|
||||||
|
}
|
||||||
|
else if(c == 'u')
|
||||||
|
{
|
||||||
|
int remainingLength = json.size() - index;
|
||||||
|
|
||||||
|
if(remainingLength >= 4)
|
||||||
|
{
|
||||||
|
QString unicodeStr = json.mid(index, 4);
|
||||||
|
|
||||||
|
int symbol = unicodeStr.toInt(0, 16);
|
||||||
|
|
||||||
|
s.append(QChar(symbol));
|
||||||
|
|
||||||
|
index += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!complete)
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseNumber
|
||||||
|
*/
|
||||||
|
QVariant Json::parseNumber(const QString &json, int &index)
|
||||||
|
{
|
||||||
|
Json::eatWhitespace(json, index);
|
||||||
|
|
||||||
|
int lastIndex = Json::lastIndexOfNumber(json, index);
|
||||||
|
int charLength = (lastIndex - index) + 1;
|
||||||
|
QString numberStr;
|
||||||
|
|
||||||
|
numberStr = json.mid(index, charLength);
|
||||||
|
|
||||||
|
index = lastIndex + 1;
|
||||||
|
|
||||||
|
if (numberStr.contains('.')) {
|
||||||
|
return QVariant(numberStr.toDouble(NULL));
|
||||||
|
} else if (numberStr.startsWith('-')) {
|
||||||
|
return QVariant(numberStr.toLongLong(NULL));
|
||||||
|
} else {
|
||||||
|
return QVariant(numberStr.toULongLong(NULL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lastIndexOfNumber
|
||||||
|
*/
|
||||||
|
int Json::lastIndexOfNumber(const QString &json, int index)
|
||||||
|
{
|
||||||
|
int lastIndex;
|
||||||
|
|
||||||
|
for(lastIndex = index; lastIndex < json.size(); lastIndex++)
|
||||||
|
{
|
||||||
|
if(QString("0123456789+-.eE").indexOf(json[lastIndex]) == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastIndex -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eatWhitespace
|
||||||
|
*/
|
||||||
|
void Json::eatWhitespace(const QString &json, int &index)
|
||||||
|
{
|
||||||
|
for(; index < json.size(); index++)
|
||||||
|
{
|
||||||
|
if(QString(" \t\n\r").indexOf(json[index]) == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lookAhead
|
||||||
|
*/
|
||||||
|
int Json::lookAhead(const QString &json, int index)
|
||||||
|
{
|
||||||
|
int saveIndex = index;
|
||||||
|
return Json::nextToken(json, saveIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nextToken
|
||||||
|
*/
|
||||||
|
int Json::nextToken(const QString &json, int &index)
|
||||||
|
{
|
||||||
|
Json::eatWhitespace(json, index);
|
||||||
|
|
||||||
|
if(index == json.size())
|
||||||
|
{
|
||||||
|
return JsonTokenNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
QChar c = json[index];
|
||||||
|
index++;
|
||||||
|
switch(c.toAscii())
|
||||||
|
{
|
||||||
|
case '{': return JsonTokenCurlyOpen;
|
||||||
|
case '}': return JsonTokenCurlyClose;
|
||||||
|
case '[': return JsonTokenSquaredOpen;
|
||||||
|
case ']': return JsonTokenSquaredClose;
|
||||||
|
case ',': return JsonTokenComma;
|
||||||
|
case '"': return JsonTokenString;
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
case '-': return JsonTokenNumber;
|
||||||
|
case ':': return JsonTokenColon;
|
||||||
|
}
|
||||||
|
|
||||||
|
index--;
|
||||||
|
|
||||||
|
int remainingLength = json.size() - index;
|
||||||
|
|
||||||
|
//True
|
||||||
|
if(remainingLength >= 4)
|
||||||
|
{
|
||||||
|
if (json[index] == 't' && json[index + 1] == 'r' &&
|
||||||
|
json[index + 2] == 'u' && json[index + 3] == 'e')
|
||||||
|
{
|
||||||
|
index += 4;
|
||||||
|
return JsonTokenTrue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//False
|
||||||
|
if (remainingLength >= 5)
|
||||||
|
{
|
||||||
|
if (json[index] == 'f' && json[index + 1] == 'a' &&
|
||||||
|
json[index + 2] == 'l' && json[index + 3] == 's' &&
|
||||||
|
json[index + 4] == 'e')
|
||||||
|
{
|
||||||
|
index += 5;
|
||||||
|
return JsonTokenFalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Null
|
||||||
|
if (remainingLength >= 4)
|
||||||
|
{
|
||||||
|
if (json[index] == 'n' && json[index + 1] == 'u' &&
|
||||||
|
json[index + 2] == 'l' && json[index + 3] == 'l')
|
||||||
|
{
|
||||||
|
index += 4;
|
||||||
|
return JsonTokenNull;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonTokenNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} //end namespace
|
204
cockatrice/src/qt-json/json.h
Normal file
204
cockatrice/src/qt-json/json.h
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
/* Copyright 2011 Eeli Reilin. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The views and conclusions contained in the software and documentation
|
||||||
|
* are those of the authors and should not be interpreted as representing
|
||||||
|
* official policies, either expressed or implied, of Eeli Reilin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file json.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JSON_H
|
||||||
|
#define JSON_H
|
||||||
|
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace QtJson
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \enum JsonToken
|
||||||
|
*/
|
||||||
|
enum JsonToken
|
||||||
|
{
|
||||||
|
JsonTokenNone = 0,
|
||||||
|
JsonTokenCurlyOpen = 1,
|
||||||
|
JsonTokenCurlyClose = 2,
|
||||||
|
JsonTokenSquaredOpen = 3,
|
||||||
|
JsonTokenSquaredClose = 4,
|
||||||
|
JsonTokenColon = 5,
|
||||||
|
JsonTokenComma = 6,
|
||||||
|
JsonTokenString = 7,
|
||||||
|
JsonTokenNumber = 8,
|
||||||
|
JsonTokenTrue = 9,
|
||||||
|
JsonTokenFalse = 10,
|
||||||
|
JsonTokenNull = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class Json
|
||||||
|
* \brief A JSON data parser
|
||||||
|
*
|
||||||
|
* Json parses a JSON data into a QVariant hierarchy.
|
||||||
|
*/
|
||||||
|
class Json
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Parse a JSON string
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
*/
|
||||||
|
static QVariant parse(const QString &json);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a JSON string
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param success The success of the parsing
|
||||||
|
*/
|
||||||
|
static QVariant parse(const QString &json, bool &success);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method generates a textual JSON representation
|
||||||
|
*
|
||||||
|
* \param data The JSON data generated by the parser.
|
||||||
|
* \param success The success of the serialization
|
||||||
|
*/
|
||||||
|
static QByteArray serialize(const QVariant &data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method generates a textual JSON representation
|
||||||
|
*
|
||||||
|
* \param data The JSON data generated by the parser.
|
||||||
|
* \param success The success of the serialization
|
||||||
|
*
|
||||||
|
* \return QByteArray Textual JSON representation
|
||||||
|
*/
|
||||||
|
static QByteArray serialize(const QVariant &data, bool &success);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Parses a value starting from index
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param index The start index
|
||||||
|
* \param success The success of the parse process
|
||||||
|
*
|
||||||
|
* \return QVariant The parsed value
|
||||||
|
*/
|
||||||
|
static QVariant parseValue(const QString &json, int &index,
|
||||||
|
bool &success);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an object starting from index
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param index The start index
|
||||||
|
* \param success The success of the object parse
|
||||||
|
*
|
||||||
|
* \return QVariant The parsed object map
|
||||||
|
*/
|
||||||
|
static QVariant parseObject(const QString &json, int &index,
|
||||||
|
bool &success);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an array starting from index
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param index The starting index
|
||||||
|
* \param success The success of the array parse
|
||||||
|
*
|
||||||
|
* \return QVariant The parsed variant array
|
||||||
|
*/
|
||||||
|
static QVariant parseArray(const QString &json, int &index,
|
||||||
|
bool &success);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string starting from index
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param index The starting index
|
||||||
|
* \param success The success of the string parse
|
||||||
|
*
|
||||||
|
* \return QVariant The parsed string
|
||||||
|
*/
|
||||||
|
static QVariant parseString(const QString &json, int &index,
|
||||||
|
bool &success);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a number starting from index
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param index The starting index
|
||||||
|
*
|
||||||
|
* \return QVariant The parsed number
|
||||||
|
*/
|
||||||
|
static QVariant parseNumber(const QString &json, int &index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the last index of a number starting from index
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param index The starting index
|
||||||
|
*
|
||||||
|
* \return The last index of the number
|
||||||
|
*/
|
||||||
|
static int lastIndexOfNumber(const QString &json, int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip unwanted whitespace symbols starting from index
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param index The start index
|
||||||
|
*/
|
||||||
|
static void eatWhitespace(const QString &json, int &index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check what token lies ahead
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param index The starting index
|
||||||
|
*
|
||||||
|
* \return int The upcoming token
|
||||||
|
*/
|
||||||
|
static int lookAhead(const QString &json, int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next JSON token
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param index The starting index
|
||||||
|
*
|
||||||
|
* \return int The next JSON token
|
||||||
|
*/
|
||||||
|
static int nextToken(const QString &json, int &index);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} //end namespace
|
||||||
|
|
||||||
|
#endif //JSON_H
|
Loading…
Reference in a new issue