From 76db682d631052bb1e842a6570fc00cb00c28264 Mon Sep 17 00:00:00 2001 From: Srikanth Reddy Lingala Date: Thu, 21 May 2020 12:15:12 +0200 Subject: [PATCH] #183 fix versionMadeBy and versionNeededToExtract header values --- .../zip4j/headers/FileHeaderFactory.java | 10 +- .../lingala/zip4j/headers/VersionMadeBy.java | 18 +++ .../zip4j/headers/VersionNeededToExtract.java | 19 +++ .../io/outputstream/ZipOutputStream.java | 2 +- .../lingala/zip4j/model/ZipParameters.java | 17 +++ .../net/lingala/zip4j/util/FileUtils.java | 5 + .../lingala/zip4j/util/ZipVersionUtils.java | 39 ++++++ .../net/lingala/zip4j/AddFilesToZipIT.java | 15 +++ .../zip4j/headers/FileHeaderFactoryTest.java | 125 +++++++++++++----- .../lingala/zip4j/headers/HeaderReaderIT.java | 4 +- .../zip4j/util/FileUtilsTestLinuxAndMac.java | 5 + .../zip4j/util/FileUtilsTestWindows.java | 5 + .../zip4j/util/ZipVersionUtilsTest.java | 79 +++++++++++ 13 files changed, 308 insertions(+), 35 deletions(-) create mode 100644 src/main/java/net/lingala/zip4j/headers/VersionMadeBy.java create mode 100644 src/main/java/net/lingala/zip4j/headers/VersionNeededToExtract.java create mode 100644 src/main/java/net/lingala/zip4j/util/ZipVersionUtils.java create mode 100644 src/test/java/net/lingala/zip4j/util/ZipVersionUtilsTest.java diff --git a/src/main/java/net/lingala/zip4j/headers/FileHeaderFactory.java b/src/main/java/net/lingala/zip4j/headers/FileHeaderFactory.java index 41eb57b5..6cc54f1d 100644 --- a/src/main/java/net/lingala/zip4j/headers/FileHeaderFactory.java +++ b/src/main/java/net/lingala/zip4j/headers/FileHeaderFactory.java @@ -10,6 +10,7 @@ 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.RawIO; import net.lingala.zip4j.util.Zip4jUtil; import java.nio.charset.Charset; @@ -17,16 +18,19 @@ import static net.lingala.zip4j.util.BitUtils.setBit; import static net.lingala.zip4j.util.BitUtils.unsetBit; import static net.lingala.zip4j.util.FileUtils.isZipEntryDirectory; +import static net.lingala.zip4j.util.ZipVersionUtils.determineVersionMadeBy; +import static net.lingala.zip4j.util.ZipVersionUtils.determineVersionNeededToExtract; public class FileHeaderFactory { - public FileHeader generateFileHeader(ZipParameters zipParameters, boolean isSplitZip, int currentDiskNumberStart, Charset charset) + public FileHeader generateFileHeader(ZipParameters zipParameters, boolean isSplitZip, int currentDiskNumberStart, + Charset charset, RawIO rawIO) throws ZipException { FileHeader fileHeader = new FileHeader(); fileHeader.setSignature(HeaderSignature.CENTRAL_DIRECTORY); - fileHeader.setVersionMadeBy(20); - fileHeader.setVersionNeededToExtract(20); + fileHeader.setVersionMadeBy(determineVersionMadeBy(zipParameters, rawIO)); + fileHeader.setVersionNeededToExtract(determineVersionNeededToExtract(zipParameters).getCode()); if (zipParameters.isEncryptFiles() && zipParameters.getEncryptionMethod() == EncryptionMethod.AES) { fileHeader.setCompressionMethod(CompressionMethod.AES_INTERNAL_ONLY); diff --git a/src/main/java/net/lingala/zip4j/headers/VersionMadeBy.java b/src/main/java/net/lingala/zip4j/headers/VersionMadeBy.java new file mode 100644 index 00000000..7b4faeca --- /dev/null +++ b/src/main/java/net/lingala/zip4j/headers/VersionMadeBy.java @@ -0,0 +1,18 @@ +package net.lingala.zip4j.headers; + +public enum VersionMadeBy { + + SPECIFICATION_VERSION((byte) 51), + WINDOWS((byte) 0), + UNIX((byte) 3); + + private byte code; + + VersionMadeBy(byte code) { + this.code = code; + } + + public byte getCode() { + return code; + } +} diff --git a/src/main/java/net/lingala/zip4j/headers/VersionNeededToExtract.java b/src/main/java/net/lingala/zip4j/headers/VersionNeededToExtract.java new file mode 100644 index 00000000..035baf70 --- /dev/null +++ b/src/main/java/net/lingala/zip4j/headers/VersionNeededToExtract.java @@ -0,0 +1,19 @@ +package net.lingala.zip4j.headers; + +public enum VersionNeededToExtract { + + DEFAULT(10), + DEFLATE_COMPRESSED(20), + ZIP_64_FORMAT(45), + AES_ENCRYPTED(51); + + private int code; + + VersionNeededToExtract(int code) { + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/src/main/java/net/lingala/zip4j/io/outputstream/ZipOutputStream.java b/src/main/java/net/lingala/zip4j/io/outputstream/ZipOutputStream.java index 3ab91443..265c7c29 100755 --- a/src/main/java/net/lingala/zip4j/io/outputstream/ZipOutputStream.java +++ b/src/main/java/net/lingala/zip4j/io/outputstream/ZipOutputStream.java @@ -148,7 +148,7 @@ private ZipModel initializeZipModel(ZipModel zipModel, CountingOutputStream coun private void initializeAndWriteFileHeader(ZipParameters zipParameters) throws IOException { fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, countingOutputStream.isSplitZipFile(), - countingOutputStream.getCurrentSplitFileCounter(), charset); + countingOutputStream.getCurrentSplitFileCounter(), charset, rawIO); fileHeader.setOffsetLocalHeader(countingOutputStream.getOffsetForNextEntry()); localFileHeader = fileHeaderFactory.generateLocalFileHeader(fileHeader); diff --git a/src/main/java/net/lingala/zip4j/model/ZipParameters.java b/src/main/java/net/lingala/zip4j/model/ZipParameters.java index 42a8d21a..fcec6520 100755 --- a/src/main/java/net/lingala/zip4j/model/ZipParameters.java +++ b/src/main/java/net/lingala/zip4j/model/ZipParameters.java @@ -65,6 +65,7 @@ public enum SymbolicLinkAction { private String fileComment; private SymbolicLinkAction symbolicLinkAction = SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY; private ExcludeFileFilter excludeFileFilter; + private boolean unixMode; /** * Create a ZipParameters instance with default values; @@ -397,4 +398,20 @@ public ExcludeFileFilter getExcludeFileFilter() { public void setExcludeFileFilter(ExcludeFileFilter excludeFileFilter) { this.excludeFileFilter = excludeFileFilter; } + + /** + * Returns true if zip4j is using unix mode as default. Returns False otherwise. + * @return true if zip4j is using unix mode as default, false otherwise + */ + public boolean isUnixMode() { + return unixMode; + } + + /** + * When set to true, zip4j uses unix mode as default when generating file headers. + * @param unixMode + */ + public void setUnixMode(boolean unixMode) { + this.unixMode = unixMode; + } } diff --git a/src/main/java/net/lingala/zip4j/util/FileUtils.java b/src/main/java/net/lingala/zip4j/util/FileUtils.java index 6a50dade..4c950a03 100644 --- a/src/main/java/net/lingala/zip4j/util/FileUtils.java +++ b/src/main/java/net/lingala/zip4j/util/FileUtils.java @@ -492,6 +492,11 @@ private static void addIfBitSet(byte b, int pos, Set posixF } } + public static boolean isWindows() { + String os = System.getProperty("os.name").toLowerCase(); + return isWindows(os); + } + private static boolean isWindows(String os) { return (os.contains("win")); } diff --git a/src/main/java/net/lingala/zip4j/util/ZipVersionUtils.java b/src/main/java/net/lingala/zip4j/util/ZipVersionUtils.java new file mode 100644 index 00000000..4e24a680 --- /dev/null +++ b/src/main/java/net/lingala/zip4j/util/ZipVersionUtils.java @@ -0,0 +1,39 @@ +package net.lingala.zip4j.util; + +import net.lingala.zip4j.headers.VersionMadeBy; +import net.lingala.zip4j.headers.VersionNeededToExtract; +import net.lingala.zip4j.model.ZipParameters; +import net.lingala.zip4j.model.enums.CompressionMethod; +import net.lingala.zip4j.model.enums.EncryptionMethod; + +public class ZipVersionUtils { + + public static int determineVersionMadeBy(ZipParameters zipParameters, RawIO rawIO) { + byte[] versionMadeBy = new byte[2]; + versionMadeBy[0] = VersionMadeBy.SPECIFICATION_VERSION.getCode(); + versionMadeBy[1] = VersionMadeBy.UNIX.getCode(); + if (FileUtils.isWindows() && !zipParameters.isUnixMode()) { // skip setting windows mode if unix mode is forced + versionMadeBy[1] = VersionMadeBy.WINDOWS.getCode(); + } + + return rawIO.readShortLittleEndian(versionMadeBy, 0); + } + + public static VersionNeededToExtract determineVersionNeededToExtract(ZipParameters zipParameters) { + VersionNeededToExtract versionRequired = VersionNeededToExtract.DEFAULT; + + if (zipParameters.getCompressionMethod() == CompressionMethod.DEFLATE) { + versionRequired = VersionNeededToExtract.DEFLATE_COMPRESSED; + } + + if (zipParameters.getEntrySize() > InternalZipConstants.ZIP_64_SIZE_LIMIT) { + versionRequired = VersionNeededToExtract.ZIP_64_FORMAT; + } + + if (zipParameters.isEncryptFiles() && zipParameters.getEncryptionMethod().equals(EncryptionMethod.AES)) { + versionRequired = VersionNeededToExtract.AES_ENCRYPTED; + } + + return versionRequired; + } +} diff --git a/src/test/java/net/lingala/zip4j/AddFilesToZipIT.java b/src/test/java/net/lingala/zip4j/AddFilesToZipIT.java index 81731ea6..53f9b77f 100644 --- a/src/test/java/net/lingala/zip4j/AddFilesToZipIT.java +++ b/src/test/java/net/lingala/zip4j/AddFilesToZipIT.java @@ -16,6 +16,8 @@ import net.lingala.zip4j.testutils.ZipFileVerifier; import net.lingala.zip4j.util.BitUtils; import net.lingala.zip4j.util.InternalZipConstants; +import net.lingala.zip4j.util.RawIO; +import net.lingala.zip4j.util.ZipVersionUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -37,6 +39,8 @@ public class AddFilesToZipIT extends AbstractIT { + private RawIO rawIO = new RawIO(); + @Rule public ExpectedException expectedException = ExpectedException.none(); @@ -56,6 +60,7 @@ public void testAddFileAsStringParameterWithoutZipParameterAddsAsDeflate() throw ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, outputFolder, 1); verifyZipFileContainsFiles(generatedZipFile, singletonList("sample.pdf"), CompressionMethod.DEFLATE, null, null); + verifyZipVersions(zipFile.getFileHeaders().get(0), new ZipParameters()); } @Test @@ -83,6 +88,7 @@ public void testAddFileAsStringWithZipParametersStoreAndStandardEncryptionAndCha ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1, true, CHARSET_CP_949); assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo(koreanFileName); + verifyZipVersions(zipFile.getFileHeaders().get(0), zipParameters); } @Test @@ -139,6 +145,7 @@ public void testAddFileWithZipParametersStoreAndAes128Encryption() throws IOExce ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, PASSWORD, outputFolder, 1); verifyZipFileContainsFiles(generatedZipFile, singletonList("sample_text_large.txt"), CompressionMethod.STORE, EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_128); + verifyZipVersions(zipFile.getFileHeaders().get(0), zipParameters); } @Test @@ -1002,4 +1009,12 @@ private CompressionMethod getShouldBeCompressionMethod(boolean isAesEncrypted, C return compressionMethod; } + + private void verifyZipVersions(FileHeader fileHeader, ZipParameters zipParameters) { + int versionMadeBy = ZipVersionUtils.determineVersionMadeBy(zipParameters, rawIO); + int versionNeededToExtract = ZipVersionUtils.determineVersionNeededToExtract(zipParameters).getCode(); + + assertThat(fileHeader.getVersionMadeBy()).isEqualTo(versionMadeBy); + assertThat(fileHeader.getVersionNeededToExtract()).isEqualTo(versionNeededToExtract); + } } diff --git a/src/test/java/net/lingala/zip4j/headers/FileHeaderFactoryTest.java b/src/test/java/net/lingala/zip4j/headers/FileHeaderFactoryTest.java index 6c668f02..0e32c896 100644 --- a/src/test/java/net/lingala/zip4j/headers/FileHeaderFactoryTest.java +++ b/src/test/java/net/lingala/zip4j/headers/FileHeaderFactoryTest.java @@ -11,6 +11,9 @@ 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.RawIO; +import org.junit.After; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -23,25 +26,37 @@ public class FileHeaderFactoryTest { + private static final String ACTUAL_OS = System.getProperty("os.name"); private static final String FILE_NAME_IN_ZIP = "filename.txt"; private static final long ENTRY_CRC = 2323L; private FileHeaderFactory fileHeaderFactory = new FileHeaderFactory(); + private RawIO rawIO = new RawIO(); @Rule public ExpectedException expectedException = ExpectedException.none(); + @Before + public void setup() { + System.setProperty("os.name", "linux"); + } + + @After + public void cleanup() { + System.setProperty("os.name", ACTUAL_OS); + } + @Test public void testGenerateFileHeaderWithoutFileNameThrowsException() throws ZipException { expectedException.expect(ZipException.class); expectedException.expectMessage("fileNameInZip is null or empty"); - fileHeaderFactory.generateFileHeader(new ZipParameters(), false, 0, InternalZipConstants.CHARSET_UTF_8); + fileHeaderFactory.generateFileHeader(new ZipParameters(), false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); } @Test public void testGenerateFileHeaderDefaults() throws ZipException { - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(generateZipParameters(), false, 0, InternalZipConstants.CHARSET_UTF_8); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(generateZipParameters(), false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); assertThat(fileHeader).isNotNull(); assertThat(fileHeader.getCompressionMethod()).isEqualTo(CompressionMethod.DEFLATE); @@ -60,8 +75,8 @@ public void testGenerateFileHeaderForStoreWithoutEncryption() throws ZipExceptio ZipParameters zipParameters = generateZipParameters(); zipParameters.setCompressionMethod(CompressionMethod.STORE); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); - verifyFileHeader(fileHeader, zipParameters, false, 0, false); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); + verifyFileHeader(fileHeader, zipParameters, false, 0, 10, false); } @Test @@ -72,7 +87,7 @@ public void testGenerateFileHeaderWhenEncryptingWithoutMethodThrowsException() t ZipParameters zipParameters = generateZipParameters(); zipParameters.setEncryptFiles(true); - fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); + fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); } @Test @@ -81,8 +96,8 @@ public void testGenerateFileHeaderWithStandardEncryption() throws ZipException { zipParameters.setEncryptFiles(true); zipParameters.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); - verifyFileHeader(fileHeader, zipParameters, false, 0, false); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); + verifyFileHeader(fileHeader, zipParameters, false, 0, 20, false); } @Test @@ -95,7 +110,7 @@ public void testGenerateFileHeaderWithAesEncryptionWithNullKeyStrengthThrowsExce zipParameters.setEncryptionMethod(EncryptionMethod.AES); zipParameters.setAesKeyStrength(null); - fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); + fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); } @Test @@ -104,8 +119,8 @@ public void testGenerateFileHeaderWithAesEncryptionWithoutKeyStrengthUsesDefault zipParameters.setEncryptFiles(true); zipParameters.setEncryptionMethod(EncryptionMethod.AES); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); - verifyFileHeader(fileHeader, zipParameters, false, 0, true); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); + verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true); verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_256, CompressionMethod.DEFLATE, AesVersion.TWO); } @@ -117,8 +132,8 @@ public void testGenerateFileHeaderWithAesEncryptionWithKeyStrength128() throws Z zipParameters.setEncryptionMethod(EncryptionMethod.AES); zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_128); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); - verifyFileHeader(fileHeader, zipParameters, false, 0, true); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); + verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true); verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_128, CompressionMethod.DEFLATE, AesVersion.TWO); } @@ -130,8 +145,8 @@ public void testGenerateFileHeaderWithAesEncryptionWithKeyStrength192() throws Z zipParameters.setEncryptionMethod(EncryptionMethod.AES); zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_192); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); - verifyFileHeader(fileHeader, zipParameters, false, 0, true); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); + verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true); verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_192, CompressionMethod.DEFLATE, AesVersion.TWO); } @@ -143,8 +158,8 @@ public void testGenerateFileHeaderWithAesEncryptionWithKeyStrength256() throws Z zipParameters.setEncryptionMethod(EncryptionMethod.AES); zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); - verifyFileHeader(fileHeader, zipParameters, false, 0, true); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); + verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true); verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_256, CompressionMethod.DEFLATE, AesVersion.TWO); } @@ -157,8 +172,8 @@ public void testGenerateFileHeaderWithAesEncryptionVersionV1() throws ZipExcepti zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256); zipParameters.setAesVersion(AesVersion.ONE); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); - verifyFileHeader(fileHeader, zipParameters, false, 0, true); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); + verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true); verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_256, CompressionMethod.DEFLATE, AesVersion.ONE); } @@ -171,8 +186,8 @@ public void testGenerateFileHeaderWithAesEncryptionWithNullVersionUsesV2() throw zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256); zipParameters.setAesVersion(null); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); - verifyFileHeader(fileHeader, zipParameters, false, 0, true); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); + verifyFileHeader(fileHeader, zipParameters, false, 0, 51, true); verifyAesExtraDataRecord(fileHeader.getAesExtraDataRecord(), AesKeyStrength.KEY_STRENGTH_256, CompressionMethod.DEFLATE, AesVersion.TWO); } @@ -183,7 +198,7 @@ public void testGenerateFileHeaderWithLastModifiedFileTime() throws ZipException ZipParameters zipParameters = generateZipParameters(); zipParameters.setLastModifiedFileTime(lastModifiedFileTime); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); assertThat(fileHeader.getLastModifiedTime()).isEqualTo(javaToDosTime(zipParameters.getLastModifiedFileTime())); } @@ -193,7 +208,7 @@ public void testGenerateFileHeaderWithCompressionLeveUltra() throws ZipException ZipParameters zipParameters = generateZipParameters(); zipParameters.setCompressionLevel(CompressionLevel.ULTRA); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); verifyCompressionLevelGridForDeflate(CompressionLevel.ULTRA, fileHeader.getGeneralPurposeFlag()[0]); } @@ -203,7 +218,7 @@ public void testGenerateFileHeaderWithCompressionLevelMaximum() throws ZipExcept ZipParameters zipParameters = generateZipParameters(); zipParameters.setCompressionLevel(CompressionLevel.MAXIMUM); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); verifyCompressionLevelGridForDeflate(CompressionLevel.MAXIMUM, fileHeader.getGeneralPurposeFlag()[0]); } @@ -213,7 +228,7 @@ public void testGenerateFileHeaderWithCompressionLevelFast() throws ZipException ZipParameters zipParameters = generateZipParameters(); zipParameters.setCompressionLevel(CompressionLevel.FAST); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); verifyCompressionLevelGridForDeflate(CompressionLevel.FAST, fileHeader.getGeneralPurposeFlag()[0]); } @@ -223,20 +238,20 @@ public void testGenerateFileHeaderWithCompressionLevelFastest() throws ZipExcept ZipParameters zipParameters = generateZipParameters(); zipParameters.setCompressionLevel(CompressionLevel.FASTEST); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); verifyCompressionLevelGridForDeflate(CompressionLevel.FASTEST, fileHeader.getGeneralPurposeFlag()[0]); } @Test public void testGenerateFileHeaderWithCorrectCharset() throws ZipException { - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(generateZipParameters(), false, 0, Charset.forName("Cp949")); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(generateZipParameters(), false, 0, Charset.forName("Cp949"), rawIO); assertThat(isBitSet(fileHeader.getGeneralPurposeFlag()[1], 3)).isFalse(); } @Test public void testGenerateFileHeaderWithUTF8Charset() throws ZipException { - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(generateZipParameters(), false, 0, InternalZipConstants.CHARSET_UTF_8); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(generateZipParameters(), false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); assertThat(isBitSet(fileHeader.getGeneralPurposeFlag()[1], 3)).isTrue(); } @@ -250,6 +265,41 @@ public void testGenerateLocalFileHeader() { verifyLocalFileHeader(localFileHeader, lastModifiedFileTime); } + @Test + public void testVersionMadeByWindowsWithUnixModeOff() throws ZipException { + changeOsSystemPropertyToWindows(); + testVersionMadeBy(generateZipParameters(), 51); + } + + @Test + public void testVersionMadeByWindowsWithUnixModeOn() throws ZipException { + changeOsSystemPropertyToWindows(); + ZipParameters zipParameters = generateZipParameters(); + zipParameters.setUnixMode(true); + testVersionMadeBy(zipParameters, 819); + } + + @Test + public void testVersionMadeByUnix() throws ZipException { + changeOsSystemPropertyToUnix(); + testVersionMadeBy(generateZipParameters(), 819); + } + + @Test + public void testVersionMadeByMac() throws ZipException { + changeOsSystemPropertyToMac(); + testVersionMadeBy(generateZipParameters(), 819); + } + + private void testVersionMadeBy(ZipParameters zipParameters, int expectedVersionMadeBy) { + try { + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); + assertThat(fileHeader.getVersionMadeBy()).isEqualTo(expectedVersionMadeBy); + } catch (Exception e) { + restoreOsSystemProperty(); + } + } + private ZipParameters generateZipParameters() { ZipParameters zipParameters = new ZipParameters(); zipParameters.setFileNameInZip(FILE_NAME_IN_ZIP); @@ -276,11 +326,11 @@ private FileHeader generateFileHeader(long lastModifiedFileTime) { } private void verifyFileHeader(FileHeader fileHeader, ZipParameters zipParameters, boolean isSplitZip, - int diskNumberStart, boolean aesExtraDataRecordPresent) { + int diskNumberStart, int versionNeededToExtract, boolean aesExtraDataRecordPresent) { assertThat(fileHeader).isNotNull(); assertThat(fileHeader.getSignature()).isEqualTo(HeaderSignature.CENTRAL_DIRECTORY); - assertThat(fileHeader.getVersionMadeBy()).isEqualTo(20); - assertThat(fileHeader.getVersionNeededToExtract()).isEqualTo(20); + assertThat(fileHeader.getVersionMadeBy()).isEqualTo(819); + assertThat(fileHeader.getVersionNeededToExtract()).isEqualTo(versionNeededToExtract); verifyCompressionMethod(fileHeader, zipParameters); assertThat(fileHeader.isEncrypted()).isEqualTo(zipParameters.isEncryptFiles()); assertThat(fileHeader.getEncryptionMethod()).isEqualTo(zipParameters.isEncryptFiles() @@ -393,4 +443,19 @@ private void verifyAesExtraDataRecord(AESExtraDataRecord aesExtraDataRecord, Aes assertThat(aesExtraDataRecord.getAesKeyStrength()).isEqualTo(aesKeyStrength); } + private void changeOsSystemPropertyToWindows() { + System.setProperty("os.name", "windows"); + } + + private void changeOsSystemPropertyToUnix() { + System.setProperty("os.name", "nux"); + } + + private void changeOsSystemPropertyToMac() { + System.setProperty("os.name", "mac"); + } + + private void restoreOsSystemProperty() { + System.setProperty("os.name", ACTUAL_OS); + } } \ No newline at end of file diff --git a/src/test/java/net/lingala/zip4j/headers/HeaderReaderIT.java b/src/test/java/net/lingala/zip4j/headers/HeaderReaderIT.java index e061a2f7..112d802d 100644 --- a/src/test/java/net/lingala/zip4j/headers/HeaderReaderIT.java +++ b/src/test/java/net/lingala/zip4j/headers/HeaderReaderIT.java @@ -14,6 +14,7 @@ import net.lingala.zip4j.model.enums.RandomAccessFileMode; import net.lingala.zip4j.util.BitUtils; import net.lingala.zip4j.util.InternalZipConstants; +import net.lingala.zip4j.util.RawIO; import org.junit.Test; import java.io.File; @@ -38,6 +39,7 @@ public class HeaderReaderIT extends AbstractIT { private FileHeaderFactory fileHeaderFactory = new FileHeaderFactory(); private HeaderReader headerReader = new HeaderReader(); private HeaderWriter headerWriter = new HeaderWriter(); + private RawIO rawIO = new RawIO(); @Test public void testReadAllHeadersWith10Entries() throws IOException { @@ -367,7 +369,7 @@ private List generateFileHeaders(ZipParameters zipParameters, int nu List fileHeaders = new ArrayList<>(); for (int i = 0; i < numberOfEntries; i++) { zipParameters.setFileNameInZip(FILE_NAME_PREFIX + i); - FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8); + FileHeader fileHeader = fileHeaderFactory.generateFileHeader(zipParameters, false, 0, InternalZipConstants.CHARSET_UTF_8, rawIO); fileHeaders.add(fileHeader); } return fileHeaders; diff --git a/src/test/java/net/lingala/zip4j/util/FileUtilsTestLinuxAndMac.java b/src/test/java/net/lingala/zip4j/util/FileUtilsTestLinuxAndMac.java index cd411de0..035b9199 100644 --- a/src/test/java/net/lingala/zip4j/util/FileUtilsTestLinuxAndMac.java +++ b/src/test/java/net/lingala/zip4j/util/FileUtilsTestLinuxAndMac.java @@ -90,6 +90,11 @@ public void testGetFileAttributesAsDefinedForDirectory() throws IOException { testGetFileAttributesGetsAsDefined(true); } + @Test + public void testIsWindowsReturnsFalse() { + assertThat(FileUtils.isWindows()).isFalse(); + } + private void testGetFileAttributesGetsAsDefined(boolean isDirectory) throws IOException { File file = mock(File.class); Path path = mock(Path.class); diff --git a/src/test/java/net/lingala/zip4j/util/FileUtilsTestWindows.java b/src/test/java/net/lingala/zip4j/util/FileUtilsTestWindows.java index 84eb964b..c6771ee4 100644 --- a/src/test/java/net/lingala/zip4j/util/FileUtilsTestWindows.java +++ b/src/test/java/net/lingala/zip4j/util/FileUtilsTestWindows.java @@ -89,6 +89,11 @@ public void testGetFileAttributesWhenFileDoesNotExistReturnsEmptyBytes() throws assertThat(attributes).contains(0, 0, 0, 0); } + @Test + public void testIsWindowsReturnsTrue() { + assertThat(FileUtils.isWindows()).isTrue(); + } + @Test public void testGetFileAttributesReturnsAttributesAsDefined() throws IOException { File file = mock(File.class); diff --git a/src/test/java/net/lingala/zip4j/util/ZipVersionUtilsTest.java b/src/test/java/net/lingala/zip4j/util/ZipVersionUtilsTest.java new file mode 100644 index 00000000..9cb4606d --- /dev/null +++ b/src/test/java/net/lingala/zip4j/util/ZipVersionUtilsTest.java @@ -0,0 +1,79 @@ +package net.lingala.zip4j.util; + +import net.lingala.zip4j.headers.VersionNeededToExtract; +import net.lingala.zip4j.model.ZipParameters; +import net.lingala.zip4j.model.enums.CompressionMethod; +import net.lingala.zip4j.model.enums.EncryptionMethod; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ZipVersionUtilsTest { + + private static final String ACTUAL_OS = System.getProperty("os.name"); + + private RawIO rawIO = new RawIO(); + + @Before + public void setup() { + System.setProperty("os.name", "linux"); + } + + @After + public void cleanup() { + System.setProperty("os.name", ACTUAL_OS); + } + + @Test + public void testDetermineVersionMadeByUnix() { + assertThat(ZipVersionUtils.determineVersionMadeBy(new ZipParameters(), rawIO)).isEqualTo(819); + } + + @Test + public void testDetermineVersionMadeByWindows() { + changeOsSystemPropertyToWindows(); + assertThat(ZipVersionUtils.determineVersionMadeBy(new ZipParameters(), rawIO)).isEqualTo(51); + } + + @Test + public void testDetermineVersionMadeByWindowsAndUnixModeOn() { + ZipParameters zipParameters = new ZipParameters(); + zipParameters.setUnixMode(true); + assertThat(ZipVersionUtils.determineVersionMadeBy(zipParameters, rawIO)).isEqualTo(819); + } + + @Test + public void testDetermineVersionNeededToExtractDefault() { + ZipParameters zipParameters = new ZipParameters(); + zipParameters.setCompressionMethod(CompressionMethod.STORE); + assertThat(ZipVersionUtils.determineVersionNeededToExtract(zipParameters)).isEqualTo(VersionNeededToExtract.DEFAULT); + } + + @Test + public void testDetermineVersionNeededToExtractDefalte() { + ZipParameters zipParameters = new ZipParameters(); + zipParameters.setCompressionMethod(CompressionMethod.DEFLATE); + assertThat(ZipVersionUtils.determineVersionNeededToExtract(zipParameters)).isEqualTo(VersionNeededToExtract.DEFLATE_COMPRESSED); + } + + @Test + public void testDetermineVersionNeededToExtractZip64() { + ZipParameters zipParameters = new ZipParameters(); + zipParameters.setEntrySize(InternalZipConstants.ZIP_64_SIZE_LIMIT + 10); + assertThat(ZipVersionUtils.determineVersionNeededToExtract(zipParameters)).isEqualTo(VersionNeededToExtract.ZIP_64_FORMAT); + } + + @Test + public void testDetermineVersionNeededToExtractAES() { + ZipParameters zipParameters = new ZipParameters(); + zipParameters.setEncryptFiles(true); + zipParameters.setEncryptionMethod(EncryptionMethod.AES); + assertThat(ZipVersionUtils.determineVersionNeededToExtract(zipParameters)).isEqualTo(VersionNeededToExtract.AES_ENCRYPTED); + } + + private void changeOsSystemPropertyToWindows() { + System.setProperty("os.name", "windows"); + } +} \ No newline at end of file