Skip to content

Commit

Permalink
#333 Fix issue with reading 7Zip split files with headers not just in…
Browse files Browse the repository at this point in the history
… first split part
  • Loading branch information
srikanth-lingala committed Jun 17, 2022
1 parent 5f51b67 commit f8465d2
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 95 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package net.lingala.zip4j.io.inputstream;

import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
* A split input stream for zip file split with 7-zip. They end with .zip.001, .zip.002, etc
*/
public class NumberedSplitFileInputStream extends SplitFileInputStream {

private RandomAccessFile randomAccessFile;

public NumberedSplitFileInputStream(File zipFile) throws IOException {
this.randomAccessFile = new NumberedSplitRandomAccessFile(zipFile, RandomAccessFileMode.READ.getValue());
}

@Override
public int read() throws IOException {
return randomAccessFile.read();
}

@Override
public int read(byte[] b) throws IOException {
return this.read(b,0, b.length);
}

@Override
public int read(byte[] b, int off, int len) throws IOException {
return randomAccessFile.read(b, off, len);
}

@Override
public void prepareExtractionForFileHeader(FileHeader fileHeader) throws IOException {
randomAccessFile.seek(fileHeader.getOffsetLocalHeader());
}

@Override
public void close() throws IOException {
if (randomAccessFile != null) {
randomAccessFile.close();
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.lingala.zip4j.io.inputstream;

import net.lingala.zip4j.model.FileHeader;

import java.io.IOException;
import java.io.InputStream;

// Even though this abstract class has only abstract method definitions, it is not implemented as an interface because
// implementations of this class has to be used as an inputstream to ZipInputStream
public abstract class SplitFileInputStream extends InputStream {

public abstract void prepareExtractionForFileHeader(FileHeader fileHeader) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,25 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

public abstract class SplitInputStream extends InputStream {
/**
* A split input stream for zip file split as per zip specification. They end with .z01, .z02... .zip
*/
public class ZipStandardSplitFileInputStream extends SplitFileInputStream {

protected RandomAccessFile randomAccessFile;
protected File zipFile;

private int lastSplitZipFileNumber;
private boolean isSplitZipArchive;
private int currentSplitFileCounter = 0;
private byte[] singleByteArray = new byte[1];

public SplitInputStream(File zipFile, boolean isSplitZipArchive, int lastSplitZipFileNumber) throws FileNotFoundException {
public ZipStandardSplitFileInputStream(File zipFile, boolean isSplitZipArchive, int lastSplitZipFileNumber) throws FileNotFoundException {
this.randomAccessFile = new RandomAccessFile(zipFile, RandomAccessFileMode.READ.getValue());
this.zipFile = zipFile;
this.isSplitZipArchive = isSplitZipArchive;


if (isSplitZipArchive) {
currentSplitFileCounter = lastSplitZipFileNumber;
}
this.lastSplitZipFileNumber = lastSplitZipFileNumber;
}

@Override
Expand Down Expand Up @@ -60,6 +58,7 @@ public int read(byte[] b, int off, int len) throws IOException {
return readLen;
}

@Override
public void prepareExtractionForFileHeader(FileHeader fileHeader) throws IOException {

if (isSplitZipArchive && (currentSplitFileCounter != fileHeader.getDiskNumberStart())) {
Expand All @@ -70,6 +69,13 @@ public void prepareExtractionForFileHeader(FileHeader fileHeader) throws IOExcep
randomAccessFile.seek(fileHeader.getOffsetLocalHeader());
}

@Override
public void close() throws IOException {
if (randomAccessFile != null) {
randomAccessFile.close();
}
}

protected void openRandomAccessFileForIndex(int zipFileIndex) throws IOException {
File nextSplitFile = getNextSplitFile(zipFileIndex);
if (!nextSplitFile.exists()) {
Expand All @@ -79,12 +85,18 @@ protected void openRandomAccessFileForIndex(int zipFileIndex) throws IOException
randomAccessFile = new RandomAccessFile(nextSplitFile, RandomAccessFileMode.READ.getValue());
}

protected abstract File getNextSplitFile(int zipFileIndex) throws IOException;
protected File getNextSplitFile(int zipFileIndex) throws IOException {
if (zipFileIndex == lastSplitZipFileNumber) {
return zipFile;
}

@Override
public void close() throws IOException {
if (randomAccessFile != null) {
randomAccessFile.close();
String currZipFileNameWithPath = zipFile.getCanonicalPath();
String extensionSubString = ".z0";
if (zipFileIndex >= 9) {
extensionSubString = ".z";
}

return new File(currZipFileNameWithPath.substring(0,
currZipFileNameWithPath.lastIndexOf(".")) + extensionSubString + (zipFileIndex + 1));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package net.lingala.zip4j.tasks;

import net.lingala.zip4j.io.inputstream.SplitInputStream;
import net.lingala.zip4j.io.inputstream.SplitFileInputStream;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.UnzipParameters;
Expand All @@ -17,7 +17,7 @@
public class ExtractAllFilesTask extends AbstractExtractFileTask<ExtractAllFilesTaskParameters> {

private final char[] password;
private SplitInputStream splitInputStream;
private SplitFileInputStream splitInputStream;

public ExtractAllFilesTask(ZipModel zipModel, char[] password, UnzipParameters unzipParameters,
AsyncTaskParameters asyncTaskParameters) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/net/lingala/zip4j/tasks/ExtractFileTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderUtil;
import net.lingala.zip4j.io.inputstream.SplitInputStream;
import net.lingala.zip4j.io.inputstream.SplitFileInputStream;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.UnzipParameters;
Expand All @@ -26,7 +26,7 @@
public class ExtractFileTask extends AbstractExtractFileTask<ExtractFileTaskParameters> {

private char[] password;
private SplitInputStream splitInputStream;
private SplitFileInputStream splitInputStream;

public ExtractFileTask(ZipModel zipModel, char[] password, UnzipParameters unzipParameters,
AsyncTaskParameters asyncTaskParameters) {
Expand Down
15 changes: 7 additions & 8 deletions src/main/java/net/lingala/zip4j/util/UnzipUtil.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package net.lingala.zip4j.util;

import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.inputstream.NumberedSplitInputStream;
import net.lingala.zip4j.io.inputstream.SplitInputStream;
import net.lingala.zip4j.io.inputstream.NumberedSplitFileInputStream;
import net.lingala.zip4j.io.inputstream.SplitFileInputStream;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.io.inputstream.ZipStandardSplitInputStream;
import net.lingala.zip4j.io.inputstream.ZipStandardSplitFileInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipModel;

Expand All @@ -21,7 +21,7 @@ public class UnzipUtil {
public static ZipInputStream createZipInputStream(ZipModel zipModel, FileHeader fileHeader, char[] password)
throws IOException {

SplitInputStream splitInputStream = null;
SplitFileInputStream splitInputStream = null;
try {
splitInputStream = createSplitInputStream(zipModel);
splitInputStream.prepareExtractionForFileHeader(fileHeader);
Expand Down Expand Up @@ -51,15 +51,14 @@ public static void applyFileAttributes(FileHeader fileHeader, File file) {
}
}

public static SplitInputStream createSplitInputStream(ZipModel zipModel) throws IOException {
public static SplitFileInputStream createSplitInputStream(ZipModel zipModel) throws IOException {
File zipFile = zipModel.getZipFile();

if (zipFile.getName().endsWith(InternalZipConstants.SEVEN_ZIP_SPLIT_FILE_EXTENSION_PATTERN)) {
return new NumberedSplitInputStream(zipModel.getZipFile(), true,
zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
return new NumberedSplitFileInputStream(zipModel.getZipFile());
}

return new ZipStandardSplitInputStream(zipModel.getZipFile(), zipModel.isSplitArchive(),
return new ZipStandardSplitFileInputStream(zipModel.getZipFile(), zipModel.isSplitArchive(),
zipModel.getEndOfCentralDirectoryRecord().getNumberOfThisDisk());
}

Expand Down
4 changes: 2 additions & 2 deletions src/test/java/net/lingala/zip4j/ExtractZipFileIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -516,15 +516,15 @@ public void testExtractZipFileCRCError() throws IOException {
@Test
public void testExtractZipFileOf7ZipFormatSplitWithoutEncryption() throws IOException {
List<File> filesToAddToZip = new ArrayList<>(FILES_TO_ADD);
filesToAddToZip.add(getTestFileFromResources("file_PDF_1MB.pdf"));
filesToAddToZip.add(0, getTestFileFromResources("file_PDF_1MB.pdf"));
File firstSplitFile = createZipFileAndSplit(filesToAddToZip, 102400, false, null);
verifyZipFileByExtractingAllFiles(firstSplitFile, outputFolder, 4);
}

@Test
public void testExtractZipFileOf7ZipFormatSplitWithAESEncryption() throws IOException {
List<File> filesToAddToZip = new ArrayList<>(FILES_TO_ADD);
filesToAddToZip.add(getTestFileFromResources("file_PDF_1MB.pdf"));
filesToAddToZip.add(0, getTestFileFromResources("file_PDF_1MB.pdf"));
File firstSplitFile = createZipFileAndSplit(filesToAddToZip, 102000, true, EncryptionMethod.AES);
verifyZipFileByExtractingAllFiles(firstSplitFile, PASSWORD, outputFolder, 4);
}
Expand Down
14 changes: 7 additions & 7 deletions src/test/java/net/lingala/zip4j/util/UnzipUtilIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import net.lingala.zip4j.AbstractIT;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.inputstream.NumberedSplitInputStream;
import net.lingala.zip4j.io.inputstream.SplitInputStream;
import net.lingala.zip4j.io.inputstream.ZipStandardSplitInputStream;
import net.lingala.zip4j.io.inputstream.NumberedSplitFileInputStream;
import net.lingala.zip4j.io.inputstream.SplitFileInputStream;
import net.lingala.zip4j.io.inputstream.ZipStandardSplitFileInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.testutils.TestUtils;
Expand Down Expand Up @@ -109,19 +109,19 @@ public void testCreateSplitInputStreamForNumberedSplitZipReturnsInstance() throw
ZipModel zipModel = createZipModel();
zipModel.setZipFile(zipFile);

SplitInputStream splitInputStream = UnzipUtil.createSplitInputStream(zipModel);
SplitFileInputStream splitInputStream = UnzipUtil.createSplitInputStream(zipModel);

assertThat(splitInputStream).isInstanceOf(NumberedSplitInputStream.class);
assertThat(splitInputStream).isInstanceOf(NumberedSplitFileInputStream.class);
}

@Test
public void testCreateSplitInputStreamForNonNumberedSplitZipReturnsInstance() throws IOException {
temporaryFolder.newFile(generatedZipFile.getName());
ZipModel zipModel = createZipModel();

SplitInputStream splitInputStream = UnzipUtil.createSplitInputStream(zipModel);
SplitFileInputStream splitInputStream = UnzipUtil.createSplitInputStream(zipModel);

assertThat(splitInputStream).isInstanceOf(ZipStandardSplitInputStream.class);
assertThat(splitInputStream).isInstanceOf(ZipStandardSplitFileInputStream.class);
}

private ZipFile createZipFile() throws ZipException {
Expand Down

0 comments on commit f8465d2

Please sign in to comment.