connectbot/sshlib

View on GitHub
src/main/java/com/trilead/ssh2/compression/Zlib.java

Summary

Maintainability
A
2 hrs
Test Coverage
C
74%
/*
 * Copyright 2007 Kenny Root, Jeffrey Sharkey
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * a.) Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * b.) Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * c.) Neither the name of Trilead nor the names of its contributors may
 *     be used to endorse or promote products derived from this software
 *     without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package com.trilead.ssh2.compression;

import com.jcraft.jzlib.JZlib;
import com.jcraft.jzlib.ZStream;

/**
 * @author Kenny Root
 *
 */
public class Zlib implements ICompressor {
    static private final int DEFAULT_BUF_SIZE = 4096;
    static private final int LEVEL = 5;

    private ZStream deflate;
    private byte[] deflate_tmpbuf;

    private ZStream inflate;
    private byte[] inflate_tmpbuf;
    private byte[] inflated_buf;

    public Zlib() {
        deflate = new ZStream();
        inflate = new ZStream();

        deflate.deflateInit(LEVEL);
        inflate.inflateInit();

        deflate_tmpbuf = new byte[DEFAULT_BUF_SIZE];
        inflate_tmpbuf = new byte[DEFAULT_BUF_SIZE];
        inflated_buf = new byte[DEFAULT_BUF_SIZE];
    }

    public boolean canCompressPreauth() {
        return true;
    }

    public int getBufferSize() {
        return DEFAULT_BUF_SIZE;
    }

    public int compress(byte[] buf, int start, int len, byte[] output) {
        deflate.next_in = buf;
        deflate.next_in_index = start;
        deflate.avail_in = len - start;

        if ((buf.length + 1024) > deflate_tmpbuf.length) {
            deflate_tmpbuf = new byte[buf.length + 1024];
        }

        deflate.next_out = deflate_tmpbuf;
        deflate.next_out_index = 0;
        deflate.avail_out = output.length;

        if (deflate.deflate(JZlib.Z_PARTIAL_FLUSH) != JZlib.Z_OK) {
            System.err.println("compress: compression failure");
        }

        if (deflate.avail_in > 0) {
            System.err.println("compress: deflated data too large");
        }

        int outputlen = output.length - deflate.avail_out;

        System.arraycopy(deflate_tmpbuf, 0, output, 0, outputlen);

        return outputlen;
    }

    public byte[] uncompress(byte[] buffer, int start, int[] length) {
        int inflated_end = 0;

        inflate.next_in = buffer;
        inflate.next_in_index = start;
        inflate.avail_in = length[0];

        while (true) {
            inflate.next_out = inflate_tmpbuf;
            inflate.next_out_index = 0;
            inflate.avail_out = DEFAULT_BUF_SIZE;
            int status = inflate.inflate(JZlib.Z_PARTIAL_FLUSH);
            switch (status) {
            case JZlib.Z_OK:
                if (inflated_buf.length < inflated_end + DEFAULT_BUF_SIZE
                        - inflate.avail_out) {
                    byte[] foo = new byte[inflated_end + DEFAULT_BUF_SIZE
                            - inflate.avail_out];
                    System.arraycopy(inflated_buf, 0, foo, 0, inflated_end);
                    inflated_buf = foo;
                }
                System.arraycopy(inflate_tmpbuf, 0, inflated_buf, inflated_end,
                        DEFAULT_BUF_SIZE - inflate.avail_out);
                inflated_end += (DEFAULT_BUF_SIZE - inflate.avail_out);
                length[0] = inflated_end;
                break;
            case JZlib.Z_BUF_ERROR:
                if (inflated_end > buffer.length - start) {
                    byte[] foo = new byte[inflated_end + start];
                    System.arraycopy(buffer, 0, foo, 0, start);
                    System.arraycopy(inflated_buf, 0, foo, start, inflated_end);
                    buffer = foo;
                } else {
                    System.arraycopy(inflated_buf, 0, buffer, start,
                            inflated_end);
                }
                length[0] = inflated_end;
                return buffer;
            default:
                System.err.println("uncompress: inflate returnd " + status);
                return null;
            }
        }
    }
}