Fix multi-part RAR extraction: use VolumedArchiveInStream for .partN.rar
The JVM extractor used RandomAccessFileInStream for multi-part RAR archives, which only provides a single file stream. 7z-JBinding requires VolumedArchiveInStream to access additional volume parts via callback. Added RAR_MULTIPART_RE and RAR_OLDSPLIT_RE patterns to detect multi-volume RAR archives and route them through VolumedArchiveInStream, fixing "Archive file can't be opened with any of the registered codecs" errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d3ec000da5
commit
d4bf574370
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "1.5.48",
|
"version": "1.5.54",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "1.5.48",
|
"version": "1.5.54",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -42,6 +42,8 @@ public final class JBindExtractorMain {
|
|||||||
private static final Pattern NUMBERED_ZIP_SPLIT_RE = Pattern.compile("(?i).*\\.zip\\.\\d{3}$");
|
private static final Pattern NUMBERED_ZIP_SPLIT_RE = Pattern.compile("(?i).*\\.zip\\.\\d{3}$");
|
||||||
private static final Pattern OLD_ZIP_SPLIT_RE = Pattern.compile("(?i).*\\.z\\d{2,3}$");
|
private static final Pattern OLD_ZIP_SPLIT_RE = Pattern.compile("(?i).*\\.z\\d{2,3}$");
|
||||||
private static final Pattern SEVEN_ZIP_SPLIT_RE = Pattern.compile("(?i).*\\.7z\\.001$");
|
private static final Pattern SEVEN_ZIP_SPLIT_RE = Pattern.compile("(?i).*\\.7z\\.001$");
|
||||||
|
private static final Pattern RAR_MULTIPART_RE = Pattern.compile("(?i).*\\.part\\d+\\.rar$");
|
||||||
|
private static final Pattern RAR_OLDSPLIT_RE = Pattern.compile("(?i).*\\.r\\d{2,3}$");
|
||||||
private static volatile boolean sevenZipInitialized = false;
|
private static volatile boolean sevenZipInitialized = false;
|
||||||
|
|
||||||
private JBindExtractorMain() {
|
private JBindExtractorMain() {
|
||||||
@ -326,7 +328,13 @@ public final class JBindExtractorMain {
|
|||||||
String effectivePassword = password == null ? "" : password;
|
String effectivePassword = password == null ? "" : password;
|
||||||
SevenZipVolumeCallback callback = new SevenZipVolumeCallback(archiveFile, effectivePassword);
|
SevenZipVolumeCallback callback = new SevenZipVolumeCallback(archiveFile, effectivePassword);
|
||||||
|
|
||||||
if (SEVEN_ZIP_SPLIT_RE.matcher(nameLower).matches()) {
|
// Multi-volume archives need VolumedArchiveInStream so 7z-JBinding can
|
||||||
|
// request additional volumes via the IArchiveOpenVolumeCallback.
|
||||||
|
boolean isMultiVolume = SEVEN_ZIP_SPLIT_RE.matcher(nameLower).matches()
|
||||||
|
|| RAR_MULTIPART_RE.matcher(nameLower).matches()
|
||||||
|
|| hasOldStyleRarSplits(archiveFile);
|
||||||
|
|
||||||
|
if (isMultiVolume) {
|
||||||
VolumedArchiveInStream volumed = new VolumedArchiveInStream(archiveFile.getName(), callback);
|
VolumedArchiveInStream volumed = new VolumedArchiveInStream(archiveFile.getName(), callback);
|
||||||
IInArchive archive = SevenZip.openInArchive(null, volumed, callback);
|
IInArchive archive = SevenZip.openInArchive(null, volumed, callback);
|
||||||
return new SevenZipArchiveContext(archive, null, volumed, callback);
|
return new SevenZipArchiveContext(archive, null, volumed, callback);
|
||||||
@ -338,6 +346,36 @@ public final class JBindExtractorMain {
|
|||||||
return new SevenZipArchiveContext(archive, stream, null, callback);
|
return new SevenZipArchiveContext(archive, stream, null, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean hasOldStyleRarSplits(File archiveFile) {
|
||||||
|
// Old-style RAR splits: main.rar + main.r01, main.r02, ...
|
||||||
|
String name = archiveFile.getName();
|
||||||
|
if (!name.toLowerCase(Locale.ROOT).endsWith(".rar")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
File parent = archiveFile.getParentFile();
|
||||||
|
if (parent == null || !parent.exists()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
File[] siblings = parent.listFiles();
|
||||||
|
if (siblings == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String stem = name.substring(0, name.length() - 4);
|
||||||
|
for (File sibling : siblings) {
|
||||||
|
if (!sibling.isFile()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String sibName = sibling.getName();
|
||||||
|
if (sibName.length() > stem.length() + 1 && sibName.substring(0, stem.length()).equalsIgnoreCase(stem)) {
|
||||||
|
String suffix = sibName.substring(stem.length());
|
||||||
|
if (RAR_OLDSPLIT_RE.matcher(suffix).matches() || suffix.toLowerCase(Locale.ROOT).matches("\\.r\\d{2,3}")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isWrongPassword(ZipException error, boolean encrypted) {
|
private static boolean isWrongPassword(ZipException error, boolean encrypted) {
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user