Last active
October 22, 2024 20:18
-
-
Save obfusk/ed9f0a960fda19f9baeaeb497202ef1c to your computer and use it in GitHub Desktop.
zip4j workaround for spanned archive marker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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