Skip to content

Commit

Permalink
#183 fix versionMadeBy and versionNeededToExtract header values
Browse files Browse the repository at this point in the history
  • Loading branch information
srikanth-lingala committed May 21, 2020
1 parent a4745ca commit 76db682
Show file tree
Hide file tree
Showing 13 changed files with 308 additions and 35 deletions.
10 changes: 7 additions & 3 deletions src/main/java/net/lingala/zip4j/headers/FileHeaderFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,27 @@
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;

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);
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/net/lingala/zip4j/headers/VersionMadeBy.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/net/lingala/zip4j/model/ZipParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
5 changes: 5 additions & 0 deletions src/main/java/net/lingala/zip4j/util/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,11 @@ private static void addIfBitSet(byte b, int pos, Set<PosixFilePermission> 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"));
}
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/net/lingala/zip4j/util/ZipVersionUtils.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
15 changes: 15 additions & 0 deletions src/test/java/net/lingala/zip4j/AddFilesToZipIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -37,6 +39,8 @@

public class AddFilesToZipIT extends AbstractIT {

private RawIO rawIO = new RawIO();

@Rule
public ExpectedException expectedException = ExpectedException.none();

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}
Loading

0 comments on commit 76db682

Please sign in to comment.