package org.vafer.lzo; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.DataFormatException; import org.apache.commons.io.input.CountingInputStream; public final class LzoIndexer { private final static long F_ADLER32_D = 0x00000001L; private final static long F_ADLER32_C = 0x00000002L; private final static long F_CRC32_D = 0x00000100L; private final static long F_CRC32_C = 0x00000200L; private final static long F_H_FILTER = 0x00000800L; private final static long F_H_EXTRA_FIELD = 0x00000040L; private final static byte magic[] = { (byte)0x89, 0x4C, 0x5A, 0x4f, 0x00, 0x0D, 0x0A, 0x1A, 0x0A }; public void createIndex(InputStream fis, OutputStream fos) throws IOException, DataFormatException { try { CountingInputStream cis = new CountingInputStream(fis); DataInputStream is = new DataInputStream(cis); DataOutputStream os = new DataOutputStream(fos); byte m[] = new byte[magic.length]; if (is.read(m) != m.length) { throw new DataFormatException("failed to read header"); } for (int i = 0; i < m.length; i++) { if (magic[i] != m[i]) { throw new DataFormatException("not a lzo file " + i); } } int version = is.readShort(); // version if (version < 0x0900) { throw new DataFormatException("cannot read version " + version); } is.readShort(); // lib version if (version >= 0x0940) { is.readShort(); // extract version } is.readByte(); // method if (version >= 0x0940) { is.readByte(); // level } int flags = is.readInt(); if ((flags & F_H_FILTER) != 0) { is.readInt(); // filter } int numCompressedChecksums = 0; if ((flags & F_ADLER32_C) != 0) numCompressedChecksums++; if ((flags & F_CRC32_C) != 0) numCompressedChecksums++; int numDecompressedChecksums = 0; if ((flags & F_ADLER32_D) != 0) numDecompressedChecksums++; if ((flags & F_CRC32_D) != 0) numDecompressedChecksums++; is.readInt(); // mode is.readInt(); // mtime_low if (version >= 0x0940) { is.readInt(); // mtime_high } int len = is.readUnsignedByte(); // name len char[] name = new char[len]; for(int i=0; i<len; i++) { name[i] = (char)is.readByte(); } is.readInt(); // checksum if ((flags & F_H_EXTRA_FIELD) != 0) { int extra_len = is.readInt(); for(int i=0; i<extra_len; i++) { is.readByte(); } is.readInt(); // checksum } while(true) { long pos = cis.getByteCount(); long uncompressed_blocksize = is.readInt(); if (uncompressed_blocksize == 0) { break; } long compressed_blocksize = is.readInt(); os.writeLong(pos); int numChecksumsToSkip = (uncompressed_blocksize == compressed_blocksize) ? numDecompressedChecksums : numDecompressedChecksums + numCompressedChecksums; long skip = compressed_blocksize + (4 * numChecksumsToSkip); while(skip > 0) { long s = is.skip(skip); if (s > 0) { skip -= s; } } } } finally { fis.close(); fos.close(); } } }