Skip to content

Commit a31ea49

Browse files
committed
Create zip reader impl delegating to java.util.zip.ZipFile
1 parent 83a6add commit a31ea49

File tree

4 files changed

+157
-10
lines changed

4 files changed

+157
-10
lines changed

src/main/java/software/coley/lljzip/ZipIO.java

+22-8
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
import software.coley.lljzip.format.model.CentralDirectoryFileHeader;
44
import software.coley.lljzip.format.model.EndOfCentralDirectory;
55
import software.coley.lljzip.format.model.ZipArchive;
6-
import software.coley.lljzip.format.read.ForwardScanZipReader;
7-
import software.coley.lljzip.format.read.JvmZipReader;
8-
import software.coley.lljzip.format.read.NaiveLocalFileZipReader;
9-
import software.coley.lljzip.format.read.ZipReader;
6+
import software.coley.lljzip.format.read.*;
107
import software.coley.lljzip.util.BufferData;
118
import software.coley.lljzip.util.ByteData;
129
import software.coley.lljzip.util.FileMapUtil;
@@ -15,6 +12,7 @@
1512
import java.io.IOException;
1613
import java.nio.file.Files;
1714
import java.nio.file.Path;
15+
import java.util.zip.ZipFile;
1816

1917
/**
2018
* IO wrappers for reading {@link ZipArchive} contents.
@@ -64,7 +62,7 @@ public static ZipArchive readStandard(byte[] data) throws IOException {
6462
* @param data
6563
* Zip path.
6664
*
67-
* @return Archive from bytes.
65+
* @return Archive from path.
6866
*
6967
* @throws IOException
7068
* When the archive bytes cannot be read from, usually indicating a malformed zip.
@@ -109,7 +107,7 @@ public static ZipArchive readNaive(byte[] data) throws IOException {
109107
* @param data
110108
* Zip path.
111109
*
112-
* @return Archive from bytes.
110+
* @return Archive from path.
113111
*
114112
* @throws IOException
115113
* When the archive bytes cannot be read from, usually indicating a malformed zip.
@@ -157,7 +155,7 @@ public static ZipArchive readJvm(byte[] data) throws IOException {
157155
* @param path
158156
* Zip path.
159157
*
160-
* @return Archive from bytes.
158+
* @return Archive from path.
161159
*
162160
* @throws IOException
163161
* When the archive bytes cannot be read from, usually indicating a malformed zip.
@@ -166,6 +164,22 @@ public static ZipArchive readJvm(Path path) throws IOException {
166164
return read(path, new JvmZipReader());
167165
}
168166

167+
/**
168+
* Creates an archive using the {@link AdaptingZipReader} which delegates work to {@link ZipFile}.
169+
*
170+
* @param path
171+
* Zip path.
172+
*
173+
* @return Archive from path.
174+
*
175+
* @throws IOException
176+
*/
177+
public static ZipArchive readAdaptingIO(Path path) throws IOException {
178+
ZipArchive archive = new ZipArchive();
179+
AdaptingZipReader.fill(archive, path.toFile());
180+
return archive;
181+
}
182+
169183
/**
170184
* @param data
171185
* Zip bytes.
@@ -189,7 +203,7 @@ public static ZipArchive read(byte[] data, ZipReader strategy) throws IOExceptio
189203
* @param strategy
190204
* Zip reader implementation.
191205
*
192-
* @return Archive from bytes.
206+
* @return Archive from path.
193207
*
194208
* @throws IOException
195209
* When the archive bytes cannot be read from, usually indicating a malformed zip.

src/main/java/software/coley/lljzip/format/model/AbstractZipFileHeader.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ public void setFileName(ByteData fileName) {
251251
*/
252252
public String getFileNameAsString() {
253253
String fileNameCache = this.fileNameCache;
254-
if (fileNameCache == null) {
254+
if (fileNameCache == null && fileName != null) {
255255
return this.fileNameCache = ByteDataUtil.toString(fileName.get());
256256
}
257257
return fileNameCache;
@@ -278,7 +278,7 @@ public void setExtraField(ByteData extraField) {
278278
*/
279279
public String getExtraFieldAsString() {
280280
String fileCommentCache = this.extraFieldCache;
281-
if (fileCommentCache == null) {
281+
if (fileCommentCache == null && extraField != null) {
282282
return this.extraFieldCache = ByteDataUtil.toString(extraField.get());
283283
}
284284
return fileCommentCache;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package software.coley.lljzip.format.model;
2+
3+
import software.coley.lljzip.util.BufferData;
4+
import software.coley.lljzip.util.NoopByteData;
5+
import software.coley.lljzip.util.lazy.LazyByteData;
6+
import software.coley.lljzip.util.lazy.LazyInt;
7+
import software.coley.lljzip.util.lazy.LazyLong;
8+
9+
import javax.annotation.Nonnull;
10+
import java.io.ByteArrayOutputStream;
11+
import java.io.IOException;
12+
import java.io.InputStream;
13+
import java.util.zip.ZipEntry;
14+
import java.util.zip.ZipFile;
15+
16+
/**
17+
* Local file header implementation that pulls values from {@link ZipEntry}.
18+
*
19+
* @author Matt Coley
20+
*/
21+
public class AdaptingLocalFileHeader extends LocalFileHeader {
22+
private static final int BUFFER_SIZE = 2048;
23+
24+
/**
25+
* @param archive
26+
* Containing archive holding the entry.
27+
* @param entry
28+
* Entry to adapt.
29+
*
30+
* @throws IOException
31+
* When the entry cannot be read from the archive.
32+
*/
33+
public AdaptingLocalFileHeader(@Nonnull ZipFile archive, @Nonnull ZipEntry entry) throws IOException {
34+
InputStream inputStream = archive.getInputStream(entry);
35+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
36+
byte[] buffer = new byte[BUFFER_SIZE];
37+
int read;
38+
while ((read = inputStream.read(buffer)) != -1)
39+
outputStream.write(buffer, 0, read);
40+
byte[] entryData = outputStream.toByteArray();
41+
String entryName = entry.getName();
42+
byte[] extra = entry.getExtra();
43+
versionNeededToExtract = new LazyInt(() -> 0);
44+
generalPurposeBitFlag = new LazyInt(() -> 0);
45+
lastModFileTime = new LazyInt(() -> 0);
46+
lastModFileDate = new LazyInt(() -> 0);
47+
fileNameLength = new LazyInt(entryName::length);
48+
fileName = new LazyByteData(() -> BufferData.wrap(entryName.getBytes()));
49+
fileDataLength = new LazyLong(() -> entryData.length);
50+
fileData = new LazyByteData(() -> BufferData.wrap(entryData));
51+
compressionMethod = new LazyInt(() -> 0);
52+
uncompressedSize = new LazyLong(() -> entryData.length);
53+
compressedSize = new LazyLong(() -> entryData.length);
54+
crc32 = new LazyInt(() -> (int) entry.getCrc());
55+
if (extra != null) {
56+
extraFieldLength = new LazyInt(() -> extra.length);
57+
extraField = new LazyByteData(() -> BufferData.wrap(extra));
58+
} else {
59+
extraFieldLength = new LazyInt(() -> 0);
60+
extraField = new LazyByteData(() -> NoopByteData.INSTANCE);
61+
}
62+
data = NoopByteData.INSTANCE;
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package software.coley.lljzip.format.read;
2+
3+
import software.coley.lljzip.format.model.AdaptingLocalFileHeader;
4+
import software.coley.lljzip.format.model.ZipArchive;
5+
import software.coley.lljzip.util.ByteData;
6+
import software.coley.lljzip.util.ByteDataUtil;
7+
8+
import javax.annotation.Nonnull;
9+
import java.io.File;
10+
import java.io.IOException;
11+
import java.nio.file.Files;
12+
import java.util.Enumeration;
13+
import java.util.zip.ZipEntry;
14+
import java.util.zip.ZipFile;
15+
16+
/**
17+
* A zip reader implementation delegating all the work to {@link ZipFile}.
18+
* <p/>
19+
* This will write temporary files to disk in order to satisfy constructor requirements if you use
20+
* the standard {@link ZipReader} methods. Instead directly call {@link #fill(ZipArchive, File)} or
21+
* {@link #fill(ZipArchive, ZipFile)}.
22+
*
23+
* @author Matt Coley
24+
*/
25+
public class AdaptingZipReader implements ZipReader {
26+
@Override
27+
public void read(@Nonnull ZipArchive zip, @Nonnull ByteData data) throws IOException {
28+
// Java's ZipFile requires the data be on-disk
29+
File temp = File.createTempFile("lljzip", ".tempzip");
30+
try {
31+
Files.write(temp.toPath(), ByteDataUtil.toByteArray(data));
32+
fill(zip, temp);
33+
} finally {
34+
temp.delete();
35+
}
36+
}
37+
38+
/**
39+
* @param to
40+
* Archive to fill.
41+
* @param from
42+
* Archive to adapt from.
43+
*
44+
* @throws IOException
45+
* When the zip file cannot be read.
46+
*/
47+
public static void fill(@Nonnull ZipArchive to, @Nonnull File from) throws IOException {
48+
try (ZipFile zipFile = new ZipFile(from)) {
49+
fill(to, zipFile);
50+
}
51+
}
52+
53+
/**
54+
* @param to
55+
* Archive to fill.
56+
* @param from
57+
* Archive to adapt from.
58+
*
59+
* @throws IOException
60+
* When the zip file cannot be read.
61+
*/
62+
public static void fill(@Nonnull ZipArchive to, @Nonnull ZipFile from) throws IOException {
63+
Enumeration<? extends ZipEntry> zipEntries = from.entries();
64+
while (zipEntries.hasMoreElements()) {
65+
ZipEntry entry = zipEntries.nextElement();
66+
to.addPart(new AdaptingLocalFileHeader(from, entry));
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)