@@ -117,28 +117,54 @@ Timeline::Timeline(std::string projectPath, bool convert_absolute_paths) :
117117 QDir asset_folder (filePath.dir ().filePath (asset_name));
118118 if (!asset_folder.exists ()) {
119119 // Create directory if needed
120- asset_folder.makeAbsolute ( );
120+ asset_folder.mkpath ( " . " );
121121 }
122122
123123 // Load UTF-8 project file into QString
124124 QFile projectFile (QString::fromStdString (path));
125125 projectFile.open (QFile::ReadOnly);
126126 QString projectContents = QString::fromUtf8 (projectFile.readAll ());
127127
128- // Convert all relative paths into absolute paths (does not support relative paths with ../)
129- // In otherwords, assets and files must be located in a child/sub-folder (and not from outside this folder)
128+ // Convert all relative paths into absolute paths (if requested)
130129 if (convert_absolute_paths) {
131- // Convert all paths into absolute (if requested)
132- QRegularExpression pathRegex (QStringLiteral (" \" (image|path)\" :.*?\" (?:\\ ./)?(?!@assets|@transitions+)(.*?)\" " ));
133- projectContents.replace (pathRegex, " \"\\ 1\" : \" " + filePath.absoluteDir ().absoluteFilePath (" \\ 2" ) + " \" " );
134130
135- // Convert all transitions paths into absolute (if requested)
136- QRegularExpression transRegex (QStringLiteral (" \" (image|path)\" :.*?\" @transitions/*(.*?)\" " ));
137- projectContents.replace (transRegex, " \"\\ 1\" : \" " + openshotTransPath.absoluteFilePath (" \\ 2" ) + " \" " );
131+ // Find all "image" or "path" references in JSON (using regex). Must loop through match results
132+ // due to our path matching needs, which are not possible with the QString::replace() function.
133+ QRegularExpression allPathsRegex (QStringLiteral (" \" (image|path)\" :.*?\" (.*?)\" " ));
134+ std::vector<QRegularExpressionMatch> matchedPositions;
135+ QRegularExpressionMatchIterator i = allPathsRegex.globalMatch (projectContents);
136+ while (i.hasNext ()) {
137+ QRegularExpressionMatch match = i.next ();
138+ if (match.hasMatch ()) {
139+ // Push all match objects into a vector (so we can reverse them later)
140+ matchedPositions.push_back (match);
141+ }
142+ }
143+
144+ // Reverse the matches (bottom of file to top, so our replacements don't break our match positions)
145+ std::vector<QRegularExpressionMatch>::reverse_iterator itr;
146+ for (itr = matchedPositions.rbegin (); itr != matchedPositions.rend (); itr++) {
147+ QRegularExpressionMatch match = *itr;
148+ QString relativeKey = match.captured (1 ); // image or path
149+ QString relativePath = match.captured (2 ); // relative file path
150+ QString absolutePath = " " ;
151+
152+ // Find absolute path of all path, image (including special replacements of @assets and @transitions)
153+ if (relativePath.startsWith (" @assets" )) {
154+ absolutePath = QFileInfo (asset_folder.absoluteFilePath (relativePath.replace (" @assets" , " ." ))).canonicalFilePath ();
155+ } else if (relativePath.startsWith (" @transitions" )) {
156+ absolutePath = QFileInfo (openshotTransPath.absoluteFilePath (relativePath.replace (" @transitions" , " ." ))).canonicalFilePath ();
157+ } else {
158+ absolutePath = QFileInfo (filePath.absoluteDir ().absoluteFilePath (relativePath)).canonicalFilePath ();
159+ }
138160
139- // Convert all assets paths into absolute
140- QRegularExpression assetRegex (QStringLiteral (" \" (image|path)\" :.*?\" @assets/*(.*?)\" " ));
141- projectContents.replace (assetRegex, " \"\\ 1\" : \" " + asset_folder.absoluteFilePath (" \\ 2" ) + " \" " );
161+ // Replace path in JSON content, if an absolute path was successfully found
162+ if (!absolutePath.isEmpty ()) {
163+ projectContents.replace (match.capturedStart (0 ), match.capturedLength (0 ), " \" " + relativeKey + " \" : \" " + absolutePath + " \" " );
164+ }
165+ }
166+ // Clear matches
167+ matchedPositions.clear ();
142168 }
143169
144170 // Set JSON of project
0 commit comments