Merge pull request #586 from makitsune/relative-urls

Allow resolving relative urls when importing entities json
This commit is contained in:
kasenvr 2020-09-01 04:34:12 -04:00 committed by GitHub
commit 6a872ef525
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 12 deletions

View file

@ -685,8 +685,9 @@ bool Octree::readFromFile(const char* fileName) {
QDataStream fileInputStream(&file); QDataStream fileInputStream(&file);
QFileInfo fileInfo(qFileName); QFileInfo fileInfo(qFileName);
uint64_t fileLength = fileInfo.size(); 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(); file.close();
@ -708,7 +709,9 @@ bool Octree::readJSONFromGzippedFile(QString qFileName) {
} }
QDataStream jsonStream(jsonData); 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 // 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; QByteArray uncompressedJsonData;
bool wasCompressed = gunzip(data, uncompressedJsonData); bool wasCompressed = gunzip(data, uncompressedJsonData);
QUrl relativeURL = QUrl(urlString).adjusted(QUrl::RemoveFilename);
if (wasCompressed) { if (wasCompressed) {
QDataStream inputStream(uncompressedJsonData); QDataStream inputStream(uncompressedJsonData);
return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID); return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, isImport, relativeURL);
} }
QDataStream inputStream(data); QDataStream inputStream(data);
return readFromStream(data.size(), inputStream, marketplaceID, isImport); return readFromStream(data.size(), inputStream, marketplaceID, isImport, relativeURL);
} }
bool Octree::readFromByteArray( bool Octree::readFromByteArray(
@ -780,20 +785,23 @@ bool Octree::readFromByteArray(
QByteArray uncompressedJsonData; QByteArray uncompressedJsonData;
bool wasCompressed = gunzip(data, uncompressedJsonData); bool wasCompressed = gunzip(data, uncompressedJsonData);
QUrl relativeURL = QUrl(urlString).adjusted(QUrl::RemoveFilename);
if (wasCompressed) { if (wasCompressed) {
QDataStream inputStream(uncompressedJsonData); QDataStream inputStream(uncompressedJsonData);
return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID); return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, false, relativeURL);
} }
QDataStream inputStream(data); QDataStream inputStream(data);
return readFromStream(data.size(), inputStream, marketplaceID); return readFromStream(data.size(), inputStream, marketplaceID, false, relativeURL);
} }
bool Octree::readFromStream( bool Octree::readFromStream(
uint64_t streamLength, uint64_t streamLength,
QDataStream& inputStream, QDataStream& inputStream,
const QString& marketplaceID, const QString& marketplaceID,
const bool isImport const bool isImport,
const QUrl& relativeURL
) { ) {
// decide if this is binary SVO or JSON-formatted SVO // decide if this is binary SVO or JSON-formatted SVO
QIODevice *device = inputStream.device(); QIODevice *device = inputStream.device();
@ -806,7 +814,7 @@ bool Octree::readFromStream(
return false; return false;
} else { } else {
qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength; 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, uint64_t streamLength,
QDataStream& inputStream, QDataStream& inputStream,
const QString& marketplaceID, /*=""*/ 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 // 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. // we get an eof. Leave streamLength parameter for consistency.
@ -858,7 +867,9 @@ bool Octree::readJSONFromStream(
} }
OctreeEntitiesFileParser octreeParser; OctreeEntitiesFileParser octreeParser;
octreeParser.relativeURL = relativeURL;
octreeParser.setEntitiesString(jsonBuffer); octreeParser.setEntitiesString(jsonBuffer);
QVariantMap asMap; QVariantMap asMap;
if (!octreeParser.parseEntities(asMap)) { if (!octreeParser.parseEntities(asMap)) {
qCritical() << "Couldn't parse Entities JSON:" << octreeParser.getErrorString().c_str(); qCritical() << "Couldn't parse Entities JSON:" << octreeParser.getErrorString().c_str();

View file

@ -218,8 +218,8 @@ public:
bool readFromFile(const char* filename); 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 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 readFromByteArray(const QString& url, const QByteArray& byteArray);
bool readFromStream(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); bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false, const QUrl& urlString = QUrl());
bool readJSONFromGzippedFile(QString qFileName); bool readJSONFromGzippedFile(QString qFileName);
virtual bool readFromMap(QVariantMap& entityDescription, const bool isImport = false) = 0; virtual bool readFromMap(QVariantMap& entityDescription, const bool isImport = false) = 0;

View file

@ -237,7 +237,75 @@ bool OctreeEntitiesFileParser::readEntitiesArray(QVariantList& entitiesArray) {
return false; 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; _position = matchingBrace;
char c = nextToken(); char c = nextToken();
if (c == ']') { if (c == ']') {

View file

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