ours
| 269 | |
| 270 | // ours |
| 271 | std::optional<QStringList> extractSubDir(QuaZip* zip, const QString& subdir, const QString& target) |
| 272 | { |
| 273 | auto target_top_dir = QUrl::fromLocalFile(target); |
| 274 | |
| 275 | QStringList extracted; |
| 276 | |
| 277 | qDebug() << "Extracting subdir" << subdir << "from" << zip->getZipName() << "to" << target; |
| 278 | auto numEntries = zip->getEntriesCount(); |
| 279 | if (numEntries < 0) { |
| 280 | qWarning() << "Failed to enumerate files in archive"; |
| 281 | return std::nullopt; |
| 282 | } else if (numEntries == 0) { |
| 283 | qDebug() << "Extracting empty archives seems odd..."; |
| 284 | return extracted; |
| 285 | } else if (!zip->goToFirstFile()) { |
| 286 | qWarning() << "Failed to seek to first file in zip"; |
| 287 | return std::nullopt; |
| 288 | } |
| 289 | |
| 290 | do { |
| 291 | QString file_name = zip->getCurrentFileName(); |
| 292 | file_name = FS::RemoveInvalidPathChars(file_name); |
| 293 | if (!file_name.startsWith(subdir)) |
| 294 | continue; |
| 295 | |
| 296 | auto relative_file_name = QDir::fromNativeSeparators(file_name.mid(subdir.size())); |
| 297 | auto original_name = relative_file_name; |
| 298 | |
| 299 | // Fix subdirs/files ending with a / getting transformed into absolute paths |
| 300 | if (relative_file_name.startsWith('/')) |
| 301 | relative_file_name = relative_file_name.mid(1); |
| 302 | |
| 303 | // Fix weird "folders with a single file get squashed" thing |
| 304 | QString sub_path; |
| 305 | if (relative_file_name.contains('/') && !relative_file_name.endsWith('/')) { |
| 306 | sub_path = relative_file_name.section('/', 0, -2) + '/'; |
| 307 | FS::ensureFolderPathExists(FS::PathCombine(target, sub_path)); |
| 308 | |
| 309 | relative_file_name = relative_file_name.split('/').last(); |
| 310 | } |
| 311 | |
| 312 | QString target_file_path; |
| 313 | if (relative_file_name.isEmpty()) { |
| 314 | target_file_path = target + '/'; |
| 315 | } else { |
| 316 | target_file_path = FS::PathCombine(target_top_dir.toLocalFile(), sub_path, relative_file_name); |
| 317 | if (relative_file_name.endsWith('/') && !target_file_path.endsWith('/')) |
| 318 | target_file_path += '/'; |
| 319 | } |
| 320 | |
| 321 | if (!target_top_dir.isParentOf(QUrl::fromLocalFile(target_file_path))) { |
| 322 | qWarning() << "Extracting" << relative_file_name << "was cancelled, because it was effectively outside of the target path" |
| 323 | << target; |
| 324 | return std::nullopt; |
| 325 | } |
| 326 | |
| 327 | if (!JlCompress::extractFile(zip, "", target_file_path)) { |
| 328 | qWarning() << "Failed to extract file" << original_name << "to" << target_file_path; |
no test coverage detected