Skip to content

Commit

Permalink
#190 Update Zip64EndCentralDirRecord when adding files to existing zip
Browse files Browse the repository at this point in the history
  • Loading branch information
srikanth-lingala committed May 26, 2020
1 parent b694675 commit 0123ae5
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 24 deletions.
10 changes: 1 addition & 9 deletions src/main/java/net/lingala/zip4j/headers/HeaderReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ private CentralDirectory readCentralDirectory(RandomAccessFile zip4jRaf, RawIO r
CentralDirectory centralDirectory = new CentralDirectory();
List<FileHeader> fileHeaders = new ArrayList<>();

long offSetStartCentralDir = getOffsetCentralDirectory(zipModel);
long offSetStartCentralDir = HeaderUtil.getOffsetStartOfCentralDirectory(zipModel);
long centralDirEntryCount = getNumberOfEntriesInCentralDirectory(zipModel);

if (zipModel.isZip64Format()) {
Expand Down Expand Up @@ -701,14 +701,6 @@ private AESExtraDataRecord readAesExtraDataRecord(List<ExtraDataRecord> extraDat
return null;
}

private long getOffsetCentralDirectory(ZipModel zipModel) {
if (zipModel.isZip64Format()) {
return zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber();
}

return zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
}

private long getNumberOfEntriesInCentralDirectory(ZipModel zipModel) {
if (zipModel.isZip64Format()) {
return zipModel.getZip64EndOfCentralDirectoryRecord().getTotalNumberOfEntriesInCentralDirectory();
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/net/lingala/zip4j/headers/HeaderUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,20 @@ public static long getOffsetOfNextEntry(ZipModel zipModel, FileHeader fileHeader

List<FileHeader> fileHeaders = zipModel.getCentralDirectory().getFileHeaders();
if (indexOfFileHeader == fileHeaders.size() - 1) {
return getOffsetOfEndOfCentralDirectory(zipModel);
return getOffsetStartOfCentralDirectory(zipModel);
} else {
return fileHeaders.get(indexOfFileHeader + 1).getOffsetLocalHeader();
}
}

public static long getOffsetStartOfCentralDirectory(ZipModel zipModel) {
if (zipModel.isZip64Format()) {
return zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber();
}

return zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
}

public static List<FileHeader> getFileHeadersUnderDirectory(List<FileHeader> allFileHeaders, FileHeader rootFileHeader) {
if (!rootFileHeader.isDirectory()) {
return Collections.emptyList();
Expand All @@ -114,14 +122,6 @@ public static long getTotalUncompressedSizeOfAllFileHeaders(List<FileHeader> fil
return totalUncompressedSize;
}

private static long getOffsetOfEndOfCentralDirectory(ZipModel zipModel) {
if (zipModel.isZip64Format()) {
return zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber();
}

return zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
}

private static FileHeader getFileHeaderWithExactMatch(ZipModel zipModel, String fileName) throws ZipException {
if (zipModel == null) {
throw new ZipException("zip model is null, cannot determine file header with exact match for fileName: "
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/net/lingala/zip4j/headers/HeaderWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ private void processHeaderData(ZipModel zipModel, OutputStream outputStream) thr
zipModel.setZip64EndOfCentralDirectoryLocator(new Zip64EndOfCentralDirectoryLocator());
}

zipModel.getZip64EndOfCentralDirectoryRecord().setOffsetStartCentralDirectoryWRTStartDiskNumber(
zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory());
zipModel.getZip64EndOfCentralDirectoryLocator().setNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord(
currentSplitFileCounter);
zipModel.getZip64EndOfCentralDirectoryLocator().setTotalNumberOfDiscs(currentSplitFileCounter + 1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.lingala.zip4j.tasks;

import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.headers.HeaderUtil;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
Expand Down Expand Up @@ -64,7 +65,6 @@ void addFilesToZip(List<File> filesToAdd, ProgressMonitor progressMonitor, ZipPa
try (SplitOutputStream splitOutputStream = new SplitOutputStream(zipModel.getZipFile(), zipModel.getSplitLength());
ZipOutputStream zipOutputStream = initializeOutputStream(splitOutputStream, charset)) {


for (File fileToAdd : updatedFilesToAdd) {
verifyIfTaskIsCancelled();
ZipParameters clonedZipParameters = cloneAndAdjustZipParameters(zipParameters, fileToAdd, progressMonitor);
Expand Down Expand Up @@ -162,10 +162,7 @@ long calculateWorkForFiles(List<File> filesToAdd, ZipParameters zipParameters) t

ZipOutputStream initializeOutputStream(SplitOutputStream splitOutputStream, Charset charset) throws IOException {
if (zipModel.getZipFile().exists()) {
if (zipModel.getEndOfCentralDirectoryRecord() == null) {
throw new ZipException("invalid end of central directory record");
}
splitOutputStream.seek(zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory());
splitOutputStream.seek(HeaderUtil.getOffsetStartOfCentralDirectory(zipModel));
}

return new ZipOutputStream(splitOutputStream, password, charset, zipModel);
Expand Down
16 changes: 16 additions & 0 deletions src/test/java/net/lingala/zip4j/ZipFileZip64IT.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
import net.lingala.zip4j.testutils.HeaderVerifier;
import net.lingala.zip4j.testutils.RandomInputStream;
import net.lingala.zip4j.testutils.SlowTests;
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.testutils.ZipFileVerifier;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -135,6 +137,20 @@ public void testZip64WithNumberOfEntriesGreaterThan70k() throws IOException {
HeaderVerifier.verifyFileHeadersDoesNotExist(zipFile, filesToRemove);
}

@Test
public void testZip64WhenAddingFilesWithNewlyInstantiatedZipFile() throws IOException {
File testFileToAdd = TestUtils.generateFileOfSize(temporaryFolder, 1073741824); // 1 GB
ZipParameters zipParameters = new ZipParameters();
zipParameters.setCompressionMethod(CompressionMethod.STORE);

for (int i = 0; i < 6; i++) {
zipParameters.setFileNameInZip(Integer.toString(i));
new ZipFile(generatedZipFile).addFile(testFileToAdd, zipParameters);
}

ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 6, false);
}

private void verifyZip64HeadersPresent() throws IOException {
HeaderReader headerReader = new HeaderReader();
ZipModel zipModel = headerReader.readAllHeaders(new RandomAccessFile(generatedZipFile,
Expand Down
26 changes: 26 additions & 0 deletions src/test/java/net/lingala/zip4j/headers/HeaderUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.CentralDirectory;
import net.lingala.zip4j.model.EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.Zip64EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.Zip64ExtendedInfo;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.util.InternalZipConstants;
Expand Down Expand Up @@ -308,6 +310,30 @@ public void testGetUncompressedSizeOfAllFileHeaders() {
assertThat(HeaderUtil.getTotalUncompressedSizeOfAllFileHeaders(fileHeaders)).isEqualTo(6000);
}

@Test
public void testGetOffsetStartOfCentralDirectoryForZip64Format() {
long offsetCentralDirectory = InternalZipConstants.ZIP_64_SIZE_LIMIT + 100;
ZipModel zipModel = new ZipModel();
zipModel.setZip64Format(true);
Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = new Zip64EndOfCentralDirectoryRecord();
zip64EndOfCentralDirectoryRecord.setOffsetStartCentralDirectoryWRTStartDiskNumber(offsetCentralDirectory);
zipModel.setZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord);

assertThat(HeaderUtil.getOffsetStartOfCentralDirectory(zipModel)).isEqualTo(offsetCentralDirectory);
}

@Test
public void testGetOffsetStartOfCentralDirectoryForNonZip64Format() {
long offsetStartOfCentralDirectory = InternalZipConstants.ZIP_64_SIZE_LIMIT - 100;
ZipModel zipModel = new ZipModel();
zipModel.setZip64Format(false);
EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = new EndOfCentralDirectoryRecord();
endOfCentralDirectoryRecord.setOffsetOfStartOfCentralDirectory(offsetStartOfCentralDirectory);
zipModel.setEndOfCentralDirectoryRecord(endOfCentralDirectoryRecord);

assertThat(HeaderUtil.getOffsetStartOfCentralDirectory(zipModel)).isEqualTo(offsetStartOfCentralDirectory);
}

private List<FileHeader> generateFileHeaderWithFileNamesWithEmptyAndNullFileNames(String fileNamePrefix, int numberOfEntriesToAdd) {
List<FileHeader> fileHeaders = generateFileHeaderWithFileNames(fileNamePrefix, numberOfEntriesToAdd);
fileHeaders.add(generateFileHeader(""));
Expand Down
23 changes: 22 additions & 1 deletion src/test/java/net/lingala/zip4j/testutils/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.io.FileInputStream;
Expand All @@ -14,8 +15,9 @@
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.util.List;
import java.nio.file.Paths;
import java.util.List;
import java.util.Random;

public class TestUtils {

Expand Down Expand Up @@ -110,6 +112,25 @@ public static void createZipFileWithZipOutputStream(File zipFile, List<File> fil
}
}

public static File generateFileOfSize(TemporaryFolder temporaryFolder, long fileSize) throws IOException {
File outputFile = temporaryFolder.newFile();
byte[] b = new byte[8 * InternalZipConstants.BUFF_SIZE];
Random random = new Random();
long bytesWritten = 0;
int bufferWriteLength;

try (OutputStream outputStream = new FileOutputStream(outputFile)) {
while (bytesWritten < fileSize) {
random.nextBytes(b);
bufferWriteLength = bytesWritten + b.length > fileSize ? ((int) (fileSize - bytesWritten)) : b.length;
outputStream.write(b, 0, bufferWriteLength);
bytesWritten += bufferWriteLength;
}
}

return outputFile;
}

private static OutputStream startNext7ZipSplitStream(File sourceFile, File outputFolder, int index) throws IOException {
File outputFile = getFileNameFor7ZipSplitIndex(sourceFile, outputFolder, index);
return new FileOutputStream(outputFile);
Expand Down

0 comments on commit 0123ae5

Please sign in to comment.