Skip to content

Commit

Permalink
#64 Enable charset selection for ZipFile and ZipInputStream (#67)
Browse files Browse the repository at this point in the history
* enable charset selection for ZipFile and InputStream

* add test cases for charset specification in ZipFile and ZipInputStream

* charset selection for ZipFile and ZipOutputStream

enable charset selection for ZipFile(output APIs) and ZipOutputStream

* add testcase for charset in ZipOutputStream

* utf-8 bit flag should not be set when charset is specified

* change the type of charset: from String to Charset

* charset is not allowed to be null

* Merge with master and adjust code

* Minor cleanup
  • Loading branch information
LeeYoung624 authored and srikanth-lingala committed Sep 29, 2019
1 parent 5cb61f7 commit bbd0234
Show file tree
Hide file tree
Showing 31 changed files with 519 additions and 184 deletions.
40 changes: 30 additions & 10 deletions src/main/java/net/lingala/zip4j/ZipFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,20 @@
import net.lingala.zip4j.tasks.ExtractFileTask;
import net.lingala.zip4j.tasks.ExtractFileTask.ExtractFileTaskParameters;
import net.lingala.zip4j.tasks.MergeSplitZipFileTask;
import net.lingala.zip4j.tasks.MergeSplitZipFileTask.MergeSplitZipFileTaskParameters;
import net.lingala.zip4j.tasks.RemoveEntryFromZipFileTask;
import net.lingala.zip4j.tasks.RemoveEntryFromZipFileTask.RemoveEntryFromZipFileTaskParameters;
import net.lingala.zip4j.tasks.SetCommentTask;
import net.lingala.zip4j.tasks.SetCommentTask.SetCommentTaskTaskParameters;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.Zip4jUtil;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;

Expand Down Expand Up @@ -74,6 +79,7 @@ public class ZipFile {
private boolean runInThread;
private char[] password;
private HeaderWriter headerWriter = new HeaderWriter();
private Charset charset = StandardCharsets.UTF_8;

/**
* Creates a new ZipFile instance with the zip file at the location specified in zipFile.
Expand Down Expand Up @@ -144,7 +150,7 @@ public void createSplitZipFile(List<File> filesToAdd, ZipParameters parameters,
zipModel.setSplitLength(splitLength);

new AddFilesToZipTask(progressMonitor, runInThread, zipModel, password, headerWriter).execute(
new AddFilesToZipTaskParameters(filesToAdd, parameters));
new AddFilesToZipTaskParameters(filesToAdd, parameters, charset));
}

/**
Expand Down Expand Up @@ -285,7 +291,7 @@ public void addFiles(List<File> filesToAdd, ZipParameters parameters) throws Zip
}

new AddFilesToZipTask(progressMonitor, runInThread, zipModel, password, headerWriter).execute(
new AddFilesToZipTaskParameters(filesToAdd, parameters));
new AddFilesToZipTaskParameters(filesToAdd, parameters, charset));
}

/**
Expand Down Expand Up @@ -357,7 +363,7 @@ private void addFolder(File folderToAdd, ZipParameters zipParameters, boolean ch
}

new AddFolderToZipTask(progressMonitor, runInThread, zipModel, password, headerWriter).execute(
new AddFolderToZipTaskParameters(folderToAdd, zipParameters));
new AddFolderToZipTaskParameters(folderToAdd, zipParameters, charset));
}

/**
Expand Down Expand Up @@ -394,7 +400,7 @@ public void addStream(InputStream inputStream, ZipParameters parameters) throws
}

new AddStreamToZipTask(progressMonitor, runInThread, zipModel, password, headerWriter).execute(
new AddStreamToZipTaskParameters(inputStream, parameters));
new AddStreamToZipTaskParameters(inputStream, parameters, charset));
}

/**
Expand Down Expand Up @@ -429,7 +435,7 @@ public void extractAll(String destinationPath) throws ZipException {
}

new ExtractAllFilesTask(progressMonitor, runInThread, zipModel, password).execute(
new ExtractAllFilesTaskParameters(destinationPath));
new ExtractAllFilesTaskParameters(destinationPath, charset));
}

/**
Expand Down Expand Up @@ -473,7 +479,7 @@ public void extractFile(FileHeader fileHeader, String destinationPath, String ne
readZipInfo();

new ExtractFileTask(progressMonitor, runInThread, zipModel, password).execute(
new ExtractFileTaskParameters(destinationPath, fileHeader, newFileName));
new ExtractFileTaskParameters(destinationPath, fileHeader, newFileName, charset));
}

/**
Expand Down Expand Up @@ -670,7 +676,8 @@ public void removeFile(FileHeader fileHeader) throws ZipException {
throw new ZipException("Zip file format does not allow updating split/spanned files");
}

new RemoveEntryFromZipFileTask(progressMonitor, runInThread, zipModel).execute(fileHeader);
new RemoveEntryFromZipFileTask(progressMonitor, runInThread, zipModel).execute(
new RemoveEntryFromZipFileTaskParameters(fileHeader, charset));
}

/**
Expand All @@ -695,7 +702,8 @@ public void mergeSplitFiles(File outputZipFile) throws ZipException {
throw new ZipException("zip model is null, corrupt zip file?");
}

new MergeSplitZipFileTask(progressMonitor, runInThread, zipModel).execute(outputZipFile);
new MergeSplitZipFileTask(progressMonitor, runInThread, zipModel).execute(
new MergeSplitZipFileTaskParameters(outputZipFile, charset));
}

/**
Expand Down Expand Up @@ -723,7 +731,8 @@ public void setComment(String comment) throws ZipException {
throw new ZipException("end of central directory is null, cannot set comment");
}

new SetCommentTask(progressMonitor, runInThread, zipModel).execute(comment);
new SetCommentTask(progressMonitor, runInThread, zipModel).execute(
new SetCommentTaskTaskParameters(comment, charset));
}

/**
Expand Down Expand Up @@ -835,7 +844,7 @@ private void readZipInfo() throws ZipException {

try (RandomAccessFile randomAccessFile = new RandomAccessFile(zipFile, RandomAccessFileMode.READ.getValue())) {
HeaderReader headerReader = new HeaderReader();
zipModel = headerReader.readAllHeaders(randomAccessFile);
zipModel = headerReader.readAllHeaders(randomAccessFile, charset);
zipModel.setZipFile(zipFile);
} catch (IOException e) {
throw new ZipException(e);
Expand Down Expand Up @@ -879,6 +888,17 @@ public File getFile() {
return zipFile;
}

public Charset getCharset() {
return charset;
}

public void setCharset(Charset charset) throws IllegalArgumentException {
if(charset == null) {
throw new IllegalArgumentException("charset cannot be null");
}
this.charset = charset;
}

@Override
public String toString() {
return zipFile.toString();
Expand Down
11 changes: 7 additions & 4 deletions src/main/java/net/lingala/zip4j/headers/FileHeaderFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.Zip4jUtil;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import static net.lingala.zip4j.util.BitUtils.setBit;
Expand All @@ -19,7 +20,7 @@

public class FileHeaderFactory {

public FileHeader generateFileHeader(ZipParameters zipParameters, boolean isSplitZip, int currentDiskNumberStart)
public FileHeader generateFileHeader(ZipParameters zipParameters, boolean isSplitZip, int currentDiskNumberStart, Charset charset)
throws ZipException {

FileHeader fileHeader = new FileHeader();
Expand Down Expand Up @@ -63,7 +64,7 @@ public FileHeader generateFileHeader(ZipParameters zipParameters, boolean isSpli
fileHeader.setCrc(zipParameters.getEntryCRC());
}

fileHeader.setGeneralPurposeFlag(determineGeneralPurposeBitFlag(fileHeader.isEncrypted(), zipParameters));
fileHeader.setGeneralPurposeFlag(determineGeneralPurposeBitFlag(fileHeader.isEncrypted(), zipParameters, charset));
fileHeader.setDataDescriptorExists(zipParameters.isWriteExtendedLocalFileHeader());
return fileHeader;
}
Expand All @@ -87,10 +88,12 @@ public LocalFileHeader generateLocalFileHeader(FileHeader fileHeader) {
return localFileHeader;
}

private byte[] determineGeneralPurposeBitFlag(boolean isEncrypted, ZipParameters zipParameters) {
private byte[] determineGeneralPurposeBitFlag(boolean isEncrypted, ZipParameters zipParameters, Charset charset) {
byte[] generalPurposeBitFlag = new byte[2];
generalPurposeBitFlag[0] = generateFirstGeneralPurposeByte(isEncrypted, zipParameters);
generalPurposeBitFlag[1] = setBit(generalPurposeBitFlag[1], 3); // set 3rd bit which corresponds to utf-8 file name charset
if(charset.equals(StandardCharsets.UTF_8)) {
generalPurposeBitFlag[1] = setBit(generalPurposeBitFlag[1], 3); // set 3rd bit which corresponds to utf-8 file name charset
}
return generalPurposeBitFlag;
}

Expand Down
15 changes: 8 additions & 7 deletions src/main/java/net/lingala/zip4j/headers/HeaderReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -57,7 +58,7 @@ public class HeaderReader {
private RawIO rawIO = new RawIO();
private byte[] intBuff = new byte[4];

public ZipModel readAllHeaders(RandomAccessFile zip4jRaf) throws IOException {
public ZipModel readAllHeaders(RandomAccessFile zip4jRaf, Charset charset) throws IOException {
zipModel = new ZipModel();

try {
Expand All @@ -79,7 +80,7 @@ public ZipModel readAllHeaders(RandomAccessFile zip4jRaf) throws IOException {
}
}

zipModel.setCentralDirectory(readCentralDirectory(zip4jRaf, rawIO));
zipModel.setCentralDirectory(readCentralDirectory(zip4jRaf, rawIO, charset));

return zipModel;
}
Expand Down Expand Up @@ -127,7 +128,7 @@ private EndOfCentralDirectoryRecord readEndOfCentralDirectoryRecord(RandomAccess
return endOfCentralDirectoryRecord;
}

private CentralDirectory readCentralDirectory(RandomAccessFile zip4jRaf, RawIO rawIO) throws IOException {
private CentralDirectory readCentralDirectory(RandomAccessFile zip4jRaf, RawIO rawIO, Charset charset) throws IOException {
CentralDirectory centralDirectory = new CentralDirectory();
List<FileHeader> fileHeaders = new ArrayList<>();

Expand Down Expand Up @@ -195,7 +196,7 @@ private CentralDirectory readCentralDirectory(RandomAccessFile zip4jRaf, RawIO r
if (fileNameLength > 0) {
byte[] fileNameBuff = new byte[fileNameLength];
zip4jRaf.readFully(fileNameBuff);
String fileName = decodeStringWithCharset(fileNameBuff, fileHeader.isFileNameUTF8Encoded());
String fileName = decodeStringWithCharset(fileNameBuff, fileHeader.isFileNameUTF8Encoded(), charset);

if (fileName.contains(":\\")) {
fileName = fileName.substring(fileName.indexOf(":\\") + 2);
Expand All @@ -214,7 +215,7 @@ private CentralDirectory readCentralDirectory(RandomAccessFile zip4jRaf, RawIO r
if (fileCommentLength > 0) {
byte[] fileCommentBuff = new byte[fileCommentLength];
zip4jRaf.readFully(fileCommentBuff);
fileHeader.setFileComment(decodeStringWithCharset(fileCommentBuff, fileHeader.isFileNameUTF8Encoded()));
fileHeader.setFileComment(decodeStringWithCharset(fileCommentBuff, fileHeader.isFileNameUTF8Encoded(), charset));
}

if (fileHeader.isEncrypted()) {
Expand Down Expand Up @@ -522,7 +523,7 @@ private void setFilePointerToReadZip64EndCentralDirLoc(RandomAccessFile zip4jRaf
zip4jRaf.seek(zip4jRaf.getFilePointer() - 4 - 4 - 8 - 4 - 4);
}

public LocalFileHeader readLocalFileHeader(InputStream inputStream) throws IOException {
public LocalFileHeader readLocalFileHeader(InputStream inputStream, Charset charset) throws IOException {
LocalFileHeader localFileHeader = new LocalFileHeader();
byte[] intBuff = new byte[4];

Expand Down Expand Up @@ -565,7 +566,7 @@ public LocalFileHeader readLocalFileHeader(InputStream inputStream) throws IOExc
// Modified after user reported an issue http://www.lingala.net/zip4j/forum/index.php?topic=2.0
// String fileName = new String(fileNameBuf, "Cp850");
// String fileName = Zip4jUtil.getCp850EncodedString(fileNameBuf);
String fileName = decodeStringWithCharset(fileNameBuf, localFileHeader.isFileNameUTF8Encoded());
String fileName = decodeStringWithCharset(fileNameBuf, localFileHeader.isFileNameUTF8Encoded(), charset);

if (fileName == null) {
throw new ZipException("file name is null, cannot assign file name to local file header");
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/net/lingala/zip4j/headers/HeaderUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import net.lingala.zip4j.model.ZipModel;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;

Expand Down Expand Up @@ -62,7 +63,11 @@ public static int getIndexOfFileHeader(ZipModel zipModel, FileHeader fileHeader)
return -1;
}

public static String decodeStringWithCharset(byte[] data, boolean isUtf8Encoded) {
public static String decodeStringWithCharset(byte[] data, boolean isUtf8Encoded, Charset charset) {
if(charset != null) {
return new String(data, charset);
}

if (isUtf8Encoded) {
return new String(data, StandardCharsets.UTF_8);
}
Expand Down
Loading

0 comments on commit bbd0234

Please sign in to comment.