Skip to content

Instantly share code, notes, and snippets.

@obfusk
Last active October 22, 2024 20:18
Show Gist options
  • Save obfusk/ed9f0a960fda19f9baeaeb497202ef1c to your computer and use it in GitHub Desktop.
Save obfusk/ed9f0a960fda19f9baeaeb497202ef1c to your computer and use it in GitHub Desktop.
zip4j workaround for spanned archive marker
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.LocalFileHeader;
public class Test {
private final static int ZIP_DATA_DESCRIPTOR = 0x504b0708;
public static void main(String[] args) {
String zipFileName = args[0];
char[] password = null;
if (args.length > 1) {
String zipPasswordFileName = args[1];
try (BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(zipPasswordFileName)))) {
password = br.readLine().toCharArray();
} catch (IOException e) {
System.err.println("Error: " + e);
}
}
try (InputStream input = new BufferedInputStream(new FileInputStream(zipFileName))) {
spannedArchiveMarkerWorkaround(input);
try (ZipInputStream zipInputStream = new ZipInputStream(input, password)) {
LocalFileHeader localFileHeader;
int files = 0, bytes = 0;
while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
if (!localFileHeader.isDirectory()) {
// String fileName = localFileHeader.getFileName();
// System.out.println("file=" + fileName);
String data = read(zipInputStream);
files++;
bytes += data.length();
}
}
System.out.println("#files=" + files + ", #bytes=" + bytes);
}
} catch (IOException e) {
System.err.println("Error: " + e);
}
}
private static void spannedArchiveMarkerWorkaround(InputStream input) throws IOException {
// Workaround: skip a spanned archive marker (data descriptor header at start of file)
// before passing the stream to ZipInputStream since zip4j cannot handle those.
// NB: we need to wrap with a BufferedInputStream for mark/reset
byte[] buf = new byte[4];
input.mark(4);
for (int i = 0; i < 4; ++i) {
if (input.read(buf, i, 1) != 1) {
throw new IOException("File is less than 4 bytes.");
}
}
if (new BigInteger(1, buf).intValue() != ZIP_DATA_DESCRIPTOR) {
System.out.println("resetting...");
input.reset();
}
}
private static String read(ZipInputStream zipInputStream) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
Reader reader = new BufferedReader(new InputStreamReader(
zipInputStream, StandardCharsets.UTF_8));
int c;
while ((c = reader.read()) != -1) {
stringBuilder.append((char) c);
}
return stringBuilder.toString();
}
}
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
// import java.util.Comparator;
import java.util.List;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
public class Test2 {
public static void main(String[] args) throws IOException {
String zipFileName = args[0];
char[] password = null;
if (args.length > 1) {
String zipPasswordFileName = args[1];
try (BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(zipPasswordFileName)))) {
password = br.readLine().toCharArray();
} catch (IOException e) {
System.err.println("Error: " + e);
}
}
ZipFile zipFile = new ZipFile(zipFileName, password);
List<FileHeader> fileHeaders = zipFile.getFileHeaders();
// fileHeaders.sort(Comparator.comparingLong(FileHeader::getOffsetLocalHeader));
int files = 0, bytes = 0;
for (FileHeader fileHeader : fileHeaders) {
if (!fileHeader.isDirectory()) {
// System.out.println(fileHeader.getFileName());
ZipInputStream zipInputStream = zipFile.getInputStream(fileHeader);
String data = read(zipInputStream);
zipInputStream.close();
files++;
bytes += data.length();
}
}
System.out.println("#files=" + files + ", #bytes=" + bytes);
}
private static String read(ZipInputStream zipInputStream) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
Reader reader = new BufferedReader(new InputStreamReader(
zipInputStream, StandardCharsets.UTF_8));
int c;
while ((c = reader.read()) != -1) {
stringBuilder.append((char) c);
}
return stringBuilder.toString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment