DataInputStream.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Реализация среды исполнения языка программирования
    Объектно-ориентированный продвинутый векторный транслятор

    Copyright © 2021, 2024 Малик Разработчик

    Это свободная программа: вы можете перераспространять ее и/или изменять
    ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она будет полезной,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <https://www.gnu.org/licenses/>.
*/

package avt.io;

import avt.io.charset.*;

public final class DataInputStream(Object, Closeable, ByteReader, Extendable)
{
    public static DataInputStream create(ByteReader reader, String charsetName) throws UnsupportedCharsetNameException {
        Charset charset = Charset.get(charsetName);
        return new DataInputStream(reader, charset);
    }

    private Charset fldCharset;
    private final ByteReader fldReader;
    private final BigEndianDataInput fldBigEndianDataInput;
    private final LittleEndianDataInput fldLittleEndianDataInput;

    public (ByteReader reader): this(reader, Charset.getDefault()) {  }

    public (ByteReader reader, Charset charset) {
        if(charset == null) charset = Charset.getDefault();
        byte[] data = new byte[0x40];
        fldCharset = charset;
        fldReader = reader;
        fldBigEndianDataInput = new BigEndianDataInput(reader, data) { fldCharset = charset };
        fldLittleEndianDataInput = new LittleEndianDataInput(reader, data) { fldCharset = charset };
    }

    public void close() throws IOException { fldReader.close(); }

    public int read() throws IOException { return fldReader.read(); }

    public int read(byte[] dst) throws IOException { return fldReader.read(dst); }

    public int read(byte[] dst, int offset, int length) throws IOException { return fldReader.read(dst, offset, length); }

    public long skip(long bytesQuantity) throws IOException { return fldReader.skip(bytesQuantity); }

    public Extension[] getExtensions() { return fldReader.getExtensions(); }

    public Extension getExtension(Class type) { return fldReader.getExtension(type); }

    public ByteReader reader { read = fldReader }

    public Charset charset { read = fldCharset, write = setCharset }

    public DataInput bigEndianDataInput { read = fldBigEndianDataInput }

    public DataInput littleEndianDataInput { read = fldLittleEndianDataInput }

    private void setCharset(Charset newCharset) {
        if(newCharset == null) newCharset = Charset.getDefault();
        fldCharset = fldLittleEndianDataInput.fldCharset = fldBigEndianDataInput.fldCharset = newCharset;
    }
}

class LittleEndianDataInput(Object, DataInput)
{
    protected final byte[] fldData;
    protected final ByteReader fldReader;
    Charset fldCharset;

    public (ByteReader reader, byte[] data) {
        fldData = data;
        fldReader = reader;
    }

    public void readFully(byte[] dst) throws IOException { readFully(dst, 0, dst == null ? 0 : dst.length); }

