Allow resolving relative urls when importing entities json

This commit is contained in:
Maki 2020-08-04 01:33:19 +01:00
parent 8f3377b716
commit 3783c98976
4 changed files with 93 additions and 12 deletions

View file

@ -685,8 +685,9 @@ bool Octree::readFromFile(const char* fileName) {
QDataStream fileInputStream(&file);
QFileInfo fileInfo(qFileName);
uint64_t fileLength = fileInfo.size();
QUrl relativeURL = QUrl::fromLocalFile(qFileName).adjusted(QUrl::RemoveFilename);
bool success = readFromStream(fileLength, fileInputStream);
bool success = readFromStream(fileLength, fileInputStream, "", false, relativeURL);
file.close();
@ -708,7 +709,9 @@ bool Octree::readJSONFromGzippedFile(QString qFileName) {
}
QDataStream jsonStream(jsonData);
return readJSONFromStream(-1, jsonStream);
QUrl relativeURL = QUrl::fromLocalFile(qFileName).adjusted(QUrl::RemoveFilename);
return readJSONFromStream(-1, jsonStream, "", false, relativeURL);
}
// hack to get the marketplace id into the entities. We will create a way to get this from a hash of
@ -761,13 +764,15 @@ bool Octree::readFromURL(
QByteArray uncompressedJsonData;
bool wasCompressed = gunzip(data, uncompressedJsonData);
QUrl relativeURL = QUrl(urlString).adjusted(QUrl::RemoveFilename);
if (wasCompressed) {
QDataStream inputStream(uncompressedJsonData);
return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID);
return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, isImport, relativeURL);
}
QDataStream inputStream(data);
return readFromStream(data.size(), inputStream, marketplaceID, isImport);
return readFromStream(data.size(), inputStream, marketplaceID, isImport, relativeURL);
}
bool Octree::readFromByteArray(
@ -780,20 +785,23 @@ bool Octree::readFromByteArray(
QByteArray uncompressedJsonData;
bool wasCompressed = gunzip(data, uncompressedJsonData);
QUrl relativeURL = QUrl(urlString).adjusted(QUrl::RemoveFilename);
if (wasCompressed) {
QDataStream inputStream(uncompressedJsonData);
return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID);
return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, false, relativeURL);
}
QDataStream inputStream(data);
return readFromStream(data.size(), inputStream, marketplaceID);
return readFromStream(data.size(), inputStream, marketplaceID, false, relativeURL);
}
bool Octree::readFromStream(
uint64_t streamLength,
QDataStream& inputStream,
const QString& marketplaceID,
const bool isImport
const bool isImport,
const QUrl& relativeURL
) {
// decide if this is binary SVO or JSON-formatted SVO
QIODevice *device = inputStream.device();
@ -806,7 +814,7 @@ bool Octree::readFromStream(
return false;
} else {
qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength;
return readJSONFromStream(streamLength, inputStream, marketplaceID, isImport);
return readJSONFromStream(streamLength, inputStream, marketplaceID, isImport, relativeURL);
}
}
@ -837,7 +845,8 @@ bool Octree::readJSONFromStream(
uint64_t streamLength,
QDataStream& inputStream,
const QString& marketplaceID, /*=""*/
const bool isImport
const bool isImport,
const QUrl& relativeURL
) {
// if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until
// we get an eof. Leave streamLength parameter for consistency.
@ -858,7 +867,9 @@ bool Octree::readJSONFromStream(
}
OctreeEntitiesFileParser octreeParser;
octreeParser.relativeURL = relativeURL;
octreeParser.setEntitiesString(jsonBuffer);
QVariantMap asMap;
if (!octreeParser.parseEntities(asMap)) {
qCritical() << "Couldn't parse Entities JSON:" << octreeParser.getErrorString().c_str();

View file

@ -218,8 +218,8 @@ public:
bool readFromFile(const char* filename);
bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1, const bool isImport = false); // will support file urls as well...
bool readFromByteArray(const QString& url, const QByteArray& byteArray);
bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false);
bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false);
bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false, const QUrl& urlString = QUrl());
bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false, const QUrl& urlString = QUrl());
bool readJSONFromGzippedFile(QString qFileName);
virtual bool readFromMap(QVariantMap& entityDescription, const bool isImport = false) = 0;

View file

@ -237,7 +237,75 @@ bool OctreeEntitiesFileParser::readEntitiesArray(QVariantList& entitiesArray) {
return false;
}
entitiesArray.append(entity.object());
QJsonObject entityObject = entity.object();
// resolve urls starting with ./ or ../
if (relativeURL.isEmpty() == false) {
bool isDirty = false;
const QStringList urlKeys {
// model
"modelURL",
"animation.url",
// image
"imageURL",
// web
"sourceUrl",
"scriptURL",
// zone
"ambientLight.ambientURL",
"skybox.url",
// particles
"textures",
// materials
"materialURL",
// ...shared
"href",
"script",
"serverScripts",
"collisionSoundURL",
"compoundShapeURL",
// TODO: deal with materialData and userData
};
for (const QString& key : urlKeys) {
if (key.contains('.')) {
// url is inside another object
const QStringList keyPair = key.split('.');
const QString entityKey = keyPair[0];
const QString childKey = keyPair[1];
if (entityObject.contains(entityKey) && entityObject[entityKey].isObject()) {
QJsonObject childObject = entityObject[entityKey].toObject();
if (childObject.contains(childKey) && childObject[childKey].isString()) {
const QString url = childObject[childKey].toString();
if (url.startsWith("./") || url.startsWith("../")) {
childObject[childKey] = relativeURL.resolved(url).toString();
entityObject[entityKey] = childObject;
isDirty = true;
}
}
}
} else {
if (entityObject.contains(key) && entityObject[key].isString()) {
const QString url = entityObject[key].toString();
if (url.startsWith("./") || url.startsWith("../")) {
entityObject[key] = relativeURL.resolved(url).toString();
isDirty = true;
}
}
}
}
if (isDirty) {
entity.setObject(entityObject);
}
}
entitiesArray.append(entityObject);
_position = matchingBrace;
char c = nextToken();
if (c == ']') {

View file

@ -16,12 +16,14 @@
#include <QByteArray>
#include <QVariant>
#include <QUrl>
class OctreeEntitiesFileParser {
public:
void setEntitiesString(const QByteArray& entitiesContents);
bool parseEntities(QVariantMap& parsedEntities);
std::string getErrorString() const;
QUrl relativeURL;
private:
int nextToken();