/*
 * 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.pdf;

public class PdfStream implements AutoCloseable {

    private com.pullenti.unisharp.Stream m_Stream = null;

    public PdfStream(String fileName, byte[] fileContent) throws java.io.FileNotFoundException, java.io.IOException {
        if (fileContent != null) 
            m_Stream = new com.pullenti.unisharp.MemoryStream(fileContent);
        else 
            m_Stream = new com.pullenti.unisharp.FileStream(fileName, "r", "");
    }

    @Override
    public void close() {
        try {
            if (m_Stream != null) 
                m_Stream.close();
            m_Stream = null;
        } catch (Exception ex123) {
        }
    }

    private boolean isSpace(byte ch) {
        if ((ch == ((byte)0x20) || ch == ((byte)0xD) || ch == ((byte)0xA)) || ch == ((byte)9)) 
            return true;
        return false;
    }

    private boolean isDelimiter(byte ch) {
        if ((((char)ch) == '(' || ((char)ch) == ')' || ((char)ch) == '<') || ((char)ch) == '>') 
            return true;
        if ((((char)ch) == '[' || ((char)ch) == ']' || ((char)ch) == '{') || ((char)ch) == '}') 
            return true;
        if (((char)ch) == '/') 
            return true;
        return false;
    }

    private int hexToInt(byte ch) {
        if (((char)ch) >= '0' && ((char)ch) <= '9') 
            return ((Byte.toUnsignedInt(ch)) - ((int)'0'));
        if (((char)ch) >= 'A' && ((char)ch) <= 'F') 
            return (((Byte.toUnsignedInt(ch)) - ((int)'A')) + 10);
        if (((char)ch) >= 'a' && ((char)ch) <= 'f') 
            return (((Byte.toUnsignedInt(ch)) - ((int)'a')) + 10);
        return -1;
    }

    private byte toHex(int val) {
        if (val < 10) 
            return (byte)((((int)'0') + val));
        return (byte)(((((int)'A') + val) - 10));
    }

    public int getPosition() throws java.io.IOException {
        return (int)m_Stream.getPosition();
    }

    public int setPosition(int value) throws java.io.IOException {
        m_Stream.setPosition((long)value);
        return value;
    }


    public int getLength() throws java.io.IOException {
        return (int)m_Stream.length();
    }


    public int readByte() throws java.io.IOException {
        return m_Stream.read();
    }

    public int read(byte[] arr, int off, int len) throws java.io.IOException {
        return m_Stream.read(arr, off, len);
    }

    public int peekSolidByte() throws java.io.IOException {
        boolean cmt = false;
        for (int i = m_Stream.read(); i >= 0; i = m_Stream.read()) {
            byte ch = (byte)i;
            if (((char)ch) == '%') 
                cmt = true;
            else if (ch == ((byte)0xD) || ch == ((byte)0xA)) 
                cmt = false;
            else if (ch != ((byte)0x20) && ch != ((byte)9) && !cmt) {
                m_Stream.setPosition(m_Stream.getPosition() - (1L));
                return i;
            }
        }
        return -1;
    }

    public byte[] readHead() throws Exception, java.io.IOException {
        byte[] head = new byte[4];
        int p0 = (int)m_Stream.getPosition();
        int i;
        m_Stream.read(head, 0, 4);
        if ((head.length != 4 || ((char)head[0]) != '%' || ((char)head[1]) != 'P') || ((char)head[2]) != 'D' || ((char)head[3]) != 'F') 
            throw new Exception("File not in PDF format");
        for (i = 4; i < (m_Stream.length() - (4L)); i++) {
            m_Stream.setPosition((long)i);
            m_Stream.read(head, 0, 4);
            if ((((((char)head[0]) == ' ' || head[0] == ((byte)0xA) || head[0] == ((byte)0xD))) && ((char)head[1]) == 'o' && ((char)head[2]) == 'b') && ((char)head[3]) == 'j') 
                break;
        }
        if (i >= (m_Stream.length() - (4L))) 
            throw new Exception("Bad PDF format");
        for (; i > 4; i--) {
            m_Stream.setPosition((long)i);
            byte b = (byte)m_Stream.read();
            if (!com.pullenti.unisharp.Utils.isWhitespace((char)b) && (((b < ((byte)0x30)) || b > ((byte)0x39)))) {
                i++;
                break;
            }
        }
        m_Stream.setPosition((long)p0);
        head = new byte[i];
        m_Stream.read(head, 0, head.length);
        return head;
    }

    public byte[] readLexemString() throws java.io.IOException {
        byte ch = (byte)m_Stream.read();
        int p0 = (int)m_Stream.getPosition();
        int i;
        java.util.ArrayList<Byte> val = new java.util.ArrayList<Byte>();
        if (((char)ch) == '<') {
            while ((((i = m_Stream.read()))) > 0) {
                ch = (byte)i;
                if (((char)ch) == '>') 
                    break;
                if (this.isSpace(ch)) 
                    continue;
                int i1 = this.hexToInt(ch);
                ch = (byte)m_Stream.read();
                int i2 = (((char)ch) == '>' ? 0 : this.hexToInt(ch));
                if ((i1 < 0) || (i2 < 0)) 
                    val.add((byte)0);
                else 
                    val.add((byte)(((i1 << 4) + i2)));
                if (((char)ch) == '>') 
                    break;
            }
            return com.pullenti.unisharp.Utils.toBytesArray(val.toArray(new Byte[val.size()]));
        }
        if (((char)ch) != '(') 
            return null;
        int lev = 0;
        int isUnicode = 0;
        while ((((i = m_Stream.read()))) >= 0) {
            ch = (byte)i;
            if ((val.size() < 2) && ((ch == ((byte)0xFE) || ch == ((byte)0xFF)))) 
                isUnicode++;
            if (isUnicode > 1) {
                if (((char)ch) == ')' && (((val.size() % 2)) == 0)) 
                    break;
                val.add(ch);
                continue;
            }
            val.add(ch);
            if (((char)ch) == '(') {
                lev++;
                continue;
            }
            if (((char)ch) == ')') {
                if ((--lev) < 0) {
                    val.remove(val.size() - 1);
                    break;
                }
                continue;
            }
            if (((char)ch) != '\\') 
                continue;
            val.remove(val.size() - 1);
            ch = (byte)m_Stream.read();
            if (((char)ch) >= '0' && ((char)ch) <= '7') {
                int res = ((Byte.toUnsignedInt(ch)) - ((int)'0'));
                for (int k = 0; k < 2; k++) {
                    ch = (byte)m_Stream.read();
                    if (((char)ch) >= '0' && ((char)ch) <= '7') 
                        res = (res * 8) + (((Byte.toUnsignedInt(ch)) - ((int)'0')));
                    else {
                        m_Stream.setPosition(m_Stream.getPosition() - (1L));
                        break;
                    }
                }
                val.add((byte)res);
                continue;
            }
            if (ch == ((byte)0xD) || ch == ((byte)0xA)) 
                continue;
            if (((char)ch) == 'r') 
                ch = (byte)0xD;
            else if (((char)ch) == 'n') 
                ch = (byte)0xA;
            else if (((char)ch) == 't') 
                ch = (byte)9;
            else if (((char)ch) == 'b') 
                ch = (byte)8;
            else if (((char)ch) == 'f') 
                ch = (byte)12;
            else if (((char)ch) == '\\' || ((char)ch) == '(' || ((char)ch) == ')') {
            }
            else {
            }
            val.add(ch);
        }
        return com.pullenti.unisharp.Utils.toBytesArray(val.toArray(new Byte[val.size()]));
    }

    public byte[] readName() throws java.io.IOException {
        int i = m_Stream.read();
        if (((char)i) != '/') 
            return null;
        java.util.ArrayList<Byte> res = new java.util.ArrayList<Byte>();
        while ((((i = m_Stream.read()))) >= 0) {
            byte ch = (byte)i;
            if (this.isSpace(ch)) 
                break;
            if (this.isDelimiter(ch)) {
                m_Stream.setPosition(m_Stream.getPosition() - (1L));
                break;
            }
            if (((char)ch) != '#') {
                res.add(ch);
                continue;
            }
            int i1 = this.hexToInt((byte)m_Stream.read());
            int i2 = this.hexToInt((byte)m_Stream.read());
            if ((i1 < 0) || (i2 < 0)) 
                res.add((byte)0);
            else 
                res.add((byte)(((i1 << 4) + i2)));
        }
        if (res.size() == 0) 
            return null;
        return com.pullenti.unisharp.Utils.toBytesArray(res.toArray(new Byte[res.size()]));
    }

    public String readWord(boolean notNull) throws java.io.IOException {
        int i;
        StringBuilder res = new StringBuilder();
        while ((((i = m_Stream.read()))) >= 0) {
            byte ch = (byte)i;
            if (this.isSpace(ch)) {
                if (res.length() > 0) 
                    break;
            }
            else if (this.isDelimiter(ch)) {
                if (res.length() == 0 && notNull) {
                    res.append((char)ch);
                    break;
                }
                m_Stream.setPosition(m_Stream.getPosition() - (1L));
                break;
            }
            else 
                res.append((char)ch);
        }
        if (res.length() == 0) 
            return null;
        return res.toString();
    }

    public boolean tryReadIdAndVersion(boolean mustBeRef, com.pullenti.unisharp.Outargwrapper<Integer> id, com.pullenti.unisharp.Outargwrapper<Short> vers) throws java.io.IOException {
        id.value = 0;
        vers.value = (short)0;
        int p0 = (int)m_Stream.getPosition();
        boolean inoutres239 = com.pullenti.unisharp.Utils.parseInteger(this.readWord(false), 0, null, id);
        if (!inoutres239) {
            m_Stream.setPosition((long)p0);
            return false;
        }
        boolean inoutres238 = com.pullenti.unisharp.Utils.parseShort(this.readWord(false), 0, null, vers);
        if (!inoutres238) {
            m_Stream.setPosition((long)p0);
            return false;
        }
        String str = this.readWord(false);
        if (mustBeRef) {
            if (com.pullenti.unisharp.Utils.stringsEq(str, "R")) 
                return true;
        }
        else if (com.pullenti.unisharp.Utils.stringsEq(str, "obj")) 
            return true;
        m_Stream.setPosition((long)p0);
        return false;
    }

    public PdfObject parseObject(PdfFile file, boolean text) throws java.io.IOException {
        PdfObject res = null;
        int i = this.peekSolidByte();
        if (i < 0) 
            return res;
        byte ch = (byte)i;
        int p0 = (int)m_Stream.getPosition();
        if (((char)ch) >= '0' && ((char)ch) <= '9' && !text) {
            int id;
            short ver;
            com.pullenti.unisharp.Outargwrapper<Integer> wrapid240 = new com.pullenti.unisharp.Outargwrapper<Integer>();
            com.pullenti.unisharp.Outargwrapper<Short> wrapver241 = new com.pullenti.unisharp.Outargwrapper<Short>();
            boolean inoutres242 = this.tryReadIdAndVersion(true, wrapid240, wrapver241);
            id = (wrapid240.value != null ? wrapid240.value : 0);
            ver = (wrapver241.value != null ? wrapver241.value : 0);
            if (inoutres242) {
                res = new PdfReference();
                res.sourceFile = file;
                res.id = id;
                res.version = ver;
                return res;
            }
        }
        if ((((((char)ch) >= '0' && ((char)ch) <= '9')) || ((char)ch) == '+' || ((char)ch) == '-') || ((char)ch) == '.') {
            String str = this.readWord(false);
            if (str == null) 
                return null;
            if (str.indexOf('.') < 0) {
                int v;
                com.pullenti.unisharp.Outargwrapper<Integer> wrapv243 = new com.pullenti.unisharp.Outargwrapper<Integer>();
                boolean inoutres244 = com.pullenti.unisharp.Utils.parseInteger(str, 0, null, wrapv243);
                v = (wrapv243.value != null ? wrapv243.value : 0);
                if (!inoutres244) 
                    return null;
                PdfIntValue ires = new PdfIntValue();
                ires.val = v;
                return ires;
            }
            else {
                PdfRealValue fres = new PdfRealValue();
                fres.val = str;
                return fres;
            }
        }
        if (((char)ch) == '/') {
            PdfName nres = new PdfName();
            nres.name = PdfStringValue.getStringByBytes(this.readName());
            if (nres.name == null) 
                return null;
            return nres;
        }
        else if (((char)ch) == '(') {
            PdfStringValue sres = new PdfStringValue();
            sres.val = this.readLexemString();
            if (sres.val == null) 
                return null;
            return sres;
        }
        else if (((char)ch) == '[') 
            res = new PdfArray();
        else if (((char)ch) == '<') {
            m_Stream.setPosition((long)(p0 + 1));
            ch = (byte)m_Stream.read();
            if (((char)ch) == '<') 
                res = PdfDictionary._new245(p0);
            else {
                PdfStringValue sres = PdfStringValue._new246(true);
                m_Stream.setPosition((long)p0);
                sres.val = this.readLexemString();
                if (sres.val == null) 
                    return null;
                return sres;
            }
        }
        else if (((((char)ch) == '\'' || ((char)ch) == '\"')) && text) {
            PdfName nres = new PdfName();
            nres.name = (((char)ch) == '\'' ? "\'" : "\"");
            m_Stream.setPosition(m_Stream.getPosition() + (1L));
            return nres;
        }
        else {
            String str = this.readWord(false);
            switch (str) { 
            case "null":
                return new PdfNull();
            case "true":
                PdfBoolValue bres1 = new PdfBoolValue();
                bres1.val = true;
                return bres1;
            case "false":
                PdfBoolValue bres2 = new PdfBoolValue();
                bres2.val = false;
                return bres2;
            case "endobj":
                return null;
        }
        if (text && str != null) {
            PdfName nres = new PdfName();
            nres.name = str;
            return nres;
        }
        return null;
        }
        res.sourceFile = file;
        if (res instanceof PdfDictionary) 
            ((PdfDictionary)com.pullenti.unisharp.Utils.cast(res, PdfDictionary.class)).postParse(this);
        else if (res instanceof PdfArray) 
            ((PdfArray)com.pullenti.unisharp.Utils.cast(res, PdfArray.class)).postParse(this);
        return res;
    }

    public java.util.ArrayList<PdfObject> parseContent() throws java.io.IOException {
        java.util.ArrayList<PdfObject> res = new java.util.ArrayList<PdfObject>();
        while (true) {
            int i = this.peekSolidByte();
            if (i < 0) 
                break;
            try {
                long pos = (long)this.getPosition();
                PdfObject obj = this.parseObject(null, true);
                if (obj != null) {
                    obj.readPos = pos;
                    obj.readLen = (int)((((long)this.getPosition()) - pos));
                    res.add(obj);
                }
                else 
                    this.readByte();
            } catch (Exception ex247) {
                break;
            }
        }
        return res;
    }
    public PdfStream() {
    }
}
