Faster JSON entities parser

This commit is contained in:
Simon Walton 2018-10-16 18:08:07 -07:00
parent f5f34e8e7d
commit c031769c67
4 changed files with 67 additions and 15 deletions

View file

@ -9,6 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#include "OctreeDataUtils.h"
#include "OctreeEntitiesFileParser.h"
#include <Gzip.h>
#include <udt/PacketHeaders.h>
@ -55,19 +56,30 @@ bool OctreeUtils::RawOctreeData::readOctreeDataInfoFromJSON(QJsonObject root) {
return true;
}
bool OctreeUtils::RawOctreeData::readOctreeDataInfoFromMap(QVariantMap map) {
if (map.contains("Id") && map.contains("DataVersion") && map.contains("Version")) {
id = map["Id"].toUuid();
dataVersion = map["DataVersion"].toInt();
version = map["Version"].toInt();
}
return true;
}
bool OctreeUtils::RawOctreeData::readOctreeDataInfoFromData(QByteArray data) {
QByteArray jsonData;
if (gunzip(data, jsonData)) {
data = jsonData;
}
auto doc = QJsonDocument::fromJson(data);
if (doc.isNull()) {
OctreeEntitiesFileParser jsonParser;
jsonParser.setEntitiesString(data);
QVariantMap entitiesMap;
if (!jsonParser.parseEntities(entitiesMap)) {
qCritical() << "Can't parse Entities JSON: " << jsonParser.getErrorString().c_str();
return false;
}
auto root = doc.object();
return readOctreeDataInfoFromJSON(root);
return readOctreeDataInfoFromMap(entitiesMap);
}
// Reads octree file and parses it into a RawOctreeData object.

View file

@ -43,6 +43,7 @@ public:
bool readOctreeDataInfoFromData(QByteArray data);
bool readOctreeDataInfoFromFile(QString path);
bool readOctreeDataInfoFromJSON(QJsonObject root);
bool readOctreeDataInfoFromMap(QVariantMap map);
};
class RawEntityData : public RawOctreeData {

View file

@ -189,23 +189,25 @@ bool OctreeEntitiesFileParser::readEntitiesArray(QVariantList& entitiesArray) {
}
while (true) {
QJsonParseError parseError;
QByteArray entitiesJson(_entitiesContents.right(_entitiesLength - _position));
QJsonDocument entity = QJsonDocument::fromJson(entitiesJson, &parseError);
if (parseError.error != QJsonParseError::GarbageAtEnd) {
_errorString = "Ill-formed entity array";
if (nextToken() != '{') {
_errorString = "Entity array item is not an object";
return false;
}
int matchingBrace = findMatchingBrace();
if (matchingBrace < 0) {
_errorString = "Unterminated entity object";
return false;
}
int entityLength = parseError.offset;
entitiesJson.truncate(entityLength);
_position += entityLength;
entity = QJsonDocument::fromJson(entitiesJson, &parseError);
if (parseError.error != QJsonParseError::NoError) {
_errorString = "Entity item parse error";
QByteArray jsonEntity = _entitiesContents.mid(_position - 1, matchingBrace - _position + 1);
QJsonDocument entity = QJsonDocument::fromJson(jsonEntity);
if (entity.isNull()) {
_errorString = "Ill-formed entity";
return false;
}
entitiesArray.append(entity.object());
_position = matchingBrace;
char c = nextToken();
if (c == ']') {
return true;
@ -216,3 +218,37 @@ bool OctreeEntitiesFileParser::readEntitiesArray(QVariantList& entitiesArray) {
}
return true;
}
int OctreeEntitiesFileParser::findMatchingBrace() const {
int index = _position;
int nestCount = 1;
while (index < _entitiesLength && nestCount != 0) {
switch (_entitiesContents[index++]) {
case '{':
++nestCount;
break;
case '}':
--nestCount;
break;
case '"':
// Skip string
while (index < _entitiesLength) {
if (_entitiesContents[index] == '"') {
++index;
break;
} else if (_entitiesContents[index] == '\\' && _entitiesContents[++index] == 'u') {
index += 4;
}
++index;
}
break;
default:
break;
}
}
return nestCount == 0 ? index : -1;
}

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Parse the top-level of the Models object ourselves - use QJsonDocument for each Entity object.
#ifndef hifi_OctreeEntitiesFileParser_h
#define hifi_OctreeEntitiesFileParser_h
@ -27,6 +29,7 @@ private:
std::string readString();
int readInteger();
bool readEntitiesArray(QVariantList& entitiesArray);
int findMatchingBrace() const;
QByteArray _entitiesContents;
int _position { 0 };