Skip to content

Commit ebfc3b7

Browse files
#116 Split ZipEntryBuilder
1 parent 7f42992 commit ebfc3b7

File tree

6 files changed

+387
-326
lines changed

6 files changed

+387
-326
lines changed

src/main/java/ru/olegcherednik/zip4jvm/io/readers/ZipModelReader.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import ru.olegcherednik.zip4jvm.model.password.PasswordProvider;
2929
import ru.olegcherednik.zip4jvm.model.src.SrcZip;
3030
import ru.olegcherednik.zip4jvm.utils.ValidationUtils;
31-
import ru.olegcherednik.zip4jvm.utils.quitely.Quietly;
3231

3332
import java.nio.charset.Charset;
3433
import java.util.function.Function;
@@ -89,7 +88,7 @@ public static int getTotalDisks(SrcZip srcZip) {
8988

9089
@Override
9190
protected RandomAccessDataInput createDataInput() {
92-
return Quietly.doRuntime(() -> UnzipEngine.createRandomAccessDataInput(srcZip));
91+
return UnzipEngine.createRandomAccessDataInput(srcZip);
9392
}
9493

9594
@Override

src/main/java/ru/olegcherednik/zip4jvm/io/readers/block/BlockZipModelReader.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import ru.olegcherednik.zip4jvm.model.builders.ZipModelBuilder;
3636
import ru.olegcherednik.zip4jvm.model.password.PasswordProvider;
3737
import ru.olegcherednik.zip4jvm.model.src.SrcZip;
38-
import ru.olegcherednik.zip4jvm.utils.quitely.Quietly;
3938

4039
import java.io.IOException;
4140
import java.nio.charset.Charset;
@@ -88,7 +87,7 @@ private BlockModel read(boolean readEntries) throws IOException {
8887

8988
@Override
9089
protected RandomAccessDataInput createDataInput() {
91-
return Quietly.doRuntime(() -> UnzipEngine.createRandomAccessDataInput(srcZip));
90+
return UnzipEngine.createRandomAccessDataInput(srcZip);
9291
}
9392

9493
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package ru.olegcherednik.zip4jvm.model.entry;
2+
3+
import ru.olegcherednik.zip4jvm.ZipFile;
4+
import ru.olegcherednik.zip4jvm.model.AesVersion;
5+
import ru.olegcherednik.zip4jvm.model.AesVersionEnum;
6+
import ru.olegcherednik.zip4jvm.model.CompressionLevel;
7+
import ru.olegcherednik.zip4jvm.model.CompressionMethod;
8+
import ru.olegcherednik.zip4jvm.model.EncryptionMethod;
9+
import ru.olegcherednik.zip4jvm.model.ExternalFileAttributes;
10+
import ru.olegcherednik.zip4jvm.model.settings.ZipEntrySettings;
11+
import ru.olegcherednik.zip4jvm.utils.ZipUtils;
12+
import ru.olegcherednik.zip4jvm.utils.function.ZipEntryInputStreamFunction;
13+
import ru.olegcherednik.zip4jvm.utils.time.DosTimestampConverterUtils;
14+
15+
import lombok.Builder;
16+
17+
/**
18+
* @author Oleg Cherednik
19+
* @since 16.02.2025
20+
*/
21+
@Builder
22+
class EntryBasedZipEntryBuilder {
23+
24+
private final ZipFile.Entry entry;
25+
private final ZipEntrySettings entrySettings;
26+
27+
public ZipEntry build() {
28+
ZipEntry zipEntry = createZipEntry();
29+
zipEntry.setComment(entrySettings.getComment());
30+
zipEntry.setUtf8(entrySettings.isUtf8());
31+
return zipEntry;
32+
}
33+
34+
private ZipEntry createZipEntry() {
35+
if (entry.isSymlink())
36+
return createSymlinkEntry();
37+
if (entry.isDir())
38+
return createEmptyDirectoryEntry();
39+
return createRegularFileEntry();
40+
}
41+
42+
private ZipEntry createSymlinkEntry() {
43+
String symlinkName = ZipUtils.getFileName(entry);
44+
int lastModifiedTime = DosTimestampConverterUtils.javaToDosTime(entry.getLastModifiedTime());
45+
ExternalFileAttributes externalFileAttributes = entry.getExternalFileAttributes();
46+
ZipEntryInputStreamFunction inputStreamSup = (zipEntry, in) -> entry.getInputStream();
47+
48+
ZipEntry zipEntry = new RegularFileZipEntry(symlinkName,
49+
lastModifiedTime,
50+
externalFileAttributes,
51+
AesVersionEnum.AUTO.getVersion(),
52+
CompressionMethod.STORE,
53+
CompressionLevel.NORMAL,
54+
EncryptionMethod.OFF,
55+
inputStreamSup);
56+
57+
zipEntry.setDataDescriptorAvailable(true);
58+
zipEntry.setComment(entrySettings.getComment());
59+
zipEntry.setUtf8(entrySettings.isUtf8());
60+
zipEntry.setUncompressedSize(entry.getUncompressedSize());
61+
62+
return zipEntry;
63+
}
64+
65+
private ZipEntry createEmptyDirectoryEntry() {
66+
String dirName = ZipUtils.getFileName(entry);
67+
int lastModifiedTime = DosTimestampConverterUtils.javaToDosTime(entry.getLastModifiedTime());
68+
ExternalFileAttributes externalFileAttributes = entry.getExternalFileAttributes();
69+
return new EmptyDirectoryZipEntry(dirName, lastModifiedTime, externalFileAttributes);
70+
}
71+
72+
private ZipEntry createRegularFileEntry() {
73+
String fileName = ZipUtils.getFileName(entry);
74+
int lastModifiedTime = DosTimestampConverterUtils.javaToDosTime(entry.getLastModifiedTime());
75+
ExternalFileAttributes externalFileAttributes = entry.getExternalFileAttributes();
76+
77+
CompressionMethod compressionMethod =
78+
entry.getUncompressedSize() == 0 ? CompressionMethod.STORE
79+
: entrySettings.getCompression().getMethod();
80+
CompressionLevel compressionLevel = entrySettings.getCompressionLevel();
81+
EncryptionMethod encryptionMethod = entrySettings.getEncryption().getMethod();
82+
ZipEntryInputStreamFunction inputStreamFunction = (zipEntry, in) -> entry.getInputStream();
83+
boolean dataDescriptorAvailable =
84+
entrySettings.getDataDescriptor().isIncludeDataDescriptor(compressionMethod, encryptionMethod);
85+
AesVersion aesVersion = entrySettings.getAesVersion().getVersion();
86+
87+
RegularFileZipEntry zipEntry = new RegularFileZipEntry(fileName,
88+
lastModifiedTime,
89+
externalFileAttributes,
90+
aesVersion,
91+
compressionMethod,
92+
compressionLevel,
93+
encryptionMethod,
94+
inputStreamFunction);
95+
96+
zipEntry.setDataDescriptorAvailable(dataDescriptorAvailable);
97+
zipEntry.setZip64(entrySettings.isZip64());
98+
zipEntry.setPassword(entrySettings.getPassword());
99+
zipEntry.setComment(entrySettings.getComment());
100+
zipEntry.setUtf8(entrySettings.isUtf8());
101+
zipEntry.setUncompressedSize(entry.getUncompressedSize());
102+
103+
return zipEntry;
104+
}
105+
106+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package ru.olegcherednik.zip4jvm.model.entry;
2+
3+
import ru.olegcherednik.zip4jvm.engine.unzip.UnzipEngine;
4+
import ru.olegcherednik.zip4jvm.io.in.DataInput;
5+
import ru.olegcherednik.zip4jvm.io.in.ReadBufferInputStream;
6+
import ru.olegcherednik.zip4jvm.io.in.decorators.ChecksumCheckDataInput;
7+
import ru.olegcherednik.zip4jvm.io.in.decorators.DataDescriptorDataInput;
8+
import ru.olegcherednik.zip4jvm.io.in.decorators.LimitSizeDataInput;
9+
import ru.olegcherednik.zip4jvm.io.in.decorators.SizeCheckDataInput;
10+
import ru.olegcherednik.zip4jvm.io.in.decorators.UncloseableDataInput;
11+
import ru.olegcherednik.zip4jvm.io.in.encrypted.EncryptedDataInput;
12+
import ru.olegcherednik.zip4jvm.io.in.file.random.RandomAccessDataInput;
13+
import ru.olegcherednik.zip4jvm.io.readers.LocalFileHeaderReader;
14+
import ru.olegcherednik.zip4jvm.model.AesVersion;
15+
import ru.olegcherednik.zip4jvm.model.AesVersionEnum;
16+
import ru.olegcherednik.zip4jvm.model.CentralDirectory;
17+
import ru.olegcherednik.zip4jvm.model.Compression;
18+
import ru.olegcherednik.zip4jvm.model.CompressionLevel;
19+
import ru.olegcherednik.zip4jvm.model.CompressionMethod;
20+
import ru.olegcherednik.zip4jvm.model.EncryptionMethod;
21+
import ru.olegcherednik.zip4jvm.model.ExternalFileAttributes;
22+
import ru.olegcherednik.zip4jvm.model.GeneralPurposeFlag;
23+
import ru.olegcherednik.zip4jvm.model.LocalFileHeader;
24+
import ru.olegcherednik.zip4jvm.model.ZipModel;
25+
import ru.olegcherednik.zip4jvm.model.src.SrcZip;
26+
import ru.olegcherednik.zip4jvm.utils.ZipUtils;
27+
import ru.olegcherednik.zip4jvm.utils.function.ZipEntryInputStreamFunction;
28+
29+
import lombok.Builder;
30+
31+
import java.io.IOException;
32+
import java.io.InputStream;
33+
import java.nio.charset.Charset;
34+
import java.util.function.Function;
35+
36+
import static ru.olegcherednik.zip4jvm.model.ZipModel.MAX_LOCAL_FILE_HEADER_OFFS;
37+
import static ru.olegcherednik.zip4jvm.model.ZipModel.MAX_TOTAL_DISKS;
38+
39+
/**
40+
* @author Oleg Cherednik
41+
* @since 16.02.2025
42+
*/
43+
@Builder
44+
class FileHeaderBasedZipEntryBuilder {
45+
46+
private final CentralDirectory.FileHeader fileHeader;
47+
private final SrcZip srcZip;
48+
private final Function<Charset, Charset> charsetCustomizer;
49+
private final boolean alt;
50+
51+
public ZipEntry build() {
52+
boolean regularFile = ZipUtils.isRegularFile(fileHeader.getFileName());
53+
ZipEntry zipEntry = regularFile ? createRegularFileEntry() : createEmptyDirectoryEntry();
54+
zipEntry.setChecksum(fileHeader.getCrc32());
55+
zipEntry.setUncompressedSize(getUncompressedSize());
56+
zipEntry.setCompressedSize(getCompressedSize());
57+
58+
int diskNo = getDiskNo();
59+
zipEntry.setDiskNo(getDiskNo());
60+
61+
long localFileHeaderDiskOffs = getLocalFileHeaderOffs();
62+
zipEntry.setLocalFileHeaderDiskOffs(localFileHeaderDiskOffs);
63+
zipEntry.setLocalFileHeaderAbsOffs(srcZip.getAbsOffs(diskNo, localFileHeaderDiskOffs));
64+
65+
return zipEntry;
66+
}
67+
68+
private ZipEntry createRegularFileEntry() {
69+
String fileName = ZipUtils.normalizeFileName(fileHeader.getFileName());
70+
int lastModifiedTime = fileHeader.getLastModifiedTime();
71+
GeneralPurposeFlag generalPurposeFlag = fileHeader.getGeneralPurposeFlag();
72+
73+
CompressionMethod compressionMethod = fileHeader.getOriginalCompressionMethod();
74+
CompressionLevel compressionLevel = generalPurposeFlag.getCompressionLevel();
75+
EncryptionMethod encryptionMethod = fileHeader.getEncryptionMethod();
76+
ExternalFileAttributes externalFileAttributes = fileHeader.getExternalFileAttributes();
77+
78+
ZipEntryInputStreamFunction inputStreamFunction = alt ? this::createInputStream
79+
: (zipEntry, in) -> createInputStream(zipEntry);
80+
81+
RegularFileZipEntry zipEntry = new RegularFileZipEntry(fileName,
82+
lastModifiedTime,
83+
externalFileAttributes,
84+
getAesVersion(),
85+
compressionMethod,
86+
compressionLevel,
87+
encryptionMethod,
88+
inputStreamFunction);
89+
90+
zipEntry.setDataDescriptorAvailable(fileHeader.isDataDescriptorAvailable());
91+
zipEntry.setLzmaEosMarker(generalPurposeFlag.isLzmaEosMarker());
92+
zipEntry.setZip64(fileHeader.isZip64());
93+
zipEntry.setComment(fileHeader.getComment());
94+
zipEntry.setUtf8(fileHeader.getGeneralPurposeFlag().isUtf8());
95+
zipEntry.setStrongEncryption(generalPurposeFlag.isStrongEncryption());
96+
97+
return zipEntry;
98+
}
99+
100+
private ZipEntry createEmptyDirectoryEntry() {
101+
String dirName = fileHeader.getFileName();
102+
int lastModifiedTime = fileHeader.getLastModifiedTime();
103+
ExternalFileAttributes externalFileAttributes = fileHeader.getExternalFileAttributes();
104+
return new EmptyDirectoryZipEntry(dirName, lastModifiedTime, externalFileAttributes);
105+
}
106+
107+
@SuppressWarnings({ "resource", "PMD.CloseResource" })
108+
private InputStream createInputStream(ZipEntry zipEntry) throws IOException {
109+
RandomAccessDataInput in1 = UnzipEngine.createRandomAccessDataInput(srcZip);
110+
in1.seek(zipEntry.getLocalFileHeaderAbsOffs());
111+
112+
DataInput in2 = in1;
113+
114+
LocalFileHeader localFileHeader = new LocalFileHeaderReader(charsetCustomizer).read(in2);
115+
zipEntry.setDataDescriptorAvailable(localFileHeader.isDataDescriptorAvailable());
116+
// TODO check that localFileHeader matches fileHeader
117+
118+
in2 = DataDescriptorDataInput.create(zipEntry, in2);
119+
in2 = LimitSizeDataInput.create(zipEntry.getCompressedSize(), in2);
120+
in2 = EncryptedDataInput.create(zipEntry.createDecoder(in2), in2);
121+
in2 = Compression.of(zipEntry.getCompressionMethod()).addCompressionDecorator(zipEntry, in2);
122+
in2 = SizeCheckDataInput.uncompressedSize(zipEntry, in2);
123+
in2 = ChecksumCheckDataInput.checksum(zipEntry, in2);
124+
125+
return ReadBufferInputStream.create(in2);
126+
}
127+
128+
private InputStream createInputStream(ZipEntry zipEntry, DataInput in) throws IOException {
129+
in = new UncloseableDataInput(in);
130+
131+
LocalFileHeader localFileHeader = new LocalFileHeaderReader(charsetCustomizer).read(in);
132+
zipEntry.setDataDescriptorAvailable(localFileHeader.isDataDescriptorAvailable());
133+
// TODO check that localFileHeader matches fileHeader
134+
135+
in = DataDescriptorDataInput.create(zipEntry, in);
136+
in = LimitSizeDataInput.create(zipEntry.getCompressedSize(), in);
137+
in = EncryptedDataInput.create(zipEntry.createDecoder(in), in);
138+
in = Compression.of(zipEntry.getCompressionMethod()).addCompressionDecorator(zipEntry, in);
139+
in = SizeCheckDataInput.uncompressedSize(zipEntry, in);
140+
in = ChecksumCheckDataInput.checksum(zipEntry, in);
141+
142+
return ReadBufferInputStream.create(in);
143+
}
144+
145+
private int getDiskNo() {
146+
if (fileHeader.getDiskNo() == MAX_TOTAL_DISKS)
147+
return (int) fileHeader.getExtraField().getExtendedInfo().getDiskNo();
148+
return fileHeader.getDiskNo();
149+
}
150+
151+
private long getCompressedSize() {
152+
if (fileHeader.getCompressedSize() == ZipModel.LOOK_IN_EXTRA_FIELD)
153+
return fileHeader.getExtraField().getExtendedInfo().getCompressedSize();
154+
return fileHeader.getCompressedSize();
155+
}
156+
157+
private long getUncompressedSize() {
158+
if (fileHeader.getUncompressedSize() == ZipModel.LOOK_IN_EXTRA_FIELD)
159+
return fileHeader.getExtraField().getExtendedInfo().getUncompressedSize();
160+
return fileHeader.getUncompressedSize();
161+
}
162+
163+
private long getLocalFileHeaderOffs() {
164+
if (fileHeader.getLocalFileHeaderRelativeOffs() == MAX_LOCAL_FILE_HEADER_OFFS)
165+
return fileHeader.getExtraField().getExtendedInfo().getLocalFileHeaderRelativeOffs();
166+
return fileHeader.getLocalFileHeaderRelativeOffs();
167+
}
168+
169+
private AesVersion getAesVersion() {
170+
if (fileHeader.getCompressionMethod() == CompressionMethod.AES)
171+
return fileHeader.getExtraField().getAesRecord().getVersion();
172+
return AesVersionEnum.AUTO.getVersion();
173+
}
174+
175+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package ru.olegcherednik.zip4jvm.model.entry;
2+
3+
import ru.olegcherednik.zip4jvm.model.AesVersion;
4+
import ru.olegcherednik.zip4jvm.model.Charsets;
5+
import ru.olegcherednik.zip4jvm.model.CompressionLevel;
6+
import ru.olegcherednik.zip4jvm.model.CompressionMethod;
7+
import ru.olegcherednik.zip4jvm.model.DataDescriptorEnum;
8+
import ru.olegcherednik.zip4jvm.model.EncryptionMethod;
9+
import ru.olegcherednik.zip4jvm.model.ExternalFileAttributes;
10+
import ru.olegcherednik.zip4jvm.model.settings.ZipEntrySettings;
11+
import ru.olegcherednik.zip4jvm.utils.function.ZipEntryInputStreamFunction;
12+
import ru.olegcherednik.zip4jvm.utils.time.DosTimestampConverterUtils;
13+
14+
import lombok.Builder;
15+
16+
import java.io.ByteArrayInputStream;
17+
import java.nio.file.Path;
18+
19+
/**
20+
* @author Oleg Cherednik
21+
* @since 16.02.2025
22+
*/
23+
@Builder
24+
class SymlinkZipEntryBuilder {
25+
26+
private final Path symlinkTarget;
27+
private final String symlinkTargetRelativePath;
28+
private final String symlinkName;
29+
private final ZipEntrySettings entrySettings;
30+
31+
public ZipEntry build() {
32+
int dosLastModifiedTime = DosTimestampConverterUtils.javaToDosTime(System.currentTimeMillis());
33+
byte[] buf = symlinkTargetRelativePath.getBytes(Charsets.UTF_8);
34+
ZipEntryInputStreamFunction inputStreamFunction = (zipEntry, in) -> new ByteArrayInputStream(buf);
35+
ExternalFileAttributes externalFileAttributes = ExternalFileAttributes.symlink(symlinkTarget);
36+
CompressionMethod compressionMethod = CompressionMethod.STORE;
37+
EncryptionMethod encryptionMethod = EncryptionMethod.OFF;
38+
DataDescriptorEnum dataDescriptorAvailability = entrySettings.getDataDescriptor();
39+
boolean dataDescriptorAvailable = dataDescriptorAvailability == DataDescriptorEnum.AUTO
40+
|| dataDescriptorAvailability.isIncludeDataDescriptor(compressionMethod, encryptionMethod);
41+
AesVersion aesVersion = entrySettings.getAesVersion().getVersion();
42+
43+
ZipEntry zipEntry = new RegularFileZipEntry(symlinkName,
44+
dosLastModifiedTime,
45+
externalFileAttributes,
46+
aesVersion,
47+
compressionMethod,
48+
CompressionLevel.NORMAL,
49+
encryptionMethod,
50+
inputStreamFunction);
51+
52+
zipEntry.setDataDescriptorAvailable(dataDescriptorAvailable);
53+
zipEntry.setComment(entrySettings.getComment());
54+
zipEntry.setUtf8(entrySettings.isUtf8());
55+
zipEntry.setUncompressedSize(buf.length);
56+
57+
return zipEntry;
58+
}
59+
60+
}

0 commit comments

Comments
 (0)