55 lines
2.4 KiB
Java
55 lines
2.4 KiB
Java
|
|
import java.io.*;
|
||
|
|
import java.util.*;
|
||
|
|
import java.util.zip.*;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Minimal zipalign: copies a zip, padding STORED entries so their data is 4-byte aligned,
|
||
|
|
* and appends any extra files given after the output path (compressed, at the zip root).
|
||
|
|
*/
|
||
|
|
public class ZipAlign {
|
||
|
|
public static void main(String[] a) throws IOException {
|
||
|
|
try (ZipFile in = new ZipFile(a[0]);
|
||
|
|
CountingOut cnt = new CountingOut(new BufferedOutputStream(new FileOutputStream(a[1])));
|
||
|
|
ZipOutputStream out = new ZipOutputStream(cnt)) {
|
||
|
|
for (ZipEntry e : Collections.list(in.entries())) {
|
||
|
|
ZipEntry n = new ZipEntry(e.getName());
|
||
|
|
n.setMethod(e.getMethod());
|
||
|
|
n.setTime(946684800000L); // 2000-01-01, inside the DOS date range (no extra timestamp field)
|
||
|
|
if (e.getMethod() == ZipEntry.STORED) {
|
||
|
|
n.setSize(e.getSize());
|
||
|
|
n.setCompressedSize(e.getSize());
|
||
|
|
n.setCrc(e.getCrc());
|
||
|
|
out.flush();
|
||
|
|
long dataStart = cnt.count + 30 + n.getName().getBytes("UTF-8").length;
|
||
|
|
int pad = (int) ((4 - dataStart % 4) % 4);
|
||
|
|
if (pad > 0) n.setExtra(padExtra(pad));
|
||
|
|
}
|
||
|
|
out.putNextEntry(n);
|
||
|
|
in.getInputStream(e).transferTo(out);
|
||
|
|
out.closeEntry();
|
||
|
|
}
|
||
|
|
for (int i = 2; i < a.length; i++) {
|
||
|
|
File f = new File(a[i]);
|
||
|
|
ZipEntry n = new ZipEntry(f.getName());
|
||
|
|
n.setTime(946684800000L);
|
||
|
|
out.putNextEntry(n);
|
||
|
|
try (InputStream fin = new FileInputStream(f)) { fin.transferTo(out); }
|
||
|
|
out.closeEntry();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// An extra field needs a 4-byte header, so use one field of pad+4 bytes (Android's 0xD935 alignment tag).
|
||
|
|
static byte[] padExtra(int pad) {
|
||
|
|
byte[] x = new byte[pad + 4];
|
||
|
|
x[0] = 0x35; x[1] = (byte) 0xD9; x[2] = (byte) pad;
|
||
|
|
return x;
|
||
|
|
}
|
||
|
|
|
||
|
|
static class CountingOut extends FilterOutputStream {
|
||
|
|
long count;
|
||
|
|
CountingOut(OutputStream o) { super(o); }
|
||
|
|
@Override public void write(int b) throws IOException { out.write(b); count++; }
|
||
|
|
@Override public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); count += len; }
|
||
|
|
}
|
||
|
|
}
|