/*
 * 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 class assists with writing/reading from Zip files.
public class ZipHelperStream extends com.pullenti.unisharp.Stream {

    public ZipHelperStream(String name, com.pullenti.unisharp.Stream stream) throws java.io.FileNotFoundException, java.io.IOException {
        super();
        if (stream == null) {
            stream_ = new com.pullenti.unisharp.FileStream(name, "rw", "");
            isOwner_ = true;
        }
        else 
            stream_ = stream;
    }

    public boolean isStreamOwner() {
        return isOwner_;
    }

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


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


    @Override
    public boolean canSeek() {
        return stream_.canSeek();
    }


    @Override
    public long length() throws java.io.IOException {
        return stream_.length();
    }


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

    @Override
    public long setPosition(long value) throws java.io.IOException {
        stream_.setPosition(value);
        return value;
    }


    @Override
    public boolean canWrite() {
        return stream_.canWrite();
    }


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

    @Override
    public long seek(long offset, int origin) throws java.io.IOException {
        return stream_.seek(offset, origin);
    }

    @Override
    public void setLength(long value) throws java.io.IOException {
        stream_.setLength(value);
    }

    @Override
    public int read(byte[] buffer, int offset, int count) throws java.io.IOException {
        return stream_.read(buffer, offset, count);
    }

    @Override
    public void write(byte[] buffer, int offset, int count) throws java.io.IOException {
        stream_.write(buffer, offset, count);
    }

    @Override
    public void close() throws java.io.IOException {
        com.pullenti.unisharp.Stream toClose = stream_;
        stream_ = null;
        if (isOwner_ && (toClose != null)) {
            isOwner_ = false;
            toClose.close();
        }
    }

    private void writeLocalHeader(ZipEntry entry, EntryPatchData patchData) throws Exception, java.io.IOException, IndexOutOfBoundsException {
        CompressionMethod method = entry.get_CompressionMethod();
        boolean headerInfoAvailable = true;
        boolean patchEntryHeader = false;
        this.writeLEInt(ZipConstants.LOCALHEADERSIGNATURE);
        this.writeLEShort(entry.getVersion());
        this.writeLEShort(entry.flags);
        this.writeLEShort(Byte.toUnsignedInt((byte)method.value()));
        this.writeLEInt((int)entry.getDosTime());
        if (headerInfoAvailable == true) {
            this.writeLEInt((int)entry.getCrc());
            if (entry.getLocalHeaderRequiresZip64()) {
                this.writeLEInt(-1);
                this.writeLEInt(-1);
            }
            else {
                this.writeLEInt((entry.isCrypted() ? (entry.getCompressedSize()) + ZipConstants.CRYPTOHEADERSIZE : entry.getCompressedSize()));
                this.writeLEInt(entry.getSize());
            }
        }
        else {
            if (patchData != null) 
                patchData.setCrcPatchOffset((int)stream_.getPosition());
            this.writeLEInt(0);
            if (patchData != null) 
                patchData.setSizePatchOffset((int)stream_.getPosition());
            if (entry.getLocalHeaderRequiresZip64() && patchEntryHeader) {
                this.writeLEInt(-1);
                this.writeLEInt(-1);
            }
            else {
                this.writeLEInt(0);
                this.writeLEInt(0);
            }
        }
        byte[] name = ZipConstants.convertToArray(entry.flags, entry.getName());
        if (name.length > 0xFFFF) 
            throw new Exception("Entry name too long.");
        ZipExtraData ed = new ZipExtraData(entry.getExtraData());
        if (entry.getLocalHeaderRequiresZip64() && ((headerInfoAvailable || patchEntryHeader))) {
            ed.startNewEntry();
            if (headerInfoAvailable) {
                ed.addLeLong(entry.getSize(), 0);
                ed.addLeLong(entry.getCompressedSize(), 0);
            }
            else {
                ed.addLeLong(-1, -1);
                ed.addLeLong(-1, -1);
            }
            ed.addNewEntry(1);
            if (!ed.find(1)) 
                throw new Exception("Internal error cant find extra data");
            if (patchData != null) 
                patchData.setSizePatchOffset(ed.getCurrentReadIndex());
        }
        else 
            ed.delete(1);
        byte[] extra = ed.getEntryData();
        this.writeLEShort(name.length);
        this.writeLEShort(extra.length);
        if (name.length > 0) 
            stream_.write(name, 0, name.length);
        if (entry.getLocalHeaderRequiresZip64() && patchEntryHeader) 
            patchData.setSizePatchOffset(patchData.getSizePatchOffset() + ((int)stream_.getPosition()));
        if (extra.length > 0) 
            stream_.write(extra, 0, extra.length);
    }

    public int locateBlockWithSignature(int signature, int endLocation, int minimumBlockSize, int maximumVariableData) throws java.io.EOFException, java.io.IOException {
        int pos = endLocation - minimumBlockSize;
        if (pos < 0) 
            return -1;
        int giveUpMarker = Math.max(pos - maximumVariableData, 0);
        do{
            if (pos < giveUpMarker) 
                return -1;
            this.seek((long)(pos--), 0);
        } while (this.readLEInt() != signature); 
        return (int)getPosition();
    }

    public void writeZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset) throws java.io.IOException {
        long centralSignatureOffset = stream_.getPosition();
        this.writeLEInt(ZipConstants.ZIP64CENTRALFILEHEADERSIGNATURE);
        this.writeLELong(44L);
        this.writeLEShort(ZipConstants.VERSIONMADEBY);
        this.writeLEShort(ZipConstants.VERSIONZIP64);
        this.writeLEInt(0);
        this.writeLEInt(0);
        this.writeLELong(noOfEntries);
        this.writeLELong(noOfEntries);
        this.writeLELong(sizeEntries);
        this.writeLELong(centralDirOffset);
        this.writeLEInt(ZipConstants.ZIP64CENTRALDIRLOCATORSIGNATURE);
        this.writeLEInt(0);
        this.writeLELong(centralSignatureOffset);
        this.writeLEInt(1);
    }

    public void writeEndOfCentralDirectory(int noOfEntries, int sizeEntries, int startOfCentralDirectory, byte[] comment) throws Exception, java.io.IOException {
        this.writeLEInt(ZipConstants.ENDOFCENTRALDIRECTORYSIGNATURE);
        this.writeLEShort(0);
        this.writeLEShort(0);
        if (noOfEntries >= 0xffff) {
            this.writeLEUshort((short)0xffff);
            this.writeLEUshort((short)0xffff);
        }
        else {
            this.writeLEShort((int)((short)noOfEntries));
            this.writeLEShort((int)((short)noOfEntries));
        }
        this.writeLEInt(sizeEntries);
        this.writeLEInt(startOfCentralDirectory);
        int commentLength = (comment != null ? comment.length : 0);
        if (commentLength > 0xffff) 
            throw new Exception(("Comment length(" + commentLength + ") is too long can only be 64K"));
        this.writeLEShort(commentLength);
        if (commentLength > 0) 
            this.write(comment, 0, comment.length);
    }

    public int readLEShort() throws java.io.EOFException, java.io.IOException {
        int byteValue1 = stream_.read();
        if (byteValue1 < 0) 
            throw new java.io.EOFException();
        int byteValue2 = stream_.read();
        if (byteValue2 < 0) 
            throw new java.io.EOFException();
        return byteValue1 | (byteValue2 << 8);
    }

    public int readLEInt() throws java.io.EOFException, java.io.IOException {
        return this.readLEShort() | (this.readLEShort() << 16);
    }

    public void writeLEShort(int value) throws java.io.IOException {
        stream_.write((byte)((value & 0xff)));
        stream_.write((byte)((((value >> 8)) & 0xff)));
    }

    public void writeLEUshort(short value) throws java.io.IOException {
        stream_.write((byte)(((Short.toUnsignedInt(value)) & 0xff)));
        stream_.write((byte)(((Short.toUnsignedInt(value)) >>> 8)));
    }

    public void writeLEInt(int value) throws java.io.IOException {
        this.writeLEShort(value);
        this.writeLEShort(value >> 16);
    }

    public void writeLEUint(int value) throws java.io.IOException {
        this.writeLEUshort((short)((((int)value) & 0xffff)));
        this.writeLEUshort((short)((((int)value) >>> 16)));
    }

    public void writeLELong(long value) throws java.io.IOException {
        this.writeLEInt((int)value);
        this.writeLEInt((int)((value >> 32)));
    }

    public void writeLEUlong(long value) throws java.io.IOException {
        this.writeLEUint((int)((((long)value) & (0xffffffffL))));
        this.writeLEUint((int)((((long)value) >>> 32)));
    }

    public int writeDataDescriptor(ZipEntry entry) throws IllegalArgumentException, java.io.IOException {
        if (entry == null) 
            throw new IllegalArgumentException("entry");
        int result = 0;
        if (((entry.flags & (GeneralBitFlags.DESCRIPTOR.value()))) != 0) {
            this.writeLEInt(ZipConstants.DATADESCRIPTORSIGNATURE);
            this.writeLEInt((int)entry.getCrc());
            result += 8;
            if (entry.getLocalHeaderRequiresZip64()) {
                this.writeLELong((long)entry.getCompressedSize());
                this.writeLELong((long)entry.getSize());
                result += 16;
            }
            else {
                this.writeLEInt(entry.getCompressedSize());
                this.writeLEInt(entry.getSize());
                result += 8;
            }
        }
        return result;
    }

    public void readDataDescriptor(boolean zip64, DescriptorData data) throws Exception, java.io.EOFException, java.io.IOException {
        int intValue = this.readLEInt();
        if (intValue != ZipConstants.DATADESCRIPTORSIGNATURE) 
            throw new Exception("Data descriptor signature not found");
        data.setCrc((int)this.readLEInt());
        if (zip64) {
            data.setCompressedSize(this.readLEInt());
            this.readLEInt();
            data.setSize(this.readLEInt());
            this.readLEInt();
        }
        else {
            data.setCompressedSize(this.readLEInt());
            data.setSize(this.readLEInt());
        }
    }

    private boolean isOwner_;

    private com.pullenti.unisharp.Stream stream_;
    public ZipHelperStream() {
        super();
    }
}
