Java tutorial
/* * This file is part of lzo-java, an implementation of LZO in Java. * https://github.com/Karmasphere/lzo-java * * The Java portion of this library is: * Copyright (C) 2011 Shevek <shevek@anarres.org> * All Rights Reserved. * * The preprocessed C portion of this library is: * Copyright (C) 2006-2011 Markus Franz Xaver Johannes Oberhumer * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with the LZO library; see the file COPYING. * If not, see <http://www.gnu.org/licenses/> or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301, USA. * As a special exception, the copyright holders of this file * give you permission to link this file with independent * modules to produce an executable, regardless of the license * terms of these independent modules, and to copy and distribute * the resulting executable under terms of your choice, provided * that you also meet, for each linked independent module, * the terms and conditions of the license of that module. An * independent module is a module which is not derived from or * based on this library or file. If you modify this file, you may * extend this exception to your version of the file, but * you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. */ package org.anarres.lzo; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.zip.Adler32; import java.util.zip.CRC32; import java.util.zip.Checksum; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * * @author shevek */ public class LzopInputStream extends LzoInputStream { private static final Log LOG = LogFactory.getLog(LzopInputStream.class); private final int flags; private final CRC32 c_crc32_c; private final CRC32 c_crc32_d; private final Adler32 c_adler32_c; private final Adler32 c_adler32_d; private boolean eof; public LzopInputStream(InputStream in) throws IOException { super(in, new LzoDecompressor1x()); this.flags = readHeader(); this.c_crc32_c = ((flags & LzopConstants.F_CRC32_C) == 0) ? null : new CRC32(); this.c_crc32_d = ((flags & LzopConstants.F_CRC32_D) == 0) ? null : new CRC32(); this.c_adler32_c = ((flags & LzopConstants.F_ADLER32_C) == 0) ? null : new Adler32(); this.c_adler32_d = ((flags & LzopConstants.F_ADLER32_D) == 0) ? null : new Adler32(); this.eof = false; // logState(); } public int getFlags() { return flags; } public int getCompressedChecksumCount() { int out = 0; if (c_crc32_c != null) out++; if (c_adler32_c != null) out++; return out; } public int getUncompressedChecksumCount() { int out = 0; if (c_crc32_d != null) out++; if (c_adler32_d != null) out++; return out; } protected void logState(String when) { super.logState(when); LOG.info(when + " Flags = " + Integer.toHexString(flags)); // LOG.info(when + " CRC32C = " + c_crc32_c); // LOG.info(when + " CRC32D = " + c_crc32_d); // LOG.info(when + " Adler32C = " + c_adler32_c); // LOG.info(when + " Adler32D = " + c_adler32_d); } /** * Read len bytes into buf, st LSB of int returned is the last byte of the * first word read. */ private int readInt(byte[] buf, int len) throws IOException { readBytes(buf, 0, len); int ret = (0xFF & buf[0]) << 24; ret |= (0xFF & buf[1]) << 16; ret |= (0xFF & buf[2]) << 8; ret |= (0xFF & buf[3]); return (len > 3) ? ret : (ret >>> (8 * (4 - len))); } /** * Read bytes, update checksums, return first four bytes as an int, first * byte read in the MSB. */ private int readHeaderItem(byte[] buf, int len, Adler32 adler, CRC32 crc32) throws IOException { int ret = readInt(buf, len); adler.update(buf, 0, len); crc32.update(buf, 0, len); Arrays.fill(buf, (byte) 0); return ret; } /** * Read and verify an lzo header, setting relevant block checksum options * and ignoring most everything else. */ protected int readHeader() throws IOException { byte[] buf = new byte[9]; readBytes(buf, 0, 9); if (!Arrays.equals(buf, LzopConstants.LZOP_MAGIC)) throw new IOException("Invalid LZO header"); Arrays.fill(buf, (byte) 0); Adler32 adler = new Adler32(); CRC32 crc32 = new CRC32(); int hitem = readHeaderItem(buf, 2, adler, crc32); // lzop version if (hitem > LzopConstants.LZOP_VERSION) { LOG.debug("Compressed with later version of lzop: " + Integer.toHexString(hitem) + " (expected 0x" + Integer.toHexString(LzopConstants.LZOP_VERSION) + ")"); } hitem = readHeaderItem(buf, 2, adler, crc32); // lzo library version if (hitem > LzoVersion.LZO_LIBRARY_VERSION) { throw new IOException("Compressed with incompatible lzo version: 0x" + Integer.toHexString(hitem) + " (expected 0x" + Integer.toHexString(LzoVersion.LZO_LIBRARY_VERSION) + ")"); } hitem = readHeaderItem(buf, 2, adler, crc32); // lzop extract version if (hitem > LzopConstants.LZOP_VERSION) { throw new IOException("Compressed with incompatible lzop version: 0x" + Integer.toHexString(hitem) + " (expected 0x" + Integer.toHexString(LzopConstants.LZOP_VERSION) + ")"); } hitem = readHeaderItem(buf, 1, adler, crc32); // method switch (hitem) { case LzopConstants.M_LZO1X_1: case LzopConstants.M_LZO1X_1_15: case LzopConstants.M_LZO1X_999: break; default: throw new IOException("Invalid strategy " + Integer.toHexString(hitem)); } readHeaderItem(buf, 1, adler, crc32); // ignore level // flags int flags = readHeaderItem(buf, 4, adler, crc32); boolean useCRC32 = (flags & LzopConstants.F_H_CRC32) != 0; boolean extraField = (flags & LzopConstants.F_H_EXTRA_FIELD) != 0; if ((flags & LzopConstants.F_MULTIPART) != 0) throw new IOException("Multipart lzop not supported"); if ((flags & LzopConstants.F_H_FILTER) != 0) throw new IOException("lzop filter not supported"); if ((flags & LzopConstants.F_RESERVED) != 0) throw new IOException("Unknown flags in header"); // known !F_H_FILTER, so no optional block readHeaderItem(buf, 4, adler, crc32); // ignore mode readHeaderItem(buf, 4, adler, crc32); // ignore mtime readHeaderItem(buf, 4, adler, crc32); // ignore gmtdiff hitem = readHeaderItem(buf, 1, adler, crc32); // fn len if (hitem > 0) { byte[] tmp = (hitem > buf.length) ? new byte[hitem] : buf; readHeaderItem(tmp, hitem, adler, crc32); // skip filename } int checksum = (int) (useCRC32 ? crc32.getValue() : adler.getValue()); hitem = readHeaderItem(buf, 4, adler, crc32); // read checksum if (hitem != checksum) { throw new IOException("Invalid header checksum: " + Long.toHexString(checksum) + " (expected 0x" + Integer.toHexString(hitem) + ")"); } if (extraField) { // lzop 1.08 ultimately ignores this LOG.debug("Extra header field not processed"); adler.reset(); crc32.reset(); hitem = readHeaderItem(buf, 4, adler, crc32); readHeaderItem(new byte[hitem], hitem, adler, crc32); checksum = (int) (useCRC32 ? crc32.getValue() : adler.getValue()); if (checksum != readHeaderItem(buf, 4, adler, crc32)) { throw new IOException("Invalid checksum for extra header field"); } } return flags; } private int readChecksum(Checksum csum) throws IOException { if (csum == null) return 0; // LOG.info("Reading checksum " + csum); return readInt(false); } private void testChecksum(Checksum csum, int value, byte[] data, int off, int len) throws IOException { if (csum == null) return; csum.reset(); csum.update(data, off, len); if (value != (int) csum.getValue()) throw new IOException("Checksum failure: " + "Expected " + Integer.toHexString(value) + "; got " + Long.toHexString(csum.getValue())); } @Override protected boolean readBlock() throws IOException { // logState("Before readBlock"); if (eof) return false; int outputBufferLength = readInt(false); if (outputBufferLength == 0) { // logState("After empty readBlock"); eof = true; return false; } setOutputBufferSize(outputBufferLength); int inputBufferLength = readInt(false); setInputBufferSize(inputBufferLength); int v_adler32_d = readChecksum(c_adler32_d); int v_crc32_d = readChecksum(c_crc32_d); // LOG.info("outputBufferLength=" + outputBufferLength + "; inputBufferLength=" + inputBufferLength); if (outputBufferLength == inputBufferLength) { outputBufferPos = 0; outputBufferLen.value = outputBufferLength; readBytes(outputBuffer, 0, outputBufferLength); testChecksum(c_adler32_d, v_adler32_d, outputBuffer, 0, outputBufferLength); testChecksum(c_crc32_d, v_crc32_d, outputBuffer, 0, outputBufferLength); // logState("After uncompressed readBlock"); return true; } int v_adler32_c = readChecksum(c_adler32_c); int v_crc32_c = readChecksum(c_crc32_c); readBytes(inputBuffer, 0, inputBufferLength); testChecksum(c_adler32_c, v_adler32_c, inputBuffer, 0, inputBufferLength); testChecksum(c_crc32_c, v_crc32_c, inputBuffer, 0, inputBufferLength); decompress(outputBufferLength, inputBufferLength); testChecksum(c_adler32_d, v_adler32_d, outputBuffer, 0, outputBufferLength); testChecksum(c_crc32_d, v_crc32_d, outputBuffer, 0, outputBufferLength); // logState("After compressed readBlock"); return true; } }