/*
 * SDK Pullenti Unitext, version 4.33, fabruary 2026. Copyright (c) 2013-2026, Pullenti. All rights reserved. 
 * Non-Commercial Freeware and Commercial Software. 
 * This class is generated using the converter Unisharping (www.unisharping.ru) from Pullenti C# project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

package com.pullenti.unitext.internal.zip;

// This filter stream is used to decompress data compressed using the "deflate"
// format. The "deflate" format is described in RFC 1951.
// This stream may form the basis for other decompression filters, such
// as the <see cref="ICSharpCode.SharpZipLib.GZip.GZipInputStream">GZipInputStream</see>.
public class InflaterInputStream extends com.pullenti.unisharp.Stream {

    public InflaterInputStream(com.pullenti.unisharp.Stream _baseInputStream, Inflater inflater, int bufferSize) throws IllegalArgumentException, IndexOutOfBoundsException {
        super();
        if (inflater == null) 
            inflater = new Inflater(false);
        if (_baseInputStream == null) 
            throw new IllegalArgumentException("baseInputStream");
        if (inflater == null) 
            throw new IllegalArgumentException("inflater");
        if (bufferSize <= 0) 
            throw new IndexOutOfBoundsException("bufferSize");
        this.baseInputStream = _baseInputStream;
        this.inf = inflater;
        inputBuffer = new InflaterInputBuffer(_baseInputStream, bufferSize);
    }

    public boolean isStreamOwner() {
        return m_IsStreamOwner;
    }

    public boolean setStreamOwner(boolean value) {
        m_IsStreamOwner = value;
        return value;
    }


    public int skip(int count) throws IndexOutOfBoundsException, java.io.IOException {
        if (count <= 0) 
            throw new IndexOutOfBoundsException("count");
        if (baseInputStream.canSeek()) {
            baseInputStream.seek((long)count, 1);
            return count;
        }
        else {
            int _length = 2048;
            if (count < _length) 
                _length = count;
            byte[] tmp = new byte[_length];
            int readCount = 1;
            int toSkip = count;
            while ((toSkip > 0) && (readCount > 0)) {
                if (toSkip < _length) 
                    _length = toSkip;
                readCount = baseInputStream.read(tmp, 0, _length);
                toSkip -= readCount;
            }
            return count - toSkip;
        }
    }

    public int getAvailable() {
        return (inf.isFinished() ? 0 : 1);
    }


    protected void fill() throws Exception, java.io.IOException, IllegalArgumentException, IndexOutOfBoundsException, UnsupportedOperationException {
        if (inputBuffer.getAvailable() <= 0) {
            inputBuffer.fill();
            if (inputBuffer.getAvailable() <= 0) 
                throw new Exception("Unexpected EOF");
        }
        inputBuffer.setInflaterInput(inf);
    }

    @Override
    public boolean canRead() {
        return baseInputStream.canRead();
    }


    @Override
    public boolean canSeek() {
        return false;
    }


    @Override
    public boolean canWrite() {
        return false;
    }


    @Override
    public long length() {
        return (long)inputBuffer.getRawLength();
    }


    @Override
    public long getPosition() throws java.io.IOException {
        return baseInputStream.getPosition();
    }

    @Override
    public long setPosition(long value) {
        return value;
    }


    @Override
    public void flush() throws java.io.IOException {
        baseInputStream.flush();
    }

    @Override
    public long seek(long offset, int origin) {
        return 0L;
    }

    @Override
    public void setLength(long value) throws java.io.IOException {
        throw new java.io.IOException("InflaterInputStream SetLength not supported");
    }

    @Override
    public void write(byte[] buffer, int offset, int count) throws java.io.IOException {
        throw new java.io.IOException("InflaterInputStream Write not supported");
    }

    @Override
    public void write(byte value) throws java.io.IOException {
        throw new java.io.IOException("InflaterInputStream WriteByte not supported");
    }

    @Override
    public void close() throws java.io.IOException {
        if (!isClosed) {
            isClosed = true;
            if (m_IsStreamOwner) 
                baseInputStream.close();
        }
    }

    @Override
    public int read(byte[] buffer, int offset, int count) throws java.io.IOException {
        if (inf.isNeedingDictionary()) 
            throw new java.io.IOException("Need a dictionary");
        int remainingBytes = count;
        while (true) {
            int bytesRead = 0;
            try {
                bytesRead = inf.inflateEx(buffer, offset, remainingBytes);
            } catch (Exception ex) {
                throw new java.io.IOException(ex.getMessage(), ex);
            }
            offset += bytesRead;
            remainingBytes -= bytesRead;
            if (remainingBytes == 0 || inf.isFinished()) 
                break;
            if (inf.isNeedingInput()) {
                try {
                    this.fill();
                } catch (Exception ex) {
                    throw new java.io.IOException(ex.getMessage(), ex);
                }
            }
            else if (bytesRead == 0) 
                throw new java.io.IOException("Dont know what to do");
        }
        return count - remainingBytes;
    }

    protected Inflater inf;

    protected InflaterInputBuffer inputBuffer;

    private com.pullenti.unisharp.Stream baseInputStream;

    protected int csize;

    private boolean isClosed;

    private boolean m_IsStreamOwner = true;
    public InflaterInputStream() {
        super();
    }
}
