* enable proper processing of any .001 style raw multi-part archive 7zip can handle
This commit is contained in:
parent
6451c5f478
commit
529e28b5d7
|
@ -8,7 +8,6 @@ import java.io.FileFilter;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -20,8 +19,6 @@ import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import net.sf.sevenzipjbinding.ArchiveFormat;
|
import net.sf.sevenzipjbinding.ArchiveFormat;
|
||||||
import net.sf.sevenzipjbinding.IArchiveOpenCallback;
|
|
||||||
import net.sf.sevenzipjbinding.IInStream;
|
|
||||||
import net.sf.sevenzipjbinding.ISevenZipInArchive;
|
import net.sf.sevenzipjbinding.ISevenZipInArchive;
|
||||||
import net.sf.sevenzipjbinding.PropID;
|
import net.sf.sevenzipjbinding.PropID;
|
||||||
import net.sf.sevenzipjbinding.SevenZipException;
|
import net.sf.sevenzipjbinding.SevenZipException;
|
||||||
|
@ -41,13 +38,15 @@ public class Archive implements Closeable {
|
||||||
throw new FileNotFoundException(file.getAbsolutePath());
|
throw new FileNotFoundException(file.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7-Zip-JBinding NATIVE LIBS MUST BE LOADED WITH SYSTEM CLASSLOADER
|
|
||||||
Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass("net.sourceforge.filebot.archive.SevenZipLoader");
|
|
||||||
Method m = clazz.getMethod("open", new Class[] { IInStream.class, IArchiveOpenCallback.class });
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
openVolume = new ArchiveOpenVolumeCallback();
|
openVolume = new ArchiveOpenVolumeCallback();
|
||||||
inArchive = (ISevenZipInArchive) m.invoke(null, openVolume.getStream(file.getAbsolutePath()), openVolume);
|
if (!hasMultiPartIndex(file)) {
|
||||||
|
// single volume archives and multi-volume rar archives
|
||||||
|
inArchive = SevenZipLoader.open(openVolume.getStream(file.getAbsolutePath()), openVolume);
|
||||||
|
} else {
|
||||||
|
// raw multi-volume archives
|
||||||
|
inArchive = SevenZipLoader.open(new VolumedArchiveInStream(file.getAbsolutePath(), openVolume), null);
|
||||||
|
}
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
throw (Exception) e.getTargetException();
|
throw (Exception) e.getTargetException();
|
||||||
}
|
}
|
||||||
|
@ -142,16 +141,24 @@ public class Archive implements Closeable {
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Pattern multiPartIndex = Pattern.compile("[.][0-9]{3}+$");
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean hasMultiPartIndex(File file) {
|
||||||
|
return multiPartIndex.matcher(file.getName()).find();
|
||||||
|
}
|
||||||
|
|
||||||
public static final FileFilter VOLUME_ONE_FILTER = new FileFilter() {
|
public static final FileFilter VOLUME_ONE_FILTER = new FileFilter() {
|
||||||
|
|
||||||
private Pattern volume = Pattern.compile("[.]r[0-9]+$|[.]part[0-9]+[.][0-9a-z]+$|[.][0-9]+$", Pattern.CASE_INSENSITIVE);
|
private Pattern volume = Pattern.compile("[.]r[0-9]+$|[.]part[0-9]+|[.][0-9]+$", Pattern.CASE_INSENSITIVE);
|
||||||
private FileFilter archives = new ExtensionFileFilter(getArchiveTypes());
|
private FileFilter archives = new ExtensionFileFilter(getArchiveTypes());
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File path) {
|
public boolean accept(File path) {
|
||||||
if (!archives.accept(path) && !volume.matcher(path.getName()).find())
|
if (!archives.accept(path) && !hasMultiPartIndex(path)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Matcher matcher = volume.matcher(path.getName());
|
Matcher matcher = volume.matcher(path.getName());
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
|
|
|
@ -46,7 +46,11 @@ public class SevenZipLoader {
|
||||||
// initialize 7-Zip-JBinding
|
// initialize 7-Zip-JBinding
|
||||||
requireNativeLibraries();
|
requireNativeLibraries();
|
||||||
|
|
||||||
|
if (callback == null) {
|
||||||
|
return SevenZip.openInArchive(null, stream);
|
||||||
|
} else {
|
||||||
return SevenZip.openInArchive(null, stream, callback);
|
return SevenZip.openInArchive(null, stream, callback);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
|
||||||
|
package net.sourceforge.filebot.archive;
|
||||||
|
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.sf.sevenzipjbinding.IArchiveOpenVolumeCallback;
|
||||||
|
import net.sf.sevenzipjbinding.IInStream;
|
||||||
|
import net.sf.sevenzipjbinding.PropID;
|
||||||
|
import net.sf.sevenzipjbinding.SevenZipException;
|
||||||
|
|
||||||
|
|
||||||
|
public class VolumedArchiveInStream implements IInStream {
|
||||||
|
|
||||||
|
private static final String FIRST_VOLUME_POSTFIX = ".001";
|
||||||
|
|
||||||
|
private long absoluteOffset;
|
||||||
|
private long absoluteLength = -1;
|
||||||
|
|
||||||
|
private int currentIndex = -1;
|
||||||
|
private IInStream currentInStream;
|
||||||
|
private long currentVolumeOffset;
|
||||||
|
private long currentVolumeLength;
|
||||||
|
private List<Long> volumePositions = new ArrayList<Long>();
|
||||||
|
|
||||||
|
private final IArchiveOpenVolumeCallback archiveOpenVolumeCallback;
|
||||||
|
private String cuttedVolumeFilename;
|
||||||
|
|
||||||
|
|
||||||
|
public VolumedArchiveInStream(IArchiveOpenVolumeCallback archiveOpenVolumeCallback) throws SevenZipException {
|
||||||
|
this((String) archiveOpenVolumeCallback.getProperty(PropID.NAME), archiveOpenVolumeCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public VolumedArchiveInStream(String firstVolumeFilename, IArchiveOpenVolumeCallback archiveOpenVolumeCallback) throws SevenZipException {
|
||||||
|
this.archiveOpenVolumeCallback = archiveOpenVolumeCallback;
|
||||||
|
volumePositions.add(Long.valueOf(0));
|
||||||
|
|
||||||
|
if (!firstVolumeFilename.endsWith(FIRST_VOLUME_POSTFIX)) {
|
||||||
|
throw new SevenZipException("The first volume filename '" + firstVolumeFilename + "' don't ends with the postfix: '" + FIRST_VOLUME_POSTFIX + "'. Can't proceed");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cuttedVolumeFilename = firstVolumeFilename.substring(0, firstVolumeFilename.length() - 3);
|
||||||
|
openVolume(1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void openVolume(int index, boolean seekToBegin) throws SevenZipException {
|
||||||
|
if (currentIndex == index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = volumePositions.size(); i < index && absoluteLength == -1; i++) {
|
||||||
|
openVolume(i, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (absoluteLength != -1 && volumePositions.size() <= index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String volumeFilename = cuttedVolumeFilename + MessageFormat.format("{0,number,000}", Integer.valueOf(index));
|
||||||
|
|
||||||
|
// Get new IInStream
|
||||||
|
IInStream newInStream = archiveOpenVolumeCallback.getStream(volumeFilename);
|
||||||
|
|
||||||
|
if (newInStream == null) {
|
||||||
|
absoluteLength = volumePositions.get(volumePositions.size() - 1).longValue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentInStream = newInStream;
|
||||||
|
|
||||||
|
if (volumePositions.size() == index) {
|
||||||
|
// Determine volume size
|
||||||
|
currentVolumeLength = currentInStream.seek(0, SEEK_END);
|
||||||
|
if (currentVolumeLength == 0) {
|
||||||
|
throw new RuntimeException("Volume " + index + " is empty");
|
||||||
|
}
|
||||||
|
volumePositions.add(Long.valueOf(volumePositions.get(index - 1).longValue() + currentVolumeLength));
|
||||||
|
|
||||||
|
if (seekToBegin) {
|
||||||
|
currentInStream.seek(0, SEEK_SET);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentVolumeLength = volumePositions.get(index).longValue() - volumePositions.get(index - 1).longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seekToBegin) {
|
||||||
|
currentVolumeOffset = 0;
|
||||||
|
absoluteOffset = volumePositions.get(index - 1).longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void openVolumeToAbsoluteOffset() throws SevenZipException {
|
||||||
|
int index = volumePositions.size() - 1;
|
||||||
|
if (absoluteLength != -1 && absoluteOffset >= absoluteLength) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (volumePositions.get(index).longValue() > absoluteOffset) {
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < volumePositions.size() - 1) {
|
||||||
|
openVolume(index + 1, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
index++;
|
||||||
|
openVolume(index, false);
|
||||||
|
} while ((absoluteLength == -1 || absoluteOffset < absoluteLength) && volumePositions.get(index).longValue() <= absoluteOffset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long seek(long offset, int seekOrigin) throws SevenZipException {
|
||||||
|
long newOffset;
|
||||||
|
boolean proceedWithSeek = false;
|
||||||
|
switch (seekOrigin) {
|
||||||
|
case SEEK_SET:
|
||||||
|
newOffset = offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_CUR:
|
||||||
|
newOffset = absoluteOffset + offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_END:
|
||||||
|
if (absoluteLength == -1) {
|
||||||
|
openVolume(Integer.MAX_VALUE, false);
|
||||||
|
proceedWithSeek = true;
|
||||||
|
}
|
||||||
|
newOffset = absoluteLength + offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Seek: unknown origin: " + seekOrigin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newOffset == absoluteOffset && !proceedWithSeek) {
|
||||||
|
return newOffset;
|
||||||
|
}
|
||||||
|
absoluteOffset = newOffset;
|
||||||
|
|
||||||
|
openVolumeToAbsoluteOffset();
|
||||||
|
|
||||||
|
if (absoluteLength != -1 && absoluteLength <= absoluteOffset) {
|
||||||
|
absoluteOffset = absoluteLength;
|
||||||
|
return absoluteLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentVolumeOffset = absoluteOffset - volumePositions.get(currentIndex - 1).longValue();
|
||||||
|
currentInStream.seek(currentVolumeOffset, SEEK_SET);
|
||||||
|
|
||||||
|
return newOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] data) throws SevenZipException {
|
||||||
|
if (absoluteLength != -1 && absoluteOffset >= absoluteLength) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read = currentInStream.read(data);
|
||||||
|
|
||||||
|
absoluteOffset += read;
|
||||||
|
currentVolumeOffset += read;
|
||||||
|
|
||||||
|
if (currentVolumeOffset >= currentVolumeLength) {
|
||||||
|
openVolume(currentIndex + 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue