Skip to content

Commit

Permalink
#412 Get raw file name bytes via file and local file headers
Browse files Browse the repository at this point in the history
  • Loading branch information
srikanth-lingala committed Mar 23, 2022
1 parent be88df4 commit 6b03a60
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import java.nio.charset.Charset;

import static net.lingala.zip4j.headers.HeaderUtil.getBytesFromString;
import static net.lingala.zip4j.util.BitUtils.setBit;
import static net.lingala.zip4j.util.BitUtils.unsetBit;
import static net.lingala.zip4j.util.FileUtils.isZipEntryDirectory;
Expand Down Expand Up @@ -52,6 +53,7 @@ public FileHeader generateFileHeader(ZipParameters zipParameters, boolean isSpli

String fileName = validateAndGetFileName(zipParameters.getFileNameInZip());
fileHeader.setFileName(fileName);
fileHeader.setFileNameBytes(getBytesFromString(fileHeader.getFileName(), charset));
fileHeader.setFileNameLength(determineFileNameLength(fileName, charset));
fileHeader.setDiskNumberStart(isSplitZip ? currentDiskNumberStart : 0);

Expand Down Expand Up @@ -90,6 +92,7 @@ public LocalFileHeader generateLocalFileHeader(FileHeader fileHeader) {
localFileHeader.setUncompressedSize(fileHeader.getUncompressedSize());
localFileHeader.setFileNameLength(fileHeader.getFileNameLength());
localFileHeader.setFileName(fileHeader.getFileName());
localFileHeader.setFileNameBytes(fileHeader.getFileNameBytes());
localFileHeader.setEncrypted(fileHeader.isEncrypted());
localFileHeader.setEncryptionMethod(fileHeader.getEncryptionMethod());
localFileHeader.setAesExtraDataRecord(fileHeader.getAesExtraDataRecord());
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/net/lingala/zip4j/headers/HeaderReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ private CentralDirectory readCentralDirectory(RandomAccessFile zip4jRaf, RawIO r
zip4jRaf.readFully(fileNameBuff);
String fileName = decodeStringWithCharset(fileNameBuff, fileHeader.isFileNameUTF8Encoded(), charset);
fileHeader.setFileName(fileName);
fileHeader.setFileNameBytes(fileNameBuff);
} else {
throw new ZipException("Invalid entry name in file header");
}
Expand Down Expand Up @@ -558,6 +559,7 @@ public LocalFileHeader readLocalFileHeader(InputStream inputStream, Charset char
String fileName = decodeStringWithCharset(fileNameBuf, localFileHeader.isFileNameUTF8Encoded(), charset);
localFileHeader.setFileName(fileName);
localFileHeader.setDirectory(fileName.endsWith("/") || fileName.endsWith("\\"));
localFileHeader.setFileNameBytes(fileNameBuf);
} else {
throw new ZipException("Invalid entry name in local file header");
}
Expand Down
20 changes: 6 additions & 14 deletions src/main/java/net/lingala/zip4j/headers/HeaderWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,7 @@ public void writeLocalFileHeader(ZipModel zipModel, LocalFileHeader localFileHea
localFileHeader.setWriteCompressedSizeInZip64ExtraRecord(false);
}

byte[] fileNameBytes = new byte[0];
if (isStringNotNullAndNotEmpty(localFileHeader.getFileName())) {
fileNameBytes = getBytesFromString(localFileHeader.getFileName(), charset);
}
rawIO.writeShortLittleEndian(byteArrayOutputStream, fileNameBytes.length);
rawIO.writeShortLittleEndian(byteArrayOutputStream, localFileHeader.getFileNameBytes().length);

int extraFieldLength = 0;
if (writeZip64Header) {
Expand All @@ -106,8 +102,8 @@ public void writeLocalFileHeader(ZipModel zipModel, LocalFileHeader localFileHea
}
rawIO.writeShortLittleEndian(byteArrayOutputStream, extraFieldLength);

if (fileNameBytes.length > 0) {
byteArrayOutputStream.write(fileNameBytes);
if (localFileHeader.getFileNameBytes().length > 0) {
byteArrayOutputStream.write(localFileHeader.getFileNameBytes());
}

//Zip64 should be the first extra data record that should be written
Expand Down Expand Up @@ -430,11 +426,7 @@ private void writeFileHeader(ZipModel zipModel, FileHeader fileHeader, ByteArray
byteArrayOutputStream.write(longBuff, 0, 4);
}

byte[] fileNameBytes = new byte[0];
if (isStringNotNullAndNotEmpty(fileHeader.getFileName())) {
fileNameBytes = getBytesFromString(fileHeader.getFileName(), charset);
}
rawIO.writeShortLittleEndian(byteArrayOutputStream, fileNameBytes.length);
rawIO.writeShortLittleEndian(byteArrayOutputStream, fileHeader.getFileNameBytes().length);

//Compute offset bytes before extra field is written for Zip64 compatibility
//NOTE: this data is not written now, but written at a later point
Expand Down Expand Up @@ -472,8 +464,8 @@ private void writeFileHeader(ZipModel zipModel, FileHeader fileHeader, ByteArray
//offset local header - this data is computed above
byteArrayOutputStream.write(offsetLocalHeaderBytes);

if (fileNameBytes.length > 0) {
byteArrayOutputStream.write(fileNameBytes);
if (fileHeader.getFileNameBytes().length > 0) {
byteArrayOutputStream.write(fileHeader.getFileNameBytes());
}

if (writeZip64ExtendedInfo) {
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/net/lingala/zip4j/model/AbstractFileHeader.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public abstract class AbstractFileHeader extends ZipHeader {
private int fileNameLength;
private int extraFieldLength;
private String fileName;
private byte[] fileNameBytes;
private boolean isEncrypted;
private EncryptionMethod encryptionMethod = EncryptionMethod.NONE;
private boolean dataDescriptorExists;
Expand Down Expand Up @@ -111,6 +112,14 @@ public void setFileName(String fileName) {
this.fileName = fileName;
}

public byte[] getFileNameBytes() {
return fileNameBytes;
}

public void setFileNameBytes(byte[] fileNameBytes) {
this.fileNameBytes = fileNameBytes;
}

public boolean isEncrypted() {
return isEncrypted;
}
Expand Down
30 changes: 30 additions & 0 deletions src/test/java/net/lingala/zip4j/MiscZipFileIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -632,6 +633,35 @@ public void testCloseZipFileMultipleTimesClosesAllStreams() throws IOException {
assertInputStreamsAreClosed(Collections.singletonList(inputStream));
}

@Test
public void testGetFileNameBytesReturnsValidBytes() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
File firstFileToAdd = getTestFileFromResources("가나다.abc");
File secondFileToAdd = getTestFileFromResources("sample.pdf");
zipFile.addFile(firstFileToAdd);
zipFile.addFile(secondFileToAdd);

byte[] firstNameExpectedBytes = firstFileToAdd.getName().getBytes(StandardCharsets.UTF_8);
byte[] secondNameExpectedBytes = secondFileToAdd.getName().getBytes(StandardCharsets.UTF_8);

// Assert before and after creating a new instance of zipFile to make sure that the bytes are set
// even after adding entries to zip and not just when reading zip entries
assertFileNameBytesEqualsToFileName(zipFile, firstNameExpectedBytes, firstFileToAdd.getName());
assertFileNameBytesEqualsToFileName(zipFile, secondNameExpectedBytes, secondFileToAdd.getName());

zipFile = new ZipFile(generatedZipFile);

assertFileNameBytesEqualsToFileName(zipFile, firstNameExpectedBytes, firstFileToAdd.getName());
assertFileNameBytesEqualsToFileName(zipFile, secondNameExpectedBytes, secondFileToAdd.getName());
}

private void assertFileNameBytesEqualsToFileName(ZipFile zipFile, byte[] expectedFileNameBytes,
String expectedFileName) throws ZipException {
FileHeader fileHeader = zipFile.getFileHeader(expectedFileName);
assertThat(fileHeader.getFileNameBytes()).isEqualTo(expectedFileNameBytes);
assertThat(new String(fileHeader.getFileNameBytes(), StandardCharsets.UTF_8)).isEqualTo(expectedFileName);
}

private void assertInputStreamsAreClosed(List<InputStream> inputStreams) {
for (InputStream inputStream : inputStreams) {
try {
Expand Down

0 comments on commit 6b03a60

Please sign in to comment.