org.anarres.lzo.LzopOutputStream.java Source code

Java tutorial

Introduction

Here is the source code for org.anarres.lzo.LzopOutputStream.java

Source

/*
 * 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.OutputStream;
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;
import org.apache.hadoop.io.DataOutputBuffer;

/**
 *
 * @author shevek
 */
public class LzopOutputStream extends LzoOutputStream {

    private static final Log LOG = LogFactory.getLog(LzopOutputStream.class);
    private final long 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 closed = false;

    /**
     * Constructs a new LzopOutputStream.
     *
     * I recommend limiting flags to the following unless you REALLY know what
     * you are doing:
     * <ul>
     * <li>{@link LzopConstants#F_ADLER32_C}</li>
     * <li>{@link LzopConstants#F_ADLER32_D}</li>
     * <li>{@link LzopConstants#F_CRC32_C}</li>
     * <li>{@link LzopConstants#F_CRC32_D}</li>
     * </ul>
     */
    public LzopOutputStream(OutputStream out, LzoCompressor compressor, int inputBufferSize, long flags)
            throws IOException {
        super(out, compressor, inputBufferSize);
        this.flags = flags;
        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();
        writeLzopHeader();
    }

    public LzopOutputStream(OutputStream out, LzoCompressor compressor, int inputBufferSize) throws IOException {
        this(out, compressor, inputBufferSize, 0L);
    }

    public LzopOutputStream(OutputStream out, LzoCompressor compressor) throws IOException {
        this(out, compressor, 256 * 1024);
    }

    /**
     * Writes an lzop-compatible header to the OutputStream provided.
     */
    protected void writeLzopHeader() throws IOException {
        DataOutputBuffer dob = new DataOutputBuffer();
        try {
            dob.writeShort(LzopConstants.LZOP_VERSION);
            dob.writeShort(LzoVersion.LZO_LIBRARY_VERSION);
            dob.writeShort(LzopConstants.LZOP_COMPAT_VERSION);
            switch (getAlgorithm()) {
            case LZO1X:
                // case LZO1X_1:
                dob.writeByte(LzopConstants.M_LZO1X_1);
                dob.writeByte(5);
                break;
            /*
            case LZO1X_15:
            dob.writeByte(LzopConstants.M_LZO1X_1_15);
            dob.writeByte(1);
            break;
            case LZO1X_999:
            dob.writeByte(LzopConstants.M_LZO1X_999);
            dob.writeByte(9);
            break;
             */
            default:
                throw new IOException("Incompatible lzop algorithm " + getAlgorithm());
            }
            long mask = LzopConstants.F_ADLER32_C | LzopConstants.F_ADLER32_D;
            mask = mask | LzopConstants.F_CRC32_C | LzopConstants.F_CRC32_D;
            dob.writeInt((int) (flags & mask & 0xFFFFFFFF)); // all flags 0
            dob.writeInt(33188); // mode
            dob.writeInt((int) (System.currentTimeMillis() / 1000)); // mtime
            dob.writeInt(0); // gmtdiff ignored
            dob.writeByte(0); // no filename
            Adler32 headerChecksum = new Adler32();
            headerChecksum.update(dob.getData(), 0, dob.getLength());
            int hc = (int) headerChecksum.getValue();
            dob.writeInt(hc);
            out.write(LzopConstants.LZOP_MAGIC);
            out.write(dob.getData(), 0, dob.getLength());
        } finally {
            dob.close();
        }
    }

    private void writeChecksum(Checksum csum, byte[] data, int off, int len) throws IOException {
        if (csum == null)
            return;
        csum.reset();
        csum.update(data, off, len);
        long value = csum.getValue();
        // LOG.info("Writing checksum " + csum);
        writeInt((int) (value & 0xFFFFFFFF));
    }

    @Override
    protected void writeBlock(byte[] inputData, int inputPos, int inputLen, byte[] outputData, int outputPos,
            int outputLen) throws IOException {
        // LOG.info("inputLen=" + inputLen + "; outputLen=" + outputLen);
        writeInt(inputLen);
        if (outputLen < inputLen)
            writeInt(outputLen);
        else
            writeInt(inputLen);

        // This is where we put checksums, if any.
        writeChecksum(c_adler32_d, inputData, inputPos, inputLen);
        writeChecksum(c_crc32_d, inputData, inputPos, inputLen);
        if (outputLen < inputLen) {
            writeChecksum(c_adler32_c, outputData, outputPos, outputLen);
            writeChecksum(c_crc32_c, outputData, outputPos, outputLen);
        }

        if (outputLen < inputLen)
            out.write(outputData, outputPos, outputLen);
        else
            out.write(inputData, inputPos, inputLen);
    }

    /**
     * Writes a null word to the underlying output stream, then closes it.
     */
    @Override
    public void close() throws IOException {
        if (!closed) {
            flush();
            out.write(new byte[] { 0, 0, 0, 0 });
            super.close();
            closed = true;
        }
    }
}