I used kzip last year, but it doesn’t support the gzip file format. Therefore here is a utility I’ve knocked up which converts zip files into gzip files. It makes various assumptions (only the first file in the zip is processed; the zip is assumed to give CRC, compressed size, and uncompressed size before the data block rather than after it). I’ve tested it with kzip and ensured that the result is correct.
Error handling is about what you’d expect from a throwaway tool (i.e. minimal).
Not yet tested on a .pack file, but I’m about to go to bed so I’ll put it up for people to play with.
import java.io.*;
// Based on http://www.gzip.org/zlib/rfc-gzip.html
// and http://www.pkware.com/documents/casestudies/APPNOTE.TXT
public class Zip2Gzip
{
// Usage: java Zip2Gzip [file.zip [file.gzip]]
public static void main(String[] args) throws IOException
{
InputStream in = args.length < 1 ? System.in : new FileInputStream(args[0]);
in = new BufferedInputStream(in);
OutputStream out = args.length < 2 ? System.out : new FileOutputStream(args[1]);
out = new BufferedOutputStream(out);
// Start by writing a gzip header.
// Magic.
out.write(0x1f);
out.write(0x8b);
// Compression method: inflate.
out.write(0x08);
// Flags: we include no optional extras.
out.write(0x00);
// Timestamp: unavailable.
out.write(0x00);
out.write(0x00);
out.write(0x00);
out.write(0x00);
// Extra flags: none.
out.write(0x00);
// OS: unknown.
out.write(0xff);
// The next block of output is the compressed data. We need to process
// the zip file header to find it and know how long it is.
// local file header signature 4 bytes (0x04034b50)
// version needed to extract 2 bytes
// general purpose bit flag 2 bytes
// compression method 2 bytes
// last mod file time 2 bytes
// last mod file date 2 bytes
// Total so far: 14 bytes
for (int i = 0; i < 14; i++) in.read();
// crc-32 4 bytes
int crc1 = in.read();
int crc2 = in.read();
int crc3 = in.read();
int crc4 = in.read();
// compressed size 4 bytes
int cmpSz = (in.read() & 0xff) +
((in.read() & 0xff) << 8) +
((in.read() & 0xff) << 16) +
((in.read() & 0xff) << 24);
// uncompressed size 4 bytes
int ucmpSz1 = in.read();
int ucmpSz2 = in.read();
int ucmpSz3 = in.read();
int ucmpSz4 = in.read();
// file name length 2 bytes
int nameLen = (in.read() & 0xff) + ((in.read() & 0xff) << 8);
// extra field length 2 bytes
int xfLen = (in.read() & 0xff) + ((in.read() & 0xff) << 8);
// file name (variable size)
for (int i = 0; i < nameLen; i++) in.read();
// extra field (variable size)
for (int i = 0; i < xfLen; i++) in.read();
// Data follows, so we can copy it to the output.
byte[] buf = new byte[4096];
while (cmpSz > 0)
{
int desired = cmpSz > buf.length ? buf.length : cmpSz;
int len = in.read(buf, 0, desired);
if (len == 0) throw new EOFException();
out.write(buf, 0, len);
cmpSz -= len;
}
// The output still needs the CRC32 and the uncompressed size.
out.write(crc1);
out.write(crc2);
out.write(crc3);
out.write(crc4);
out.write(ucmpSz1);
out.write(ucmpSz2);
out.write(ucmpSz3);
out.write(ucmpSz4);
// Done. Be tidy.
out.close();
in.close();
}
}