/*
    Zlib – библиотека сжатия данных общего назначения. Версия 1.1.0
    Это изменённая объектно-ориентированная версия библиотеки, полностью
    совместимая с оригинальной библиотекой.
    
    Copyright © 1995–2005 Jean-loup Gailly и Mark Adler
    Copyright © 2000–2011 ymnk, JCraft, Inc.
    Copyright © 2016–2017, 2019–2022 Малик Разработчик
    
    Эта библиотека поставляется «как есть», без каких-либо явных или
    подразумеваемых гарантий. Ни при каких обстоятельствах авторы не
    несут какой-либо ответственности в случае потери данных вследствие
    использования данной библиотеки.
    
    Разрешается всем использовать эту библиотеку для любых целей, в том
    числе и для коммерческих приложений, а также изменять её и
    распространять свободно при соблюдении следующих условий:
    
        1. Оригинал библиотеки не должен быть искажён; вы не должны
    заявлять, что именно вы написали оригинальную библиотеку. Если вы
    используете эту библиотеку в своём программном продукте, то ссылка
    на авторов библиотеки была бы желательна, но это не является
    обязательным требованием.
    
        2. Изменённые версии исходных текстов должны быть отчётливо
    маркированы и не должны выдаваться за оригинал библиотеки.
    
        3. Эти замечания не могут быть удалены либо изменены при
    каком-либо варианте распространения исходных текстов.
*/

package malik.emulator.compression.zlib;

import java.io.*;

public class Zlib extends Object
{
    /* wbits */
    public static final int MAX_WBITS =        15;
    public static final int DEF_WBITS = MAX_WBITS;

    /* уровни сжатия */
    public static final int DEFAULT_COMPRESSION       = -1;
    public static final int NO_COMPRESSION            =  0;
    public static final int BEST_SPEED                =  1;
    public static final int OPTIMAL_SPEED_COMPRESSION =  7;
    public static final int BEST_COMPRESSION          =  9;

    /* стратегии сжатия */
    public static final int DEFAULT_STRATEGY = 0;
    public static final int FILTERED         = 1;
    public static final int HUFFMAN_ONLY     = 2;

    /* режимы ввода-вывода */
    public static final int NO_FLUSH      = 0;
    public static final int PARTIAL_FLUSH = 1;
    public static final int SYNC_FLUSH    = 2;
    public static final int FULL_FLUSH    = 3;
    public static final int FINISH        = 4;

    /* возвращаемые значения */
    public static final int VERSION_ERROR = -6;
    public static final int BUF_ERROR     = -5;
    public static final int MEM_ERROR     = -4;
    public static final int DATA_ERROR    = -3;
    public static final int STREAM_ERROR  = -2;
    public static final int ERRNO         = -1;
    public static final int OK            =  0;
    public static final int STREAM_END    =  1;
    public static final int NEED_DICT     =  2;

    public static byte[] compress(byte[] src) {
        return compress(src, 0, src.length, OPTIMAL_SPEED_COMPRESSION, true);
    }

    public static byte[] compress(byte[] src, boolean defaultInit) {
        return compress(src, 0, src.length, OPTIMAL_SPEED_COMPRESSION, defaultInit);
    }

    public static byte[] compress(byte[] src, int level) {
        return compress(src, 0, src.length, level, true);
    }

    public static byte[] compress(byte[] src, int level, boolean defaultInit) {
        return compress(src, 0, src.length, level, defaultInit);
    }

    public static byte[] compress(byte[] src, int offset, int length) {
        return compress(src, offset, length, OPTIMAL_SPEED_COMPRESSION, true);
    }

    public static byte[] compress(byte[] src, int offset, int length, boolean defaultInit) {
        return compress(src, offset, length, OPTIMAL_SPEED_COMPRESSION, defaultInit);
    }

    public static byte[] compress(byte[] src, int offset, int length, int level) {
        return compress(src, offset, length, level, true);
    }

    public static byte[] compress(byte[] src, int offset, int length, int level, boolean defaultInit) {
        int zlibResult;
        long totalOut = 0L;
        byte[] result = new byte[0x10000];
        ZStream compressor = new ZStream();
        ByteArrayOutputStream tempStream = new ByteArrayOutputStream();
        if(defaultInit)
        {
            compressor.deflateInit(level);
        } else
        {
            compressor.deflateInit(level, -MAX_WBITS);
        }
        compressor.setInput(src, offset, length, false);
        do
        {
            compressor.setOutput(result);
            zlibResult = compressor.deflate(FINISH);
            tempStream.write(result, 0, (int) (compressor.getTotalOut() - totalOut));
            if(zlibResult == STREAM_END)
            {
                compressor.deflateEnd();
                break;
            }
            totalOut = compressor.getTotalOut();
        } while(true);
        return tempStream.toByteArray();
    }

    public static byte[] decompress(byte[] src) {
        return decompress(src, 0, src.length, true);
    }

    public static byte[] decompress(byte[] src, boolean defaultInit) {
        return decompress(src, 0, src.length, defaultInit);
    }

    public static byte[] decompress(byte[] src, int offset, int length) {
        return decompress(src, offset, length, true);
    }

    public static byte[] decompress(byte[] src, int offset, int length, boolean defaultInit) {
        long totalOut = 0L;
        byte[] result = new byte[0x10000];
        ZStream decompressor = new ZStream();
        ByteArrayOutputStream tempStream = new ByteArrayOutputStream();
        if(defaultInit)
        {
            decompressor.inflateInit();
        } else
        {
            decompressor.inflateInit(-MAX_WBITS);
        }
        decompressor.setInput(src, offset, length, false);
        do
        {
            int zlibResult;
            decompressor.setOutput(result);
            zlibResult = decompressor.inflate(NO_FLUSH);
            tempStream.write(result, 0, (int) (decompressor.getTotalOut() - totalOut));
            if(zlibResult == STREAM_END || zlibResult < 0)
            {
                decompressor.inflateEnd();
                break;
            }
            totalOut = decompressor.getTotalOut();
        } while(true);
        return tempStream.toByteArray();
    }

    public static String version() {
        return "1.1.0";
    }

    Zlib() {
    }
}
