Add JSON class
This commit is contained in:
parent
a0d7f98175
commit
488152c37d
@ -76,14 +76,16 @@ HEADERS += \
|
|||||||
src/ATBAPP/ATBHealthEvent.h \
|
src/ATBAPP/ATBHealthEvent.h \
|
||||||
src/ATBAPP/ATBMachineEvent.h \
|
src/ATBAPP/ATBMachineEvent.h \
|
||||||
src/ATBAPP/ATBDeviceControllerPlugin.h \
|
src/ATBAPP/ATBDeviceControllerPlugin.h \
|
||||||
src/ATBAPP/Utils.h
|
src/ATBAPP/Utils.h \
|
||||||
|
src/ATBAPP/support/JSON.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
src/ATBAPP/ATBHealthEvent.cpp \
|
src/ATBAPP/ATBHealthEvent.cpp \
|
||||||
src/ATBAPP/ATBMachineEvent.cpp \
|
src/ATBAPP/ATBMachineEvent.cpp \
|
||||||
src/ATBAPP/ATBDeviceControllerPlugin.cpp \
|
src/ATBAPP/ATBDeviceControllerPlugin.cpp \
|
||||||
src/ATBAPP/DeviceControllerDiag.cpp \
|
src/ATBAPP/DeviceControllerDiag.cpp \
|
||||||
src/ATBAPP/Utils.cpp
|
src/ATBAPP/Utils.cpp \
|
||||||
|
src/ATBAPP/support/JSON.cpp
|
||||||
|
|
||||||
DISTFILES += \
|
DISTFILES += \
|
||||||
generate-version.sh
|
generate-version.sh
|
||||||
|
735
src/ATBAPP/support/JSON.cpp
Normal file
735
src/ATBAPP/support/JSON.cpp
Normal file
@ -0,0 +1,735 @@
|
|||||||
|
#include <QDateTime>
|
||||||
|
#include <QStringList>
|
||||||
|
#include "JSON.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace JSON {
|
||||||
|
static QString dateFormat, dateTimeFormat;
|
||||||
|
static bool prettySerialize = false;
|
||||||
|
|
||||||
|
static QString sanitizeString(QString str);
|
||||||
|
static QByteArray join(const QList<QByteArray> &list, const QByteArray &sep);
|
||||||
|
static QVariant parseValue(const QString &json, int &index, bool &success);
|
||||||
|
static QVariant parseObject(const QString &json, int &index, bool &success);
|
||||||
|
static QVariant parseArray(const QString &json, int &index, bool &success);
|
||||||
|
static QVariant parseString(const QString &json, int &index, bool &success);
|
||||||
|
static QVariant parseNumber(const QString &json, int &index);
|
||||||
|
static int lastIndexOfNumber(const QString &json, int index);
|
||||||
|
static void eatWhitespace(const QString &json, int &index);
|
||||||
|
static int lookAhead(const QString &json, int index);
|
||||||
|
static int nextToken(const QString &json, int &index);
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
QByteArray serializeMap(const T &map, bool &success, int _level = 0) {
|
||||||
|
QByteArray newline;
|
||||||
|
QByteArray tabs;
|
||||||
|
QByteArray tabsFields;
|
||||||
|
if (prettySerialize && !map.isEmpty()) {
|
||||||
|
newline = "\n";
|
||||||
|
for (int l=1; l<_level; l++) {
|
||||||
|
tabs += " ";
|
||||||
|
}
|
||||||
|
tabsFields = tabs + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray str = "{" + newline;
|
||||||
|
QList<QByteArray> pairs;
|
||||||
|
for (typename T::const_iterator it = map.begin(), itend = map.end(); it != itend; ++it) {
|
||||||
|
bool otherSuccess = true;
|
||||||
|
QByteArray serializedValue = serialize(it.value(), otherSuccess, _level);
|
||||||
|
if (serializedValue.isNull()) {
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pairs << tabsFields + sanitizeString(it.key()).toUtf8() + ":" + (prettySerialize ? " " : "") + serializedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
str += join(pairs, "," + newline) + newline;
|
||||||
|
str += tabs + "}";
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void insert(QVariant &v, const QString &key, const QVariant &value);
|
||||||
|
void append(QVariant &v, const QVariant &value);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void cloneMap(QVariant &json, const T &map) {
|
||||||
|
for (typename T::const_iterator it = map.begin(), itend = map.end(); it != itend; ++it) {
|
||||||
|
insert(json, it.key(), (*it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void cloneList(QVariant &json, const T &list) {
|
||||||
|
for (typename T::const_iterator it = list.begin(), itend = list.end(); it != itend; ++it) {
|
||||||
|
append(json, (*it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse
|
||||||
|
*/
|
||||||
|
QVariant parse(const QString &json) {
|
||||||
|
bool success = true;
|
||||||
|
return parse(json, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse
|
||||||
|
*/
|
||||||
|
QVariant 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 = parseValue(data, index, success);
|
||||||
|
|
||||||
|
// Return the parsed value
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
// Return the empty QVariant
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clone
|
||||||
|
*/
|
||||||
|
QVariant clone(const QVariant &data) {
|
||||||
|
QVariant v;
|
||||||
|
|
||||||
|
if (data.type() == QVariant::Map) {
|
||||||
|
cloneMap(v, data.toMap());
|
||||||
|
} else if (data.type() == QVariant::Hash) {
|
||||||
|
cloneMap(v, data.toHash());
|
||||||
|
} else if (data.type() == QVariant::List) {
|
||||||
|
cloneList(v, data.toList());
|
||||||
|
} else if (data.type() == QVariant::StringList) {
|
||||||
|
cloneList(v, data.toStringList());
|
||||||
|
} else {
|
||||||
|
v = QVariant(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insert value (map case)
|
||||||
|
*/
|
||||||
|
void insert(QVariant &v, const QString &key, const QVariant &value) {
|
||||||
|
if (!v.canConvert<QVariantMap>()) v = QVariantMap();
|
||||||
|
QVariantMap *p = (QVariantMap *)v.data();
|
||||||
|
p->insert(key, clone(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* append value (list case)
|
||||||
|
*/
|
||||||
|
void append(QVariant &v, const QVariant &value) {
|
||||||
|
if (!v.canConvert<QVariantList>()) v = QVariantList();
|
||||||
|
QVariantList *p = (QVariantList *)v.data();
|
||||||
|
p->append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray serialize(const QVariant &data) {
|
||||||
|
bool success = true;
|
||||||
|
return serialize(data, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QByteArray serialize(const QVariant &data, bool &success, int _level /*= 0*/) {
|
||||||
|
QByteArray newline;
|
||||||
|
QByteArray tabs;
|
||||||
|
QByteArray tabsFields;
|
||||||
|
if (prettySerialize) {
|
||||||
|
newline = "\n";
|
||||||
|
for (int l=0; l<_level; l++) {
|
||||||
|
tabs += " ";
|
||||||
|
}
|
||||||
|
tabsFields = tabs + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
bool otherSuccess = true;
|
||||||
|
QByteArray serializedValue = serialize(v, otherSuccess, _level+1);
|
||||||
|
if (serializedValue.isNull()) {
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
values << tabsFields + serializedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!values.isEmpty()) {
|
||||||
|
str = "[" + newline + join( values, "," + newline ) + newline + tabs + "]";
|
||||||
|
} else {
|
||||||
|
str = "[]";
|
||||||
|
}
|
||||||
|
} else if (data.type() == QVariant::Hash) { // variant is a hash?
|
||||||
|
str = serializeMap<>(data.toHash(), success, _level+1);
|
||||||
|
} else if (data.type() == QVariant::Map) { // variant is a map?
|
||||||
|
str = serializeMap<>(data.toMap(), success, _level+1);
|
||||||
|
} 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?
|
||||||
|
double value = data.toDouble(&success);
|
||||||
|
if (success) {
|
||||||
|
str = QByteArray::number(value, 'g');
|
||||||
|
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>()) { //TODO: this code is never executed because all smaller types can be converted to qlonglong
|
||||||
|
str = QString::number(data.value<long>()).toUtf8();
|
||||||
|
} else if (data.type() == QVariant::DateTime) { // datetime value?
|
||||||
|
str = sanitizeString(dateTimeFormat.isEmpty()
|
||||||
|
? data.toDateTime().toString()
|
||||||
|
: data.toDateTime().toString(dateTimeFormat)).toUtf8();
|
||||||
|
} else if (data.type() == QVariant::Date) { // date value?
|
||||||
|
str = sanitizeString(dateTimeFormat.isEmpty()
|
||||||
|
? data.toDate().toString()
|
||||||
|
: data.toDate().toString(dateFormat)).toUtf8();
|
||||||
|
} else if (data.canConvert<QString>()) { // can value be converted to string?
|
||||||
|
// this will catch QUrl, ... (all other types which can be converted to string)
|
||||||
|
str = sanitizeString(data.toString()).toUtf8();
|
||||||
|
} else {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString serializeStr(const QVariant &data) {
|
||||||
|
return QString::fromUtf8(serialize(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString serializeStr(const QVariant &data, bool &success) {
|
||||||
|
return QString::fromUtf8(serialize(data, success));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseValue
|
||||||
|
*/
|
||||||
|
static QVariant parseValue(const QString &json, int &index, bool &success) {
|
||||||
|
// Determine what kind of data we should parse by
|
||||||
|
// checking out the upcoming token
|
||||||
|
switch(lookAhead(json, index)) {
|
||||||
|
case JsonTokenString:
|
||||||
|
return parseString(json, index, success);
|
||||||
|
case JsonTokenNumber:
|
||||||
|
return parseNumber(json, index);
|
||||||
|
case JsonTokenCurlyOpen:
|
||||||
|
return parseObject(json, index, success);
|
||||||
|
case JsonTokenSquaredOpen:
|
||||||
|
return parseArray(json, index, success);
|
||||||
|
case JsonTokenTrue:
|
||||||
|
nextToken(json, index);
|
||||||
|
return QVariant(true);
|
||||||
|
case JsonTokenFalse:
|
||||||
|
nextToken(json, index);
|
||||||
|
return QVariant(false);
|
||||||
|
case JsonTokenNull:
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
static QVariant parseObject(const QString &json, int &index, bool &success) {
|
||||||
|
QVariantMap map;
|
||||||
|
int token;
|
||||||
|
|
||||||
|
// Get rid of the whitespace and increment index
|
||||||
|
nextToken(json, index);
|
||||||
|
|
||||||
|
// Loop through all of the key/value pairs of the object
|
||||||
|
bool done = false;
|
||||||
|
while (!done) {
|
||||||
|
// Get the upcoming token
|
||||||
|
token = lookAhead(json, index);
|
||||||
|
|
||||||
|
if (token == JsonTokenNone) {
|
||||||
|
success = false;
|
||||||
|
return QVariantMap();
|
||||||
|
} else if (token == JsonTokenComma) {
|
||||||
|
nextToken(json, index);
|
||||||
|
} else if (token == JsonTokenCurlyClose) {
|
||||||
|
nextToken(json, index);
|
||||||
|
return map;
|
||||||
|
} else {
|
||||||
|
// Parse the key/value pair's name
|
||||||
|
QString name = parseString(json, index, success).toString();
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return QVariantMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next token
|
||||||
|
token = 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 = 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
|
||||||
|
*/
|
||||||
|
static QVariant parseArray(const QString &json, int &index, bool &success) {
|
||||||
|
QVariantList list;
|
||||||
|
|
||||||
|
nextToken(json, index);
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
while(!done) {
|
||||||
|
int token = lookAhead(json, index);
|
||||||
|
|
||||||
|
if (token == JsonTokenNone) {
|
||||||
|
success = false;
|
||||||
|
return QVariantList();
|
||||||
|
} else if (token == JsonTokenComma) {
|
||||||
|
nextToken(json, index);
|
||||||
|
} else if (token == JsonTokenSquaredClose) {
|
||||||
|
nextToken(json, index);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
QVariant value = parseValue(json, index, success);
|
||||||
|
if (!success) {
|
||||||
|
return QVariantList();
|
||||||
|
}
|
||||||
|
list.push_back(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseString
|
||||||
|
*/
|
||||||
|
static QVariant parseString(const QString &json, int &index, bool &success) {
|
||||||
|
QString s;
|
||||||
|
QChar c;
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
static QVariant parseNumber(const QString &json, int &index) {
|
||||||
|
eatWhitespace(json, index);
|
||||||
|
|
||||||
|
int lastIndex = lastIndexOfNumber(json, index);
|
||||||
|
int charLength = (lastIndex - index) + 1;
|
||||||
|
QString numberStr;
|
||||||
|
|
||||||
|
numberStr = json.mid(index, charLength);
|
||||||
|
|
||||||
|
index = lastIndex + 1;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
if (numberStr.contains('.')) {
|
||||||
|
return QVariant(numberStr.toDouble(NULL));
|
||||||
|
} else if (numberStr.startsWith('-')) {
|
||||||
|
int i = numberStr.toInt(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
qlonglong ll = numberStr.toLongLong(&ok);
|
||||||
|
return ok ? ll : QVariant(numberStr);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
} else {
|
||||||
|
uint u = numberStr.toUInt(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
qulonglong ull = numberStr.toULongLong(&ok);
|
||||||
|
return ok ? ull : QVariant(numberStr);
|
||||||
|
}
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lastIndexOfNumber
|
||||||
|
*/
|
||||||
|
static int 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
|
||||||
|
*/
|
||||||
|
static void eatWhitespace(const QString &json, int &index) {
|
||||||
|
for(; index < json.size(); index++) {
|
||||||
|
if (QString(" \t\n\r").indexOf(json[index]) == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lookAhead
|
||||||
|
*/
|
||||||
|
static int lookAhead(const QString &json, int index) {
|
||||||
|
int saveIndex = index;
|
||||||
|
return nextToken(json, saveIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nextToken
|
||||||
|
*/
|
||||||
|
static int nextToken(const QString &json, int &index) {
|
||||||
|
eatWhitespace(json, index);
|
||||||
|
|
||||||
|
if (index == json.size()) {
|
||||||
|
return JsonTokenNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
QChar c = json[index];
|
||||||
|
index++;
|
||||||
|
switch(c.toLatin1()) {
|
||||||
|
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--; // ^ WTF?
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDateTimeFormat(const QString &format) {
|
||||||
|
dateTimeFormat = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDateFormat(const QString &format) {
|
||||||
|
dateFormat = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getDateTimeFormat() {
|
||||||
|
return dateTimeFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getDateFormat() {
|
||||||
|
return dateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPrettySerialize(bool enabled) {
|
||||||
|
prettySerialize = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPrettySerialize() {
|
||||||
|
return prettySerialize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QQueue<BuilderJsonObject *> BuilderJsonObject::created_list;
|
||||||
|
|
||||||
|
BuilderJsonObject::BuilderJsonObject() {
|
||||||
|
// clean objects previous "created"
|
||||||
|
while (!BuilderJsonObject::created_list.isEmpty()) {
|
||||||
|
delete BuilderJsonObject::created_list.dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonObject::BuilderJsonObject(JsonObject &json) {
|
||||||
|
BuilderJsonObject();
|
||||||
|
|
||||||
|
obj = json;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonObject *BuilderJsonObject::set(const QString &key, const QVariant &value) {
|
||||||
|
obj[key] = value;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonObject *BuilderJsonObject::set(const QString &key, BuilderJsonObject *builder) {
|
||||||
|
return set(key, builder->create());
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonObject *BuilderJsonObject::set(const QString &key, BuilderJsonArray *builder) {
|
||||||
|
return set(key, builder->create());
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject BuilderJsonObject::create() {
|
||||||
|
BuilderJsonObject::created_list.enqueue(this);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QQueue<BuilderJsonArray *> BuilderJsonArray::created_list;
|
||||||
|
|
||||||
|
BuilderJsonArray::BuilderJsonArray() {
|
||||||
|
// clean objects previous "created"
|
||||||
|
while (!BuilderJsonArray::created_list.isEmpty()) {
|
||||||
|
delete BuilderJsonArray::created_list.dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonArray::BuilderJsonArray(JsonArray &json) {
|
||||||
|
BuilderJsonArray();
|
||||||
|
|
||||||
|
array = json;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonArray *BuilderJsonArray::add(const QVariant &element) {
|
||||||
|
array.append(element);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonArray *BuilderJsonArray::add(BuilderJsonObject *builder) {
|
||||||
|
return add(builder->create());
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonArray *BuilderJsonArray::add(BuilderJsonArray *builder) {
|
||||||
|
return add(builder->create());
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonArray BuilderJsonArray::create() {
|
||||||
|
BuilderJsonArray::created_list.enqueue(this);
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BuilderJsonObject *objectBuilder() {
|
||||||
|
return new BuilderJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonObject *objectBuilder(JsonObject &json) {
|
||||||
|
return new BuilderJsonObject(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonArray *arrayBuilder() {
|
||||||
|
return new BuilderJsonArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderJsonArray *arrayBuilder(JsonArray &json) {
|
||||||
|
return new BuilderJsonArray(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
} //end namespace
|
250
src/ATBAPP/support/JSON.h
Normal file
250
src/ATBAPP/support/JSON.h
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
#ifndef JSON_H
|
||||||
|
#define JSON_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QString>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
/**********************************************
|
||||||
|
* based on: https://github.com/qt-json/qt-json
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \namespace JSON
|
||||||
|
* \brief A JSON data parser
|
||||||
|
*
|
||||||
|
* Json parses a JSON data into a QVariant hierarchy.
|
||||||
|
*/
|
||||||
|
namespace JSON {
|
||||||
|
typedef QVariantMap JsonObject;
|
||||||
|
typedef QVariantList JsonArray;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone a JSON object (makes a deep copy)
|
||||||
|
*
|
||||||
|
* \param data The JSON object
|
||||||
|
*/
|
||||||
|
QVariant clone(const QVariant &data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert value to JSON object (QVariantMap)
|
||||||
|
*
|
||||||
|
* \param v The JSON object
|
||||||
|
* \param key The key
|
||||||
|
* \param value The value
|
||||||
|
*/
|
||||||
|
void insert(QVariant &v, const QString &key, const QVariant &value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append value to JSON array (QVariantList)
|
||||||
|
*
|
||||||
|
* \param v The JSON array
|
||||||
|
* \param value The value
|
||||||
|
*/
|
||||||
|
void append(QVariant &v, const QVariant &value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a JSON string
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
*/
|
||||||
|
QVariant parse(const QString &json);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a JSON string
|
||||||
|
*
|
||||||
|
* \param json The JSON data
|
||||||
|
* \param success The success of the parsing
|
||||||
|
*/
|
||||||
|
QVariant parse(const QString &json, bool &success);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method generates a textual JSON representation
|
||||||
|
*
|
||||||
|
* \param data The JSON data generated by the parser.
|
||||||
|
*
|
||||||
|
* \return QByteArray Textual JSON representation in UTF-8
|
||||||
|
*/
|
||||||
|
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 in UTF-8
|
||||||
|
*/
|
||||||
|
QByteArray serialize(const QVariant &data, bool &success, int _level = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method generates a textual JSON representation
|
||||||
|
*
|
||||||
|
* \param data The JSON data generated by the parser.
|
||||||
|
*
|
||||||
|
* \return QString Textual JSON representation
|
||||||
|
*/
|
||||||
|
QString serializeStr(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 QString Textual JSON representation
|
||||||
|
*/
|
||||||
|
QString serializeStr(const QVariant &data, bool &success, int _level = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets date(time) format to be used for QDateTime::toString
|
||||||
|
* If QString is empty, Qt::TextDate is used.
|
||||||
|
*
|
||||||
|
* \param format The JSON data generated by the parser.
|
||||||
|
*/
|
||||||
|
void setDateTimeFormat(const QString& format);
|
||||||
|
void setDateFormat(const QString& format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method gets date(time) format to be used for QDateTime::toString
|
||||||
|
* If QString is empty, Qt::TextDate is used.
|
||||||
|
*/
|
||||||
|
QString getDateTimeFormat();
|
||||||
|
QString getDateFormat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setPrettySerialize enable/disabled pretty-print when serialize() a json
|
||||||
|
* @param enabled
|
||||||
|
*/
|
||||||
|
void setPrettySerialize(bool enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief isPrettySerialize check if is enabled pretty-print when serialize() a json
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool isPrettySerialize();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QVariant based Json object
|
||||||
|
*/
|
||||||
|
class Object : public QVariant {
|
||||||
|
template<typename T>
|
||||||
|
Object& insertKey(Object* ptr, const QString& key) {
|
||||||
|
T* p = (T*)ptr->data();
|
||||||
|
if (!p->contains(key)) p->insert(key, QVariant());
|
||||||
|
return *reinterpret_cast<Object*>(&p->operator[](key));
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void removeKey(Object *ptr, const QString& key) {
|
||||||
|
T* p = (T*)ptr->data();
|
||||||
|
p->remove(key);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
Object() : QVariant() {}
|
||||||
|
Object(const Object& ref) : QVariant(ref) {}
|
||||||
|
|
||||||
|
Object& operator=(const QVariant& rhs) {
|
||||||
|
/** It maybe more robust when running under Qt versions below 4.7 */
|
||||||
|
QObject * obj = qvariant_cast<QObject *>(rhs);
|
||||||
|
// setValue(rhs);
|
||||||
|
setValue(obj);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Object& operator[](const QString& key) {
|
||||||
|
if (type() == QVariant::Map)
|
||||||
|
return insertKey<QVariantMap>(this, key);
|
||||||
|
else if (type() == QVariant::Hash)
|
||||||
|
return insertKey<QVariantHash>(this, key);
|
||||||
|
|
||||||
|
setValue(QVariantMap());
|
||||||
|
|
||||||
|
return insertKey<QVariantMap>(this, key);
|
||||||
|
}
|
||||||
|
const Object& operator[](const QString& key) const {
|
||||||
|
return const_cast<Object*>(this)->operator[](key);
|
||||||
|
}
|
||||||
|
void remove(const QString& key) {
|
||||||
|
if (type() == QVariant::Map)
|
||||||
|
removeKey<QVariantMap>(this, key);
|
||||||
|
else if (type() == QVariant::Hash)
|
||||||
|
removeKey<QVariantHash>(this, key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BuilderJsonArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The BuilderJsonObject class
|
||||||
|
*/
|
||||||
|
class BuilderJsonObject {
|
||||||
|
|
||||||
|
public:
|
||||||
|
BuilderJsonObject();
|
||||||
|
BuilderJsonObject(JsonObject &json);
|
||||||
|
|
||||||
|
BuilderJsonObject *set(const QString &key, const QVariant &value);
|
||||||
|
BuilderJsonObject *set(const QString &key, BuilderJsonObject *builder);
|
||||||
|
BuilderJsonObject *set(const QString &key, BuilderJsonArray *builder);
|
||||||
|
JsonObject create();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QQueue<BuilderJsonObject *> created_list;
|
||||||
|
|
||||||
|
JsonObject obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The BuilderJsonArray class
|
||||||
|
*/
|
||||||
|
class BuilderJsonArray {
|
||||||
|
|
||||||
|
public:
|
||||||
|
BuilderJsonArray();
|
||||||
|
BuilderJsonArray(JsonArray &json);
|
||||||
|
|
||||||
|
BuilderJsonArray *add(const QVariant &element);
|
||||||
|
BuilderJsonArray *add(BuilderJsonObject *builder);
|
||||||
|
BuilderJsonArray *add(BuilderJsonArray *builder);
|
||||||
|
JsonArray create();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QQueue<BuilderJsonArray *> created_list;
|
||||||
|
|
||||||
|
JsonArray array;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a BuilderJsonObject
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
BuilderJsonObject *objectBuilder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a BuilderJsonObject starting from copy of another json
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
BuilderJsonObject *objectBuilder(JsonObject &json);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a BuilderJsonArray
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
BuilderJsonArray *arrayBuilder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a BuilderJsonArray starting from copy of another json
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
BuilderJsonArray *arrayBuilder(JsonArray &json);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JSON_H
|
Loading…
Reference in New Issue
Block a user