From 4ea362380acffbcf96b0c9087e321eacf63921f0 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 10 Mar 2020 17:35:21 -0500 Subject: [PATCH] Adding support for proper absolute/canonical path detection and replacement --- src/Timeline.cpp | 50 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 671e28845..61ce31e33 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -117,7 +117,7 @@ Timeline::Timeline(std::string projectPath, bool convert_absolute_paths) : QDir asset_folder(filePath.dir().filePath(asset_name)); if (!asset_folder.exists()) { // Create directory if needed - asset_folder.makeAbsolute(); + asset_folder.mkpath("."); } // Load UTF-8 project file into QString @@ -125,20 +125,46 @@ Timeline::Timeline(std::string projectPath, bool convert_absolute_paths) : projectFile.open(QFile::ReadOnly); QString projectContents = QString::fromUtf8(projectFile.readAll()); - // Convert all relative paths into absolute paths (does not support relative paths with ../) - // In otherwords, assets and files must be located in a child/sub-folder (and not from outside this folder) + // Convert all relative paths into absolute paths (if requested) if (convert_absolute_paths) { - // Convert all paths into absolute (if requested) - QRegularExpression pathRegex(QStringLiteral("\"(image|path)\":.*?\"(?:\\./)?(?!@assets|@transitions+)(.*?)\"")); - projectContents.replace(pathRegex, "\"\\1\": \"" + filePath.absoluteDir().absoluteFilePath("\\2") + "\""); - // Convert all transitions paths into absolute (if requested) - QRegularExpression transRegex(QStringLiteral("\"(image|path)\":.*?\"@transitions/*(.*?)\"")); - projectContents.replace(transRegex, "\"\\1\": \"" + openshotTransPath.absoluteFilePath("\\2") + "\""); + // Find all "image" or "path" references in JSON (using regex). Must loop through match results + // due to our path matching needs, which are not possible with the QString::replace() function. + QRegularExpression allPathsRegex(QStringLiteral("\"(image|path)\":.*?\"(.*?)\"")); + std::vector matchedPositions; + QRegularExpressionMatchIterator i = allPathsRegex.globalMatch(projectContents); + while (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + if (match.hasMatch()) { + // Push all match objects into a vector (so we can reverse them later) + matchedPositions.push_back(match); + } + } + + // Reverse the matches (bottom of file to top, so our replacements don't break our match positions) + std::vector::reverse_iterator itr; + for (itr = matchedPositions.rbegin(); itr != matchedPositions.rend(); itr++) { + QRegularExpressionMatch match = *itr; + QString relativeKey = match.captured(1); // image or path + QString relativePath = match.captured(2); // relative file path + QString absolutePath = ""; + + // Find absolute path of all path, image (including special replacements of @assets and @transitions) + if (relativePath.startsWith("@assets")) { + absolutePath = QFileInfo(asset_folder.absoluteFilePath(relativePath.replace("@assets", "."))).canonicalFilePath(); + } else if (relativePath.startsWith("@transitions")) { + absolutePath = QFileInfo(openshotTransPath.absoluteFilePath(relativePath.replace("@transitions", "."))).canonicalFilePath(); + } else { + absolutePath = QFileInfo(filePath.absoluteDir().absoluteFilePath(relativePath)).canonicalFilePath(); + } - // Convert all assets paths into absolute - QRegularExpression assetRegex(QStringLiteral("\"(image|path)\":.*?\"@assets/*(.*?)\"")); - projectContents.replace(assetRegex, "\"\\1\": \"" + asset_folder.absoluteFilePath("\\2") + "\""); + // Replace path in JSON content, if an absolute path was successfully found + if (!absolutePath.isEmpty()) { + projectContents.replace(match.capturedStart(0), match.capturedLength(0), "\"" + relativeKey + "\": \"" + absolutePath + "\""); + } + } + // Clear matches + matchedPositions.clear(); } // Set JSON of project