Skip to content

Commit

Permalink
#106 Do not use CentralDirectory when extract all
Browse files Browse the repository at this point in the history
  • Loading branch information
oleg-cherednik committed Dec 22, 2024
1 parent 5ba0100 commit 32515e8
Show file tree
Hide file tree
Showing 24 changed files with 66 additions and 83 deletions.
2 changes: 1 addition & 1 deletion src/main/java/ru/olegcherednik/zip4jvm/ZipFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public static Entry regularFile(InputStreamSupplier inputStreamSupplier,
}

public InputStream getInputStream() {
return Quietly.doQuietly(inputStreamSupplier);
return Quietly.doRuntime(inputStreamSupplier);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public final class AesEncoder implements Encoder {
private final AesEngine engine;

public static AesEncoder create(ZipEntry zipEntry) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
AesStrength strength = AesEngine.getStrength(zipEntry.getEncryptionMethod());
byte[] salt = strength.generateSalt();
byte[] key = AesEngine.createKey(zipEntry.getPassword(), salt, strength);
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/ru/olegcherednik/zip4jvm/crypto/aes/AesEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public final class AesEngine implements Engine {

@Override
public byte encrypt(byte b) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
byte bb = cipherUpdate(b);
mac.update(bb);
return bb;
Expand All @@ -71,7 +71,7 @@ public byte encrypt(byte b) {
public int decrypt(byte[] buf, int offs, int len) {
assert len > 0;

Quietly.doQuietly(() -> {
Quietly.doRuntime(() -> {
mac.update(buf, offs, len);
cipherUpdate(buf, offs, len);
});
Expand Down Expand Up @@ -118,15 +118,15 @@ public byte[] getMac() {
}

public static byte[] createKey(char[] password, byte[] salt, AesStrength strength) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
int keyLength = strength.getSize() * 2 + 16;
KeySpec keySpec = new PBEKeySpec(password, salt, ITERATION_COUNT, keyLength);
return SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(keySpec).getEncoded();
});
}

public static Cipher createCipher(SecretKeySpec secretKeySpec) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
// use custom AES implementation, so no worry for DECRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
Expand All @@ -135,7 +135,7 @@ public static Cipher createCipher(SecretKeySpec secretKeySpec) {
}

public static Mac createMac(SecretKeySpec secretKeySpec) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(secretKeySpec);
return mac;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public int getBlockSize() {
public int decrypt(byte[] buf, int offs, int len) {
assert len > 0;

return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
if (decryptedBytes >= compressedSize)
return 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public int getBlockSize() {

@Override
public int decrypt(byte[] buf, int offs, int len) {
return Quietly.doQuietly(() -> cipher.update(buf, offs, len, buf, offs));
return Quietly.doRuntime(() -> cipher.update(buf, offs, len, buf, offs));
}

// ---------- Encrypt ----------
Expand Down Expand Up @@ -88,7 +88,7 @@ public static Cipher createCipher(DecryptionHeader decryptionHeader,
char[] password,
AesStrength strength,
ByteOrder byteOrder) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
IvParameterSpec iv = new IvParameterSpec(decryptionHeader.getIv());
byte[] randomData = decryptRandomData(decryptionHeader, password, strength, iv);
byte[] fileKey = getFileKey(decryptionHeader, randomData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public final class PkwareDecoder implements Decoder {
private final long compressedSize;

public static PkwareDecoder create(ZipEntry zipEntry, DataInput in) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
requireNotEmpty(zipEntry.getPassword(), zipEntry.getFileName() + ".password");

PkwareEngine engine = new PkwareEngine(zipEntry.getPassword());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;

/**
Expand All @@ -50,12 +51,12 @@ public UnzipEngine(SrcZip srcZip, UnzipSettings settings) {

@Override
public void extract(Path dstDir) throws IOException {
unzipExtractEngine.extract(dstDir);
extract(dstDir, Collections.emptySet());
}

@Override
public void extract(Path dstDir, String fileName) throws IOException {
unzipExtractEngine.extract(dstDir, fileName);
extract(dstDir, Collections.singleton(fileName));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
import ru.olegcherednik.zip4jvm.model.password.PasswordProvider;
import ru.olegcherednik.zip4jvm.model.src.SrcZip;
import ru.olegcherednik.zip4jvm.utils.ZipUtils;
import ru.olegcherednik.zip4jvm.utils.quitely.Quietly;
import ru.olegcherednik.zip4jvm.utils.time.DosTimestampConverterUtils;

import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;

Expand All @@ -58,7 +58,6 @@
import java.util.stream.Collectors;

import static ru.olegcherednik.zip4jvm.utils.ValidationUtils.requireNotBlank;
import static ru.olegcherednik.zip4jvm.utils.ValidationUtils.requireNotNull;

/**
* @author Oleg Cherednik
Expand All @@ -70,28 +69,10 @@ public class UnzipExtractEngine {
protected final PasswordProvider passwordProvider;
protected final ZipModel zipModel;

public void extract(Path dstDir) throws IOException {
try (ConsecutiveAccessDataInput in = createConsecutiveDataInput(zipModel.getSrcZip())) {
Iterator<ZipEntry> it = zipModel.offsAscIterator();

while (it.hasNext()) {
ZipEntry zipEntry = it.next();
in.seekForward(zipEntry.getLocalFileHeaderAbsOffs());
extractEntry(dstDir, zipEntry, in, ZipEntry::getFileName);
}
}
}

public void extract(Path dstDir, String fileName) throws IOException {
requireNotBlank(fileName, "UnzipEngine.fileName");
extract(dstDir, Collections.singleton(fileName));
}

public void extract(Path dstDir, Collection<String> fileNames) throws IOException {
requireNotNull(fileNames, "UnzipEngine.fileNames");

Map<String, Function<ZipEntry, String>> map = getEntryNamesByPrefix(new HashSet<>(fileNames));
extract(dstDir, map);
Map<String, Function<ZipEntry, String>> map =
CollectionUtils.isEmpty(fileNames) ? null : getEntryNamesByPrefix(new HashSet<>(fileNames));
extractEntry(dstDir, map);
}

public ZipFile.Entry extract(String fileName) throws IOException {
Expand All @@ -106,21 +87,6 @@ public ZipFile.Entry extract(String fileName) throws IOException {
return zipEntry.createImmutableEntry();
}

protected void extract(Path dstDir, Map<String, Function<ZipEntry, String>> map) throws IOException {
try (ConsecutiveAccessDataInput in = createConsecutiveDataInput(zipModel.getSrcZip())) {
Iterator<ZipEntry> it = zipModel.offsAscIterator();

while (it.hasNext()) {
ZipEntry zipEntry = it.next();

if (map.containsKey(zipEntry.getFileName())) {
in.seekForward(zipEntry.getLocalFileHeaderAbsOffs());
extractEntry(dstDir, zipEntry, in, map.get(zipEntry.getFileName()));
}
}
}
}

protected Map<String, Function<ZipEntry, String>> getEntryNamesByPrefix(Set<String> fileNames) {
Map<String, Function<ZipEntry, String>> map = new HashMap<>();

Expand All @@ -134,7 +100,7 @@ protected Map<String, Function<ZipEntry, String>> getEntryNamesByPrefix(Set<Stri
map.put(zipEntry.getFileName(), ZipEntry::getFileName);
}

return map;
return map.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(map);
}

protected List<ZipEntry> getEntriesNamesByPrefix(String fileNamePrefix) {
Expand All @@ -145,6 +111,24 @@ protected List<ZipEntry> getEntriesNamesByPrefix(String fileNamePrefix) {

// ----------

protected void extractEntry(Path dstDir, Map<String, Function<ZipEntry, String>> map) throws IOException {
try (ConsecutiveAccessDataInput in = createConsecutiveDataInput(zipModel.getSrcZip())) {
Iterator<ZipEntry> it = zipModel.offsAscIterator();

while (it.hasNext()) {
ZipEntry zipEntry = it.next();

if (map == null || map.containsKey(zipEntry.getFileName())) {
in.seekForward(zipEntry.getLocalFileHeaderAbsOffs());


extractEntry(dstDir, zipEntry, in, map == null ? ZipEntry::getFileName
: map.get(zipEntry.getFileName()));
}
}
}
}

protected void extractEntry(Path dstDir,
ZipEntry zipEntry,
DataInput in,
Expand Down Expand Up @@ -197,18 +181,14 @@ protected void extractRegularFile(Path file, ZipEntry zipEntry, DataInput di) th
ZipUtils.copyLarge(in, getOutputStream(file));
}

protected static void setFileAttributes(Path path, ZipEntry zipEntry) {
Quietly.doQuietly(() -> {
if (zipEntry.getExternalFileAttributes() != null)
zipEntry.getExternalFileAttributes().apply(path);
});
protected static void setFileAttributes(Path path, ZipEntry zipEntry) throws IOException {
if (zipEntry.getExternalFileAttributes() != null)
zipEntry.getExternalFileAttributes().apply(path);
}

private static void setFileLastModifiedTime(Path path, ZipEntry zipEntry) {
Quietly.doQuietly(() -> {
long lastModifiedTime = DosTimestampConverterUtils.dosToJavaTime(zipEntry.getLastModifiedTime());
Files.setLastModifiedTime(path, FileTime.fromMillis(lastModifiedTime));
});
private static void setFileLastModifiedTime(Path path, ZipEntry zipEntry) throws IOException {
long lastModifiedTime = DosTimestampConverterUtils.dosToJavaTime(zipEntry.getLastModifiedTime());
Files.setLastModifiedTime(path, FileTime.fromMillis(lastModifiedTime));
}

protected static OutputStream getOutputStream(Path file) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ private static ZipModel createTempZipModel(Path zip, ZipSettings settings, Map<S
}

private static Path createTempZip(Path zip) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
Path dir = zip.getParent().resolve("tmp");
Files.createDirectories(dir);
return dir.resolve(zip.getFileName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public static Path getSymlinkTarget(Path symlink) {
assert Files.exists(symlink) : symlink;
assert Files.isSymbolicLink(symlink) : symlink;

return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
Path resSymlink = symlink;

while (Files.isSymbolicLink(resSymlink)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import java.io.IOException;

/**
* This interface extends {@link DataInput} with adding ability consecutive
* data access. It means that it's able to move forward only.
*
* @author Oleg Cherednik
* @since 20.12.2024
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class OffsOutputStream extends OutputStream {
private long offs;

public static OffsOutputStream create(Path file) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
Files.createDirectories(file.getParent());
return new OffsOutputStream(new BufferedOutputStream(Files.newOutputStream(file)));
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ final class Bzip2EntryDataOutput extends CompressedEntryDataOutput {

Bzip2EntryDataOutput(DataOutput out, CompressionLevel compressionLevel) {
super(out);
bzip2 = Quietly.doQuietly(() -> new Bzip2OutputStream(out, compressionLevel));
bzip2 = Quietly.doRuntime(() -> new Bzip2OutputStream(out, compressionLevel));
}

// ---------- OutputStream ----------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private static LzmaOutputStream createOutputStream(DataOutput out,
CompressionLevel compressionLevel,
boolean eosMarker,
long uncompressedSize) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
LzmaInputStream.Properties properties = new LzmaInputStream.Properties(compressionLevel);
return new LzmaOutputStream(out, properties, eosMarker ? -1 : uncompressedSize);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public static int getTotalDisks(SrcZip srcZip) {

@Override
protected RandomAccessDataInput createDataInput() {
return Quietly.doQuietly(() -> UnzipEngine.createRandomAccessDataInput(srcZip));
return Quietly.doRuntime(() -> UnzipEngine.createRandomAccessDataInput(srcZip));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private BlockModel read(boolean readEntries) throws IOException {

@Override
protected RandomAccessDataInput createDataInput() {
return Quietly.doQuietly(() -> UnzipEngine.createRandomAccessDataInput(srcZip));
return Quietly.doRuntime(() -> UnzipEngine.createRandomAccessDataInput(srcZip));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class ZstdOutputStream extends OutputStream {
private final com.github.luben.zstd.ZstdOutputStream out;

public ZstdOutputStream(DataOutput out, CompressionLevel compressionLevel) {
this.out = Quietly.doQuietly(() -> {
this.out = Quietly.doRuntime(() -> {
OutputStream outStream = new Decorator(out);
int level = compressionLevel(compressionLevel);
return new com.github.luben.zstd.ZstdOutputStream(outStream, level);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public void readFrom(Path path) {
DosFileAttributeView view = Files.getFileAttributeView(path, DosFileAttributeView.class);

if (view != null) {
DosFileAttributes dos = Quietly.doQuietly(view::readAttributes);
DosFileAttributes dos = Quietly.doRuntime(view::readAttributes);
readOnly = dos.isReadOnly();
hidden = dos.isHidden();
system = dos.isSystem();
Expand Down Expand Up @@ -331,7 +331,7 @@ public void readFrom(Path path) {
if (view == null)
return;

Set<PosixFilePermission> permissions = Quietly.doQuietly(() -> view.readAttributes().permissions());
Set<PosixFilePermission> permissions = Quietly.doRuntime(() -> view.readAttributes().permissions());
othersExecute = permissions.contains(OTHERS_EXECUTE);
othersWrite = permissions.contains(OTHERS_WRITE);
othersRead = permissions.contains(OTHERS_READ);
Expand Down
1 change: 0 additions & 1 deletion src/main/java/ru/olegcherednik/zip4jvm/model/ZipModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ public Iterator<ZipEntry> offsAscIterator() {
.sorted(SORT_BY_ABS_OFFS)
.collect(Collectors.toList());

// TODO should be immutable entries
return entries.iterator();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public static ZipEntry symlink(Path symlinkTarget,
String symlinkTargetRelativePath,
String symlinkName,
ZipEntrySettings entrySettings) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
int dosLastModifiedTime = DosTimestampConverterUtils.javaToDosTime(System.currentTimeMillis());
byte[] buf = symlinkTargetRelativePath.getBytes(Charsets.UTF_8);
ZipEntryInputStreamFunction inputStreamFunction = (zipEntry, in) -> new ByteArrayInputStream(buf);
Expand Down Expand Up @@ -118,7 +118,7 @@ public static ZipEntry symlink(Path symlinkTarget,
}

public static ZipEntry emptyDirectory(Path dir, String dirName, ZipEntrySettings entrySettings) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
long lastModifiedTime = Files.getLastModifiedTime(dir).toMillis();
int dosLastModifiedTime = DosTimestampConverterUtils.javaToDosTime(lastModifiedTime);
ExternalFileAttributes externalFileAttributes = ExternalFileAttributes.directory(dir);
Expand All @@ -132,7 +132,7 @@ public static ZipEntry emptyDirectory(Path dir, String dirName, ZipEntrySettings
}

public static ZipEntry regularFile(Path file, String fileName, ZipEntrySettings entrySettings) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
long lastModifiedTime = Files.getLastModifiedTime(file).toMillis();
int dosLastModifiedTime = DosTimestampConverterUtils.javaToDosTime(lastModifiedTime);
long size = Files.size(file);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public final class ChecksumUtils {

@SuppressWarnings({ "NewMethodNamingConvention", "PMD.EmptyControlStatement" })
public static long crc32(InputStream is) {
return Quietly.doQuietly(() -> {
return Quietly.doRuntime(() -> {
Checksum crc32 = new PureJavaCrc32();
InputStream bis = is instanceof BufferedInputStream ? is : new BufferedInputStream(is);

Expand Down
Loading

0 comments on commit 32515e8

Please sign in to comment.