    public void readFully(byte[] dst, int offset, int length) throws IOException {
        if(dst == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "dst" }));
        }
        Array.checkBounds(dst, offset, length);
        for(ByteReader reader = fldReader, int readed; length > 0; offset += readed, length -= readed) if((readed = reader.read(dst, offset, length)) <= 0)
        {
            throw new EndOfStreamException(package.getResourceString("end-of-stream"));
        }
    }

    public boolean readBoolean() throws IOException {
        int data = fldReader.read();
        if(data < 0)
        {
            throw new EndOfStreamException(package.getResourceString("end-of-stream"));
        }
        return (data & 0xff) != 0;
    }

    public native char readChar() throws IOException;

    public int readUnsignedByte() throws IOException {
        int data = fldReader.read();
        if(data < 0)
        {
            throw new EndOfStreamException(package.getResourceString("end-of-stream"));
        }
        return data & 0xff;
    }

    public native int readUnsignedShort() throws IOException;

    public int readByte() throws IOException {
        int data = fldReader.read();
        if(data < 0)
        {
            throw new EndOfStreamException(package.getResourceString("end-of-stream"));
        }
        return (byte) data;
    }

    public native int readShort() throws IOException;

    public native int readInt() throws IOException;

    public native int2 readUnsignedByte2() throws IOException;

    public native int2 readUnsignedShort2() throws IOException;

    public native int2 readByte2() throws IOException;

    public native int2 readShort2() throws IOException;

    public native int2 readInt2() throws IOException;

    public native int4 readUnsignedByte4() throws IOException;

    public native int4 readUnsignedShort4() throws IOException;

    public native int4 readByte4() throws IOException;

    public native int4 readShort4() throws IOException;

    public native int4 readInt4() throws IOException;

    public native int8 readUnsignedByte8() throws IOException;

    public native int8 readUnsignedShort8() throws IOException;

    public native int8 readByte8() throws IOException;

    public native int8 readShort8() throws IOException;

    public native int8 readInt8() throws IOException;

    public native long readLong() throws IOException;

    public native long2 readLong2() throws IOException;

    public native long4 readLong4() throws IOException;

    public native long8 readLong8() throws IOException;

    public native float readFloat() throws IOException;

    public native float2 readFloat2() throws IOException;

    public native float4 readFloat4() throws IOException;

    public native float8 readFloat8() throws IOException;

    public native double readDouble() throws IOException;

    public native double2 readDouble2() throws IOException;

    public native double4 readDouble4() throws IOException;

    public native double8 readDouble8() throws IOException;

    public native real readReal() throws IOException;

    public String readUTF() throws IOException {
        int utfLength = readUnsignedShort();
        if(utfLength <= 0) return "";
        byte[] utfData = new byte[utfLength];
        readFully(utfData, 0, utfLength);
        int resultLength = 0;
        char[] resultData = new char[utfLength];
        for(int index = 0; index < utfLength; )
        {
            int b1 = utfData[index] & 0xff;
            switch(b1 >> 4)
            {
            case 0x00:
            case 0x01:
            case 0x02:
            case 0x03:
            case 0x04:
            case 0x05:
            case 0x06:
            case 0x07:
                index++;
                resultData[resultLength++] = (char) b1;
                break;
            case 0x0c:
            case 0x0d:
                int b2;
                if((index += 2) > utfLength || ((b2 = utfData[index - 1]) & 0xc0) != 0x80)
                {
                    throw new UTFDataFormatException(package.getResourceString("invalid-data-format.utf"));
                }
                resultData[resultLength++] = (char) ((b1 & 0x1f) << 6 | (b2 & 0x3f));
                break;
            case 0x0e:
                int b2;
                int b3;
                if((index += 3) > utfLength || ((b2 = utfData[index - 2]) & 0xc0) != 0x80 || ((b3 = utfData[index - 1]) & 0xc0) != 0x80)
                {
                    throw new UTFDataFormatException(package.getResourceString("invalid-data-format.utf"));
                }
                resultData[resultLength++] = (char) ((b1 & 0x0f) << 12 | (b2 & 0x3f) << 6 | (b3 & 0x3f));
                break;
            default:
                throw new UTFDataFormatException(package.getResourceString("invalid-data-format.utf"));
            }
        }
        return new String(resultData, 0, resultLength);
    }

    public String readln() throws IOException {
        int length = 0;
        byte[] data = new byte[0x7f];
        Charset charset = fldCharset;
        for(byte[] ending = Platform.instance.lineSeparator.toByteArray(charset), int estart = ending[0] & 0xff, int elength = ending.length, ByteReader reader = fldReader; length < Int.MAX_VALUE; )
        {
            int b0 = reader.read();
            if(b0 == estart)
            {
                for(int index = 1; index < elength; index++) if(reader.read() != (ending[index] & 0xff))
                {
                    throw new MalformedLineSeparatorException(package.getResourceString("invalid-data-format.malformed-line-separator"));
                }
                break;
            }
            if(b0 < 0) break;
            if(length == data.length) Array.copy(data, 0, data = new byte[length << 1 | 1], 0, length);
            data[length++] = (byte) b0;
        }
        return new String(data, 0, length, charset);
    }

    public String read() throws IOException {
        int length = 0;
        byte[] data = new byte[0x7f];
        Charset charset = fldCharset;
        byte[] ending = Platform.instance.lineSeparator.toByteArray(charset);
        int estart = ending[0] & 0xff;
        int elength = ending.length;
        ByteReader reader = fldReader;
        do
        {
            int b0 = reader.read();
            if(b0 < 0) return "";
            if(b0 > 0x20)
            {
                data[0] = (byte) b0;
                length = 1;
                break;
            }
        } while(true);
        while(length < Int.MAX_VALUE)
        {
            int b0 = reader.read();
            if(b0 == estart)
            {
                for(int index = 1; index < elength; index++) if(reader.read() != (ending[index] & 0xff))
                {
                    throw new MalformedLineSeparatorException(package.getResourceString("invalid-data-format.malformed-line-separator"));
                }
                break;
            }
            if(b0 <= 0x20) break;
            if(length == data.length) Array.copy(data, 0, data = new byte[length << 1 | 1], 0, length);
            data[length++] = (byte) b0;
        }
        return new String(data, 0, length, charset);
    }

    protected void readData(int length) throws IOException {
        byte[] dst = fldData;
        int offset = 0;
        for(ByteReader reader = fldReader, int readed; length > 0; offset += readed, length -= readed) if((readed = reader.read(dst, offset, length)) <= 0)
        {
            throw new EndOfStreamException(package.getResourceString("end-of-stream"));
        }
    }
}

class BigEndianDataInput(LittleEndianDataInput)
{
    public (ByteReader reader, byte[] data): super(reader, data) {  }

    protected native void readData(int length) throws IOException;
}