[Git][java-team/zip4j][upstream] New upstream version 2.9.1
Andrius Merkys (@merkys)
gitlab at salsa.debian.org
Wed Nov 24 06:51:57 GMT 2021
Andrius Merkys pushed to branch upstream at Debian Java Maintainers / zip4j
Commits:
bd9bc700 by Andrius Merkys at 2021-11-24T01:15:06-05:00
New upstream version 2.9.1
- - - - -
23 changed files:
- .travis.yml
- src/main/java/net/lingala/zip4j/ZipFile.java
- src/main/java/net/lingala/zip4j/crypto/AESDecrypter.java
- src/main/java/net/lingala/zip4j/headers/HeaderReader.java
- src/main/java/net/lingala/zip4j/headers/HeaderUtil.java
- src/main/java/net/lingala/zip4j/io/inputstream/ZipInputStream.java
- src/main/java/net/lingala/zip4j/io/outputstream/ZipOutputStream.java
- src/main/java/net/lingala/zip4j/model/FileHeader.java
- src/main/java/net/lingala/zip4j/tasks/AbstractExtractFileTask.java
- src/main/java/net/lingala/zip4j/tasks/ExtractFileTask.java
- + src/main/java/net/lingala/zip4j/util/PasswordCallback.java
- src/main/java/net/lingala/zip4j/util/UnzipUtil.java
- src/test/java/net/lingala/zip4j/ExtractZipFileIT.java
- src/test/java/net/lingala/zip4j/RemoveFilesFromZipIT.java
- src/test/java/net/lingala/zip4j/ZipFileTest.java
- src/test/java/net/lingala/zip4j/headers/HeaderReaderIT.java
- src/test/java/net/lingala/zip4j/headers/HeaderUtilTest.java
- src/test/java/net/lingala/zip4j/io/inputstream/ZipInputStreamIT.java
- src/test/java/net/lingala/zip4j/io/outputstream/ZipOutputStreamIT.java
- src/test/java/net/lingala/zip4j/testutils/TestUtils.java
- + src/test/resources/test-archives/archive-with-no-dir-entries.zip
- + src/test/resources/test-archives/dirs_with_extended_local_file_headers.zip
- + src/test/resources/test-archives/zip_with_duplicate_entries.zip
Changes:
=====================================
.travis.yml
=====================================
@@ -5,3 +5,7 @@ before_script:
script:
- travis_wait 45 mvn clean verify
+
+cache:
+ directories:
+ - $HOME/.m2
=====================================
src/main/java/net/lingala/zip4j/ZipFile.java
=====================================
@@ -500,6 +500,34 @@ public class ZipFile implements Closeable {
extractFile(fileHeader, destinationPath, null, unzipParameters);
}
+ /**
+ * Extracts a specific file from the zip file to the destination path.
+ * If destination path is invalid, then this method throws an exception.
+ * <br><br>
+ * If newFileName is not null or empty, newly created file name will be replaced by
+ * the value in newFileName. If this value is null, then the file name will be the
+ * value in FileHeader.getFileName. If file being extract is a directory, the directory name
+ * will be replaced with the newFileName
+ * <br><br>
+ * If fileHeader is a directory, this method extracts all files under this directory.
+ * <br/><br/>
+ * Any parameters that have to be considered during extraction can be passed in through unzipParameters
+ *
+ * @param fileHeader file header corresponding to the entry which has to be extracted
+ * @param destinationPath path to which the entries of the zip are to be extracted
+ * @param newFileName if not null, this will be the name given to the file upon extraction
+ * @param unzipParameters any parameters that have to be considered during extraction
+ * @throws ZipException when an issue occurs during extraction
+ */
+ public void extractFile(FileHeader fileHeader, String destinationPath, String newFileName,
+ UnzipParameters unzipParameters) throws ZipException {
+ if (fileHeader == null) {
+ throw new ZipException("input file header is null, cannot extract file");
+ }
+
+ extractFile(fileHeader.getFileName(), destinationPath, newFileName, unzipParameters);
+ }
+
/**
* Extracts a specific file from the zip file to the destination path.
* This method first finds the necessary file header from the input file name.
@@ -631,42 +659,6 @@ public class ZipFile implements Closeable {
throw new ZipException("file to extract is null or empty, cannot extract file");
}
- readZipInfo();
-
- FileHeader fileHeader = HeaderUtil.getFileHeader(zipModel, fileName);
-
- if (fileHeader == null) {
- throw new ZipException("No file found with name " + fileName + " in zip file", ZipException.Type.FILE_NOT_FOUND);
- }
-
- extractFile(fileHeader, destinationPath, newFileName, unzipParameters);
- }
-
- /**
- * Extracts a specific file from the zip file to the destination path.
- * If destination path is invalid, then this method throws an exception.
- * <br><br>
- * If newFileName is not null or empty, newly created file name will be replaced by
- * the value in newFileName. If this value is null, then the file name will be the
- * value in FileHeader.getFileName. If file being extract is a directory, the directory name
- * will be replaced with the newFileName
- * <br><br>
- * If fileHeader is a directory, this method extracts all files under this directory.
- * <br/><br/>
- * Any parameters that have to be considered during extraction can be passed in through unzipParameters
- *
- * @param fileHeader file header corresponding to the entry which has to be extracted
- * @param destinationPath path to which the entries of the zip are to be extracted
- * @param newFileName if not null, this will be the name given to the file upon extraction
- * @param unzipParameters any parameters that have to be considered during extraction
- * @throws ZipException when an issue occurs during extraction
- */
- public void extractFile(FileHeader fileHeader, String destinationPath, String newFileName,
- UnzipParameters unzipParameters) throws ZipException {
- if (fileHeader == null) {
- throw new ZipException("input file header is null, cannot extract file");
- }
-
if (!isStringNotNullAndNotEmpty(destinationPath)) {
throw new ZipException("destination path is empty or null, cannot extract file");
}
@@ -678,7 +670,7 @@ public class ZipFile implements Closeable {
readZipInfo();
new ExtractFileTask(zipModel, password, unzipParameters, buildAsyncParameters()).execute(
- new ExtractFileTaskParameters(destinationPath, fileHeader, newFileName, buildConfig()));
+ new ExtractFileTaskParameters(destinationPath, fileName, newFileName, buildConfig()));
}
/**
=====================================
src/main/java/net/lingala/zip4j/crypto/AESDecrypter.java
=====================================
@@ -25,6 +25,7 @@ import net.lingala.zip4j.model.enums.AesKeyStrength;
import java.util.Arrays;
import static net.lingala.zip4j.crypto.AesCipherUtil.prepareBuffAESIVBytes;
+import static net.lingala.zip4j.exception.ZipException.Type.WRONG_PASSWORD;
import static net.lingala.zip4j.util.InternalZipConstants.AES_BLOCK_SIZE;
/**
@@ -49,7 +50,7 @@ public class AESDecrypter implements Decrypter {
throws ZipException {
if (password == null || password.length <= 0) {
- throw new ZipException("empty or null password provided for AES decryption");
+ throw new ZipException("empty or null password provided for AES decryption", WRONG_PASSWORD);
}
final AesKeyStrength aesKeyStrength = aesExtraDataRecord.getAesKeyStrength();
=====================================
src/main/java/net/lingala/zip4j/headers/HeaderReader.java
=====================================
@@ -191,11 +191,6 @@ public class HeaderReader {
byte[] fileNameBuff = new byte[fileNameLength];
zip4jRaf.readFully(fileNameBuff);
String fileName = decodeStringWithCharset(fileNameBuff, fileHeader.isFileNameUTF8Encoded(), charset);
-
- if (fileName.contains(":\\")) {
- fileName = fileName.substring(fileName.indexOf(":\\") + 2);
- }
-
fileHeader.setFileName(fileName);
} else {
fileHeader.setFileName(null);
@@ -560,11 +555,6 @@ public class HeaderReader {
readFully(inputStream, fileNameBuf);
String fileName = decodeStringWithCharset(fileNameBuf, localFileHeader.isFileNameUTF8Encoded(), charset);
-
- if (fileName.contains(":" + System.getProperty("file.separator"))) {
- fileName = fileName.substring(fileName.indexOf(":" + System.getProperty("file.separator")) + 2);
- }
-
localFileHeader.setFileName(fileName);
localFileHeader.setDirectory(fileName.endsWith("/") || fileName.endsWith("\\"));
} else {
=====================================
src/main/java/net/lingala/zip4j/headers/HeaderUtil.java
=====================================
@@ -8,7 +8,6 @@ import net.lingala.zip4j.util.InternalZipConstants;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import static net.lingala.zip4j.util.InternalZipConstants.ZIP4J_DEFAULT_CHARSET;
@@ -65,14 +64,10 @@ public class HeaderUtil {
return zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
}
- public static List<FileHeader> getFileHeadersUnderDirectory(List<FileHeader> allFileHeaders, FileHeader rootFileHeader) {
- if (!rootFileHeader.isDirectory()) {
- return Collections.emptyList();
- }
-
+ public static List<FileHeader> getFileHeadersUnderDirectory(List<FileHeader> allFileHeaders, String fileName) {
List<FileHeader> fileHeadersUnderDirectory = new ArrayList<>();
for (FileHeader fileHeader : allFileHeaders) {
- if (fileHeader.getFileName().startsWith(rootFileHeader.getFileName())) {
+ if (fileHeader.getFileName().startsWith(fileName)) {
fileHeadersUnderDirectory.add(fileHeader);
}
}
=====================================
src/main/java/net/lingala/zip4j/io/inputstream/ZipInputStream.java
=====================================
@@ -16,6 +16,9 @@
package net.lingala.zip4j.io.inputstream;
+import static net.lingala.zip4j.util.InternalZipConstants.MIN_BUFF_SIZE;
+import static net.lingala.zip4j.util.Zip4jUtil.getCompressionMethod;
+
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderReader;
import net.lingala.zip4j.headers.HeaderSignature;
@@ -28,6 +31,7 @@ import net.lingala.zip4j.model.enums.AesVersion;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.InternalZipConstants;
+import net.lingala.zip4j.util.PasswordCallback;
import java.io.IOException;
import java.io.InputStream;
@@ -36,15 +40,13 @@ import java.nio.charset.Charset;
import java.util.List;
import java.util.zip.CRC32;
-import static net.lingala.zip4j.util.InternalZipConstants.MIN_BUFF_SIZE;
-import static net.lingala.zip4j.util.Zip4jUtil.getCompressionMethod;
-
public class ZipInputStream extends InputStream {
private PushbackInputStream inputStream;
private DecompressedInputStream decompressedInputStream;
private HeaderReader headerReader = new HeaderReader();
private char[] password;
+ private PasswordCallback passwordCallback;
private LocalFileHeader localFileHeader;
private CRC32 crc32 = new CRC32();
private byte[] endOfEntryBuffer;
@@ -54,37 +56,56 @@ public class ZipInputStream extends InputStream {
private boolean entryEOFReached = false;
public ZipInputStream(InputStream inputStream) {
- this(inputStream, null, (Charset) null);
+ this(inputStream, (char[]) null, (Charset) null);
}
public ZipInputStream(InputStream inputStream, Charset charset) {
- this(inputStream, null, charset);
+ this(inputStream, (char[]) null, charset);
}
public ZipInputStream(InputStream inputStream, char[] password) {
this(inputStream, password, (Charset) null);
}
+ public ZipInputStream(InputStream inputStream, PasswordCallback passwordCallback) {
+ this(inputStream, passwordCallback, (Charset) null);
+ }
+
public ZipInputStream(InputStream inputStream, char[] password, Charset charset) {
this(inputStream, password, new Zip4jConfig(charset, InternalZipConstants.BUFF_SIZE));
}
+ public ZipInputStream(InputStream inputStream, PasswordCallback passwordCallback, Charset charset) {
+ this(inputStream, passwordCallback, new Zip4jConfig(charset, InternalZipConstants.BUFF_SIZE));
+ }
+
public ZipInputStream(InputStream inputStream, char[] password, Zip4jConfig zip4jConfig) {
+ this(inputStream, password, null, zip4jConfig);
+ }
+
+ public ZipInputStream(InputStream inputStream, PasswordCallback passwordCallback, Zip4jConfig zip4jConfig) {
+ this(inputStream, null, passwordCallback, zip4jConfig);
+ }
+
+ private ZipInputStream(InputStream inputStream, char[] password, PasswordCallback passwordCallback, Zip4jConfig zip4jConfig) {
if (zip4jConfig.getBufferSize() < InternalZipConstants.MIN_BUFF_SIZE) {
throw new IllegalArgumentException("Buffer size cannot be less than " + MIN_BUFF_SIZE + " bytes");
}
this.inputStream = new PushbackInputStream(inputStream, zip4jConfig.getBufferSize());
this.password = password;
+ this.passwordCallback = passwordCallback;
this.zip4jConfig = zip4jConfig;
}
public LocalFileHeader getNextEntry() throws IOException {
- return getNextEntry(null);
+ return getNextEntry(null, true);
}
- public LocalFileHeader getNextEntry(FileHeader fileHeader) throws IOException {
- if (localFileHeader != null) {
+ public LocalFileHeader getNextEntry(FileHeader fileHeader, boolean readUntilEndOfCurrentEntryIfOpen)
+ throws IOException {
+
+ if (localFileHeader != null && readUntilEndOfCurrentEntryIfOpen) {
readUntilEndOfEntry();
}
@@ -94,6 +115,10 @@ public class ZipInputStream extends InputStream {
return null;
}
+ if (localFileHeader.isEncrypted() && password == null && passwordCallback != null) {
+ setPassword(passwordCallback.getPassword());
+ }
+
verifyLocalFileHeader(localFileHeader);
crc32.reset();
@@ -152,10 +177,6 @@ public class ZipInputStream extends InputStream {
return -1;
}
- if (localFileHeader.isDirectory()) {
- return -1;
- }
-
try {
int readLen = decompressedInputStream.read(b, off, len);
=====================================
src/main/java/net/lingala/zip4j/io/outputstream/ZipOutputStream.java
=====================================
@@ -20,6 +20,7 @@ import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.zip.CRC32;
+import static net.lingala.zip4j.util.FileUtils.isZipEntryDirectory;
import static net.lingala.zip4j.util.InternalZipConstants.BUFF_SIZE;
import static net.lingala.zip4j.util.InternalZipConstants.MIN_BUFF_SIZE;
@@ -72,12 +73,19 @@ public class ZipOutputStream extends OutputStream {
public void putNextEntry(ZipParameters zipParameters) throws IOException {
verifyZipParameters(zipParameters);
- initializeAndWriteFileHeader(zipParameters);
+
+ ZipParameters clonedZipParameters = new ZipParameters(zipParameters);
+ if (isZipEntryDirectory(zipParameters.getFileNameInZip())) {
+ clonedZipParameters.setWriteExtendedLocalFileHeader(false);
+ clonedZipParameters.setCompressionMethod(CompressionMethod.STORE);
+ clonedZipParameters.setEncryptFiles(false);
+ }
+ initializeAndWriteFileHeader(clonedZipParameters);
//Initialisation of below compressedOutputStream should happen after writing local file header
//because local header data should be written first and then the encryption header data
//and below initialisation writes encryption header data
- compressedOutputStream = initializeCompressedOutputStream(zipParameters);
+ compressedOutputStream = initializeCompressedOutputStream(clonedZipParameters);
this.entryClosed = false;
}
@@ -220,7 +228,7 @@ public class ZipOutputStream extends OutputStream {
private void verifyZipParameters(ZipParameters zipParameters) {
if (zipParameters.getCompressionMethod() == CompressionMethod.STORE
&& zipParameters.getEntrySize() < 0
- && !isEntryDirectory(zipParameters.getFileNameInZip())
+ && !isZipEntryDirectory(zipParameters.getFileNameInZip())
&& zipParameters.isWriteExtendedLocalFileHeader()) {
throw new IllegalArgumentException("uncompressed size should be set for zip entries of compression type store");
}
@@ -235,8 +243,4 @@ public class ZipOutputStream extends OutputStream {
return fileHeader.getAesExtraDataRecord().getAesVersion().equals(AesVersion.ONE);
}
-
- private boolean isEntryDirectory(String entryName) {
- return entryName.endsWith("/") || entryName.endsWith("\\");
- }
}
=====================================
src/main/java/net/lingala/zip4j/model/FileHeader.java
=====================================
@@ -18,6 +18,8 @@ package net.lingala.zip4j.model;
import net.lingala.zip4j.headers.HeaderSignature;
+import java.util.Objects;
+
public class FileHeader extends AbstractFileHeader {
private int versionMadeBy;
@@ -92,4 +94,26 @@ public class FileHeader extends AbstractFileHeader {
public String toString() {
return getFileName();
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
+ FileHeader that = (FileHeader) o;
+ return determineOffsetOfLocalFileHeader(this) == determineOffsetOfLocalFileHeader(that);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getFileName(), determineOffsetOfLocalFileHeader(this));
+ }
+
+ private long determineOffsetOfLocalFileHeader(FileHeader fileHeader) {
+ if (fileHeader.getZip64ExtendedInfo() != null) {
+ return fileHeader.getZip64ExtendedInfo().getOffsetLocalHeader();
+ }
+
+ return fileHeader.getOffsetLocalHeader();
+ }
}
=====================================
src/main/java/net/lingala/zip4j/tasks/AbstractExtractFileTask.java
=====================================
@@ -18,7 +18,6 @@ import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.regex.Matcher;
import static net.lingala.zip4j.util.InternalZipConstants.FILE_SEPARATOR;
@@ -140,7 +139,7 @@ public abstract class AbstractExtractFileTask<T> extends AsyncZipTask<T> {
"Zip4j does not support Strong Encryption, as this is patented.");
}
- LocalFileHeader localFileHeader = zipInputStream.getNextEntry(fileHeader);
+ LocalFileHeader localFileHeader = zipInputStream.getNextEntry(fileHeader, false);
if (localFileHeader == null) {
throw new ZipException("Could not read corresponding local file header for file header: "
@@ -159,21 +158,13 @@ public abstract class AbstractExtractFileTask<T> extends AsyncZipTask<T> {
}
private File determineOutputFile(FileHeader fileHeader, String outputPath, String newFileName) {
- String outputFileName;
+ String outputFileName = fileHeader.getFileName();
if (Zip4jUtil.isStringNotNullAndNotEmpty(newFileName)) {
outputFileName = newFileName;
- } else {
- // replace all slashes with file separator
- outputFileName = getFileNameWithSystemFileSeparators(fileHeader.getFileName());
}
-
return new File(outputPath + FILE_SEPARATOR + outputFileName);
}
- private String getFileNameWithSystemFileSeparators(String fileNameToReplace) {
- return fileNameToReplace.replaceAll("[/\\\\]", Matcher.quoteReplacement(FILE_SEPARATOR));
- }
-
@Override
protected ProgressMonitor.Task getTask() {
return ProgressMonitor.Task.EXTRACT_ENTRY;
=====================================
src/main/java/net/lingala/zip4j/tasks/ExtractFileTask.java
=====================================
@@ -1,5 +1,7 @@
package net.lingala.zip4j.tasks;
+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.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
@@ -8,6 +10,7 @@ import net.lingala.zip4j.model.Zip4jConfig;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.tasks.ExtractFileTask.ExtractFileTaskParameters;
+import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import net.lingala.zip4j.util.UnzipUtil;
import net.lingala.zip4j.util.Zip4jUtil;
@@ -16,6 +19,7 @@ import java.io.IOException;
import java.util.Collections;
import java.util.List;
+import static net.lingala.zip4j.exception.ZipException.Type.FILE_NOT_FOUND;
import static net.lingala.zip4j.headers.HeaderUtil.getFileHeadersUnderDirectory;
import static net.lingala.zip4j.headers.HeaderUtil.getTotalUncompressedSizeOfAllFileHeaders;
@@ -34,12 +38,12 @@ public class ExtractFileTask extends AbstractExtractFileTask<ExtractFileTaskPara
protected void executeTask(ExtractFileTaskParameters taskParameters, ProgressMonitor progressMonitor)
throws IOException {
- try(ZipInputStream zipInputStream =
- createZipInputStream(taskParameters.fileHeader, taskParameters.zip4jConfig)) {
- List<FileHeader> fileHeadersUnderDirectory = getFileHeadersToExtract(taskParameters.fileHeader);
+ List<FileHeader> fileHeadersUnderDirectory = getFileHeadersToExtract(taskParameters.fileToExtract);
+ try(ZipInputStream zipInputStream = createZipInputStream(taskParameters.zip4jConfig)) {
byte[] readBuff = new byte[taskParameters.zip4jConfig.getBufferSize()];
for (FileHeader fileHeader : fileHeadersUnderDirectory) {
- String newFileName = determineNewFileName(taskParameters.newFileName, taskParameters.fileHeader, fileHeader);
+ splitInputStream.prepareExtractionForFileHeader(fileHeader);
+ String newFileName = determineNewFileName(taskParameters.newFileName, taskParameters.fileToExtract, fileHeader);
extractFile(zipInputStream, fileHeader, taskParameters.outputPath, newFileName, progressMonitor, readBuff);
}
} finally {
@@ -50,33 +54,35 @@ public class ExtractFileTask extends AbstractExtractFileTask<ExtractFileTaskPara
}
@Override
- protected long calculateTotalWork(ExtractFileTaskParameters taskParameters) {
- List<FileHeader> fileHeadersUnderDirectory = getFileHeadersToExtract(taskParameters.fileHeader);
+ protected long calculateTotalWork(ExtractFileTaskParameters taskParameters) throws ZipException {
+ List<FileHeader> fileHeadersUnderDirectory = getFileHeadersToExtract(taskParameters.fileToExtract);
return getTotalUncompressedSizeOfAllFileHeaders(fileHeadersUnderDirectory);
}
- private List<FileHeader> getFileHeadersToExtract(FileHeader rootFileHeader) {
- if (!rootFileHeader.isDirectory()) {
- return Collections.singletonList(rootFileHeader);
+ private List<FileHeader> getFileHeadersToExtract(String fileNameToExtract) throws ZipException {
+ if (!FileUtils.isZipEntryDirectory(fileNameToExtract)) {
+ FileHeader fileHeader = HeaderUtil.getFileHeader(getZipModel(), fileNameToExtract);
+ if (fileHeader == null) {
+ throw new ZipException("No file found with name " + fileNameToExtract + " in zip file", FILE_NOT_FOUND);
+ }
+ return Collections.singletonList(fileHeader);
}
- return getFileHeadersUnderDirectory(
- getZipModel().getCentralDirectory().getFileHeaders(), rootFileHeader);
+ return getFileHeadersUnderDirectory(getZipModel().getCentralDirectory().getFileHeaders(), fileNameToExtract);
}
- private ZipInputStream createZipInputStream(FileHeader fileHeader, Zip4jConfig zip4jConfig) throws IOException {
+ private ZipInputStream createZipInputStream(Zip4jConfig zip4jConfig) throws IOException {
splitInputStream = UnzipUtil.createSplitInputStream(getZipModel());
- splitInputStream.prepareExtractionForFileHeader(fileHeader);
return new ZipInputStream(splitInputStream, password, zip4jConfig);
}
- private String determineNewFileName(String newFileName, FileHeader fileHeaderToExtract,
+ private String determineNewFileName(String newFileName, String fileNameToExtract,
FileHeader fileHeaderBeingExtracted) {
if (!Zip4jUtil.isStringNotNullAndNotEmpty(newFileName)) {
return newFileName;
}
- if (!fileHeaderToExtract.isDirectory()) {
+ if (!FileUtils.isZipEntryDirectory(fileNameToExtract)) {
return newFileName;
}
@@ -85,20 +91,19 @@ public class ExtractFileTask extends AbstractExtractFileTask<ExtractFileTaskPara
fileSeparator = "";
}
- return fileHeaderBeingExtracted.getFileName().replaceFirst(fileHeaderToExtract.getFileName(),
- newFileName + fileSeparator);
+ return fileHeaderBeingExtracted.getFileName().replaceFirst(fileNameToExtract, newFileName + fileSeparator);
}
public static class ExtractFileTaskParameters extends AbstractZipTaskParameters {
private String outputPath;
- private FileHeader fileHeader;
+ private String fileToExtract;
private String newFileName;
- public ExtractFileTaskParameters(String outputPath, FileHeader fileHeader, String newFileName,
+ public ExtractFileTaskParameters(String outputPath, String fileToExtract, String newFileName,
Zip4jConfig zip4jConfig) {
super(zip4jConfig);
this.outputPath = outputPath;
- this.fileHeader = fileHeader;
+ this.fileToExtract = fileToExtract;
this.newFileName = newFileName;
}
}
=====================================
src/main/java/net/lingala/zip4j/util/PasswordCallback.java
=====================================
@@ -0,0 +1,6 @@
+package net.lingala.zip4j.util;
+
+public interface PasswordCallback {
+
+ char[] getPassword();
+}
=====================================
src/main/java/net/lingala/zip4j/util/UnzipUtil.java
=====================================
@@ -27,7 +27,7 @@ public class UnzipUtil {
splitInputStream.prepareExtractionForFileHeader(fileHeader);
ZipInputStream zipInputStream = new ZipInputStream(splitInputStream, password);
- if (zipInputStream.getNextEntry(fileHeader) == null) {
+ if (zipInputStream.getNextEntry(fileHeader, false) == null) {
throw new ZipException("Could not locate local file header for corresponding file header");
}
=====================================
src/test/java/net/lingala/zip4j/ExtractZipFileIT.java
=====================================
@@ -587,6 +587,22 @@ public class ExtractZipFileIT extends AbstractIT {
ZipFileVerifier.verifyFileContent(TestUtils.getTestFileFromResources("öüäöäö/asöäööl"), outputFile);
}
+ @Test
+ public void testExtractFileWhichIsAFolderExtractsContentsEvenWhenFolderEntryIsNotInZip() throws IOException {
+ ZipFile zipFile = new ZipFile(getTestArchiveFromResources("archive-with-no-dir-entries.zip"));
+ String outputFolderPath = outputFolder.getPath();
+
+ zipFile.extractFile("items/", outputFolderPath);
+
+ List<File> extractedFiles = FileUtils.getFilesInDirectoryRecursive(outputFolder, false, false);
+ assertThat(extractedFiles).isNotEmpty();
+ assertThat(extractedFiles).hasSize(3);
+ assertThat(extractedFiles).contains(
+ Paths.get(outputFolderPath, "items").toFile(),
+ Paths.get(outputFolderPath, "items/subitems").toFile(),
+ Paths.get(outputFolderPath, "items/subitems/beta.txt").toFile());
+ }
+
@Test
public void testExtractJarFileWithFileHeaderCompressedSize2() throws IOException {
extractFile(TestUtils.getTestArchiveFromResources("jar-dir-fh-entry-size-2.jar"));
@@ -641,6 +657,27 @@ public class ExtractZipFileIT extends AbstractIT {
}
}
+ @Test
+ public void testExtractZipFileByFileNameWhichTheDirectoryEntryAtTheEndOfCentralDirectoryExtractsSuccessfully()
+ throws ZipException {
+ ZipFile zipFile = new ZipFile(generatedZipFile);
+ zipFile.addFolder(getTestFileFromResources("/"));
+
+ zipFile.extractFile("test-files/", outputFolder.getPath());
+ zipFile = new ZipFile(generatedZipFile);
+ zipFile.extractFile("test-files/", outputFolder.getPath());
+ }
+
+ @Test
+ public void testExtractZipFileThrowsExceptionOfTypeWrongPasswordForNullAesPassword() throws ZipException {
+ testExtractZipFileThrowsExceptionOfTypeWrongPasswordForNullOrEmptyAesPassword(null);
+ }
+
+ @Test
+ public void testExtractZipFileThrowsExceptionOfTypeWrongPasswordForEmptyAesPassword() throws ZipException {
+ testExtractZipFileThrowsExceptionOfTypeWrongPasswordForNullOrEmptyAesPassword("".toCharArray());
+ }
+
private void addFileToZip(ZipFile zipFile, String fileName, EncryptionMethod encryptionMethod, String password) throws ZipException {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(encryptionMethod != null);
@@ -768,4 +805,15 @@ public class ExtractZipFileIT extends AbstractIT {
}
return regularFiles;
}
+
+ private void testExtractZipFileThrowsExceptionOfTypeWrongPasswordForNullOrEmptyAesPassword(char[] password) throws ZipException {
+ ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
+ addFileToZip(zipFile, "sample.pdf", EncryptionMethod.AES, new String(PASSWORD));
+
+ expectedException.expect(ZipException.class);
+ expectedException.expectMessage("empty or null password provided for AES decryption");
+
+ zipFile = new ZipFile(generatedZipFile, password);
+ zipFile.extractAll(outputFolder.getPath());
+ }
}
=====================================
src/test/java/net/lingala/zip4j/RemoveFilesFromZipIT.java
=====================================
@@ -234,6 +234,18 @@ public class RemoveFilesFromZipIT extends AbstractIT {
assertZipFileDoesNotContainsFileByName(new ZipFile(zipFileUnderTest), fileNameToRemove);
}
+ @Test
+ public void testRemoveEntryFromAZipFileWithDuplicateEntriesRemovesSuccessfully() throws IOException {
+ TestUtils.copyFile(TestUtils.getTestArchiveFromResources("zip_with_duplicate_entries.zip"), generatedZipFile);
+ ZipFile zipFile = new ZipFile(generatedZipFile);
+ int actualNumberOfEntries = zipFile.getFileHeaders().size();
+ zipFile.removeFile("sample.pdf");
+
+ zipFile = new ZipFile(generatedZipFile);
+ assertThat(zipFile.getFileHeaders().size()).isEqualTo(actualNumberOfEntries - 1);
+ assertZipFileDoesNotContainsFileByName(zipFile, "sample.pdf");
+ }
+
private void testRemoveEntryFromZipWhichHasCentralDirEntriesInDifferentOrderThanLocalEntries(
String fileNameToRemove) throws IOException {
TestUtils.copyFile(TestUtils.getTestArchiveFromResources("cen_dir_entries_diff_order_as_local_entries.zip"),
=====================================
src/test/java/net/lingala/zip4j/ZipFileTest.java
=====================================
@@ -378,7 +378,7 @@ public class ZipFileTest {
expectedException.expectMessage("destination path is empty or null, cannot extract file");
expectedException.expect(ZipException.class);
- zipFile.extractFile(new FileHeader(), null);
+ zipFile.extractFile(createFileHeader("SOME_NAME"), null);
}
@Test
@@ -386,7 +386,7 @@ public class ZipFileTest {
expectedException.expectMessage("destination path is empty or null, cannot extract file");
expectedException.expect(ZipException.class);
- zipFile.extractFile(new FileHeader(), "");
+ zipFile.extractFile(createFileHeader("SOME_NAME"), "");
}
@Test
@@ -397,7 +397,7 @@ public class ZipFileTest {
expectedException.expectMessage("invalid operation - Zip4j is in busy state");
expectedException.expect(ZipException.class);
- zipFile.extractFile(new FileHeader(), "SOME_DESTINATION");
+ zipFile.extractFile(createFileHeader("SOME_NAME"), "SOME_DESTINATION");
}
@Test
@@ -649,4 +649,10 @@ public class ZipFileTest {
when(folder.canRead()).thenReturn(true);
return folder;
}
+
+ private FileHeader createFileHeader(String fileName) {
+ FileHeader fileHeader = new FileHeader();
+ fileHeader.setFileName(fileName);
+ return fileHeader;
+ }
}
=====================================
src/test/java/net/lingala/zip4j/headers/HeaderReaderIT.java
=====================================
@@ -116,22 +116,6 @@ public class HeaderReaderIT extends AbstractIT {
}
}
- @Test
- public void testReadAllWithFileNameContainsWindowsDriveExcludesIt() throws IOException {
- String fileName = "C:\\test.txt";
- ZipModel actualZipModel = generateZipModel(1);
- actualZipModel.getCentralDirectory().getFileHeaders().get(0).setFileName(fileName);
- File headersFile = writeZipHeaders(actualZipModel);
- actualZipModel.setZipFile(headersFile);
-
- try(RandomAccessFile randomAccessFile = new RandomAccessFile(actualZipModel.getZipFile(),
- RandomAccessFileMode.READ.getValue())) {
- ZipModel readZipModel = headerReader.readAllHeaders(randomAccessFile, buildDefaultConfig());
- FileHeader fileHeader = readZipModel.getCentralDirectory().getFileHeaders().get(0);
- assertThat(fileHeader.getFileName()).isEqualTo("test.txt");
- }
- }
-
@Test
public void testReadAllWithoutFileNameWritesNull() throws IOException {
ZipModel actualZipModel = generateZipModel(1);
@@ -438,4 +422,4 @@ public class HeaderReaderIT extends AbstractIT {
return headersFile;
}
}
-}
\ No newline at end of file
+}
=====================================
src/test/java/net/lingala/zip4j/headers/HeaderUtilTest.java
=====================================
@@ -194,10 +194,8 @@ public class HeaderUtilTest {
@Test
public void testGetFileHeadersUnderDirectoryWhenNotDirectoryReturnsEmptyList() {
List<FileHeader> allFileHeaders = generateFileHeaderWithFileNames("header", 5);
- FileHeader rootFileHeader = generateFileHeader("some_name");
- rootFileHeader.setDirectory(false);
- assertThat(HeaderUtil.getFileHeadersUnderDirectory(allFileHeaders, rootFileHeader)).isEmpty();
+ assertThat(HeaderUtil.getFileHeadersUnderDirectory(allFileHeaders, "some_name")).isEmpty();
}
@Test
@@ -205,10 +203,8 @@ public class HeaderUtilTest {
List<FileHeader> allFileHeaders = generateFileHeaderWithFileNames("some_name/header", 5);
allFileHeaders.add(generateFileHeader("some_name/"));
allFileHeaders.add(generateFileHeader("some_other_name.txt"));
- FileHeader rootFileHeader = generateFileHeader("some_name/");
- rootFileHeader.setDirectory(true);
- List<FileHeader> filHeadersUnderDirectory = HeaderUtil.getFileHeadersUnderDirectory(allFileHeaders, rootFileHeader);
+ List<FileHeader> filHeadersUnderDirectory = HeaderUtil.getFileHeadersUnderDirectory(allFileHeaders, "some_name/");
assertThat(filHeadersUnderDirectory).hasSize(6);
for (FileHeader fileHeader : filHeadersUnderDirectory) {
assertThat(fileHeader)
=====================================
src/test/java/net/lingala/zip4j/io/inputstream/ZipInputStreamIT.java
=====================================
@@ -49,7 +49,7 @@ public class ZipInputStreamIT extends AbstractIT {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Buffer size cannot be less than " + MIN_BUFF_SIZE + " bytes");
- new ZipInputStream(inputStream, null, zip4jConfig);
+ new ZipInputStream(inputStream, (char[]) null, zip4jConfig);
}
@Test
@@ -97,55 +97,55 @@ public class ZipInputStreamIT extends AbstractIT {
@Test
public void testExtractDeflateWithAesEncryption256AndV1() throws IOException {
File createdZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD, AesVersion.ONE);
- extractZipFileWithInputStreams(createdZipFile, PASSWORD, InternalZipConstants.BUFF_SIZE, AesVersion.ONE);
+ extractZipFileWithInputStreams(createdZipFile, PASSWORD);
}
@Test
public void testExtractWithReadLengthLessThan16WithAesAndStoreCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.STORE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
- extractZipFileWithInputStreams(createZipFile, PASSWORD, 15, AesVersion.TWO);
+ extractZipFileWithInputStreams(createZipFile, PASSWORD, 15);
}
@Test
public void testExtractWithReadLengthLessThan16WithAesAndDeflateCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
- extractZipFileWithInputStreams(createZipFile, PASSWORD, 15, AesVersion.TWO);
+ extractZipFileWithInputStreams(createZipFile, PASSWORD, 15);
}
@Test
public void testExtractWithReadLengthLessThan16WithZipCryptoAndStoreCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD, null, PASSWORD);
- extractZipFileWithInputStreams(createZipFile, PASSWORD, 12, null);
+ extractZipFileWithInputStreams(createZipFile, PASSWORD, 12);
}
@Test
public void testExtractWithReadLengthLessThan16WithZipCryptoAndDeflateCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD, null, PASSWORD);
- extractZipFileWithInputStreams(createZipFile, PASSWORD, 5, null);
+ extractZipFileWithInputStreams(createZipFile, PASSWORD, 5);
}
@Test
public void testExtractWithReadLengthGreaterThanButNotMultipleOf16WithAesAndStoreCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.STORE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
- extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 4) + 1, AesVersion.TWO);
+ extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 4) + 1);
}
@Test
public void testExtractWithReadLengthGreaterThanButNotMultipleOf16WithAesAndDeflateCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256, PASSWORD);
- extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 8) - 10, AesVersion.TWO);
+ extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 8) - 10);
}
@Test
public void testExtractWithReadLengthGreaterThanButNotMultipleOf16WithZipCryptoAndStoreCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD, null, PASSWORD);
- extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 2) - 6, null);
+ extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 2) - 6);
}
@Test
public void testExtractWithReadLengthGreaterThanButNotMultipleOf16WithZipCryptoAndDeflateCompression() throws IOException {
File createZipFile = createZipFile(CompressionMethod.DEFLATE, true, EncryptionMethod.ZIP_STANDARD, null, PASSWORD);
- extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 10) - 11, null);
+ extractZipFileWithInputStreams(createZipFile, PASSWORD, (16 * 10) - 11);
}
@Test
@@ -295,12 +295,22 @@ public class ZipInputStreamIT extends AbstractIT {
}
}
+ @Test
+ public void testExtractZipFileWithDirectoriesContainingExtendedLocalFileHeader() throws IOException {
+ extractZipFileWithInputStreams(TestUtils.getTestArchiveFromResources("dirs_with_extended_local_file_headers.zip"),
+ null, InternalZipConstants.BUFF_SIZE, false, 2);
+ }
+
private void extractZipFileWithInputStreams(File zipFile, char[] password) throws IOException {
- extractZipFileWithInputStreams(zipFile, password, 4096, AesVersion.TWO);
+ extractZipFileWithInputStreams(zipFile, password, InternalZipConstants.BUFF_SIZE);
}
- private void extractZipFileWithInputStreams(File zipFile, char[] password, int bufferLength, AesVersion aesVersion)
- throws IOException {
+ private void extractZipFileWithInputStreams(File zipFile, char[] password, int bufferLength) throws IOException {
+ extractZipFileWithInputStreams(zipFile, password, bufferLength, true, FILES_TO_ADD.size());
+ }
+
+ private void extractZipFileWithInputStreams(File zipFile, char[] password, int bufferLength,
+ boolean verifyFileContents, int numberOfEntriesExpected) throws IOException {
LocalFileHeader localFileHeader;
int readLen;
byte[] readBuffer = new byte[bufferLength];
@@ -316,13 +326,15 @@ public class ZipInputStreamIT extends AbstractIT {
}
}
verifyLocalFileHeader(localFileHeader);
- verifyFileContent(getTestFileFromResources(localFileHeader.getFileName()), extractedFile);
+ if (verifyFileContents) {
+ verifyFileContent(getTestFileFromResources(localFileHeader.getFileName()), extractedFile);
+ }
numberOfEntriesExtracted++;
}
}
}
- assertThat(numberOfEntriesExtracted).isEqualTo(FILES_TO_ADD.size());
+ assertThat(numberOfEntriesExtracted).isEqualTo(numberOfEntriesExpected);
}
private void verifyLocalFileHeader(LocalFileHeader localFileHeader) {
=====================================
src/test/java/net/lingala/zip4j/io/outputstream/ZipOutputStreamIT.java
=====================================
@@ -238,6 +238,21 @@ public class ZipOutputStreamIT extends AbstractIT {
verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 1);
}
+ @Test
+ public void testCreateZipFileWithDirectoriesAndExtendedLocalFileHeaderIsSuccessful() throws IOException {
+ try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(generatedZipFile))) {
+ putNextEntryAndCloseEntry(zos, "dir1/");
+ putNextEntryAndCloseEntry(zos, "dir2/");
+ }
+
+ ZipFile zipFile = new ZipFile(generatedZipFile);
+ List<FileHeader> fileHeaders = zipFile.getFileHeaders();
+ for (FileHeader fileHeader : fileHeaders) {
+ assertThat(fileHeader.isDataDescriptorExists()).isFalse();
+ }
+ verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 2);
+ }
+
private void testZipOutputStream(CompressionMethod compressionMethod, boolean encrypt,
EncryptionMethod encryptionMethod, AesKeyStrength aesKeyStrength,
AesVersion aesVersion)
@@ -434,4 +449,11 @@ public class ZipOutputStreamIT extends AbstractIT {
return zipFile;
}
+
+ private void putNextEntryAndCloseEntry(ZipOutputStream zipOutputStream, String fileName) throws IOException {
+ ZipParameters zipParameters = new ZipParameters();
+ zipParameters.setFileNameInZip(fileName);
+ zipOutputStream.putNextEntry(zipParameters);
+ zipOutputStream.closeEntry();
+ }
}
=====================================
src/test/java/net/lingala/zip4j/testutils/TestUtils.java
=====================================
@@ -13,6 +13,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
+import java.net.URL;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -164,8 +165,11 @@ public class TestUtils {
private static File getFileFromResources(String parentFolder, String fileName) {
try {
String path = "/" + parentFolder + "/" + fileName;
- String utfDecodedFilePath = URLDecoder.decode(TestUtils.class.getResource(path).getFile(),
- InternalZipConstants.CHARSET_UTF_8.toString());
+ URL fileUrl = TestUtils.class.getResource(path);
+ if (fileUrl == null) {
+ throw new RuntimeException("File not found " + path);
+ }
+ String utfDecodedFilePath = URLDecoder.decode(fileUrl.getFile(), InternalZipConstants.CHARSET_UTF_8.toString());
return new File(utfDecodedFilePath);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
=====================================
src/test/resources/test-archives/archive-with-no-dir-entries.zip
=====================================
Binary files /dev/null and b/src/test/resources/test-archives/archive-with-no-dir-entries.zip differ
=====================================
src/test/resources/test-archives/dirs_with_extended_local_file_headers.zip
=====================================
Binary files /dev/null and b/src/test/resources/test-archives/dirs_with_extended_local_file_headers.zip differ
=====================================
src/test/resources/test-archives/zip_with_duplicate_entries.zip
=====================================
Binary files /dev/null and b/src/test/resources/test-archives/zip_with_duplicate_entries.zip differ
View it on GitLab: https://salsa.debian.org/java-team/zip4j/-/commit/bd9bc700acea7482af924645ba21c6dcbe3dc40d
--
View it on GitLab: https://salsa.debian.org/java-team/zip4j/-/commit/bd9bc700acea7482af924645ba21c6dcbe3dc40d
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20211124/d2e36415/attachment.htm>
More information about the pkg-java-commits
mailing list