/*
    Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
    и других спецификаций для функционирования компактных приложений на языке
    Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

    Copyright © 2016–2017, 2019–2022 Малик Разработчик

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

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

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

package java.io;

public class DataInputStream extends InputStream implements DataInput
{
    public static String readUTF(DataInput stream) throws IOException {
        int length;
        int strlen;
        char[] result;
        byte[] b;
        if(stream == null || (length = stream.readUnsignedShort()) == 0) return "";
        strlen = 0;
        result = new char[length];
        stream.readFully(b = new byte[length]);
        for(int i = 0; i < length; )
        {
            int byte1;
            int byte2;
            int byte3;
            switch((byte1 = b[i] & 0xff) >> 4)
            {
            default:
                throw new UTFDataFormatException("DataInputStream.readUTF: ошибка в данных, закодированных кодировкой UTF-8.");
            case 0x00:
            case 0x01:
            case 0x02:
            case 0x03:
            case 0x04:
            case 0x05:
            case 0x06:
            case 0x07:
                i++;
                result[strlen++] = (char) byte1;
                break;
            case 0x0c:
            case 0x0d:
                if((i += 2) > length || ((byte2 = b[i - 1]) & 0xc0) != 0x80)
                {
                    throw new UTFDataFormatException("DataInputStream.readUTF: ошибка в данных, закодированных кодировкой UTF-8.");
                }
                result[strlen++] = (char) ((byte1 & 0x1f) << 6 | (byte2 & 0x3f));
                break;
            case 0x0e:
                if((i += 3) > length || ((byte2 = b[i - 2]) & 0xc0) != 0x80 || ((byte3 = b[i - 1]) & 0xc0) != 0x80)
                {
                    throw new UTFDataFormatException("DataInputStream.readUTF: ошибка в данных, закодированных кодировкой UTF-8.");
                }
                result[strlen++] = (char) ((byte1 & 0x0f) << 12 | (byte2 & 0x3f) << 6 | (byte3 & 0x3f));
                break;
            }
        }
        return new String(result, 0, strlen);
    }

    protected InputStream in;

    public DataInputStream(InputStream stream) {
        this.in = stream;
    }

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

    public void reset() throws IOException {
        in.reset();
    }

    public void mark(int readLimit) {
        in.mark(readLimit);
    }

    public boolean markSupported() {
        return in.markSupported();
    }

    public int available() throws IOException {
        return in.available();
    }

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

    public long skip(long quantity) throws IOException {
        return in.skip(quantity);
    }

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

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

    public final void readFully(byte[] dst) throws IOException {
        InputStream stream;
        if(dst == null)
        {
            throw new NullPointerException("DataInputStream.readFully: аргумент dst равен нулевой ссылке.");
        }
        stream = in;
        for(int offset = 0, length = dst.length, readed; length > 0; offset += readed, length -= readed) if((readed = stream.read(dst, offset, length)) <= 0)
        {
            throw new EOFException("DataInputStream.readFully: достигнут конец потока данных.");
        }
    }

    public final void readFully(byte[] dst, int offset, int length) throws IOException {
        InputStream stream;
        if(dst == null)
        {
            throw new NullPointerException("DataInputStream.readFully: аргумент dst равен нулевой ссылке.");
        }
        Array.checkBound("DataInputStream.readFully", dst.length, offset, length);
        stream = in;
        for(int readed; length > 0; offset += readed, length -= readed) if((readed = stream.read(dst, offset, length)) <= 0)
        {
            throw new EOFException("DataInputStream.readFully: достигнут конец потока данных.");
        }
    }

    public final boolean readBoolean() throws IOException {
        int byte0;
        if((byte0 = in.read()) < 0)
        {
            throw new EOFException("DataInputStream.readBoolean: достигнут конец потока данных.");
        }
        return (byte0 & 0xff) > 0;
    }

    public final char readChar() throws IOException {
        int byte0;
        int byte1;
        InputStream stream = in;
        byte1 = stream.read();
        byte0 = stream.read();
        if((byte0 | byte1) < 0)
        {
            throw new EOFException("DataInputStream.readChar: достигнут конец потока данных.");
        }
        return (char) (byte1 << 8 | byte0 & 0xff);
    }

    public final float readFloat() throws IOException {
        int byte0;
        int byte1;
        int byte2;
        int byte3;
        InputStream stream = in;
        byte3 = stream.read();
        byte2 = stream.read();
        byte1 = stream.read();
        byte0 = stream.read();
        if((byte0 | byte1 | byte2 | byte3) < 0)
        {
            throw new EOFException("DataInputStream.readFloat: достигнут конец потока данных.");
        }
        return Float.intBitsToFloat((byte3 & 0xff) << 0x18 | (byte2 & 0xff) << 0x10 | (byte1 & 0xff) << 0x08 | (byte0 & 0xff));
    }

    public final double readDouble() throws IOException {
        int byte0;
        int byte1;
        int byte2;
        int byte3;
        int byte4;
        int byte5;
        int byte6;
        int byte7;
        InputStream stream = in;
        byte7 = stream.read();
        byte6 = stream.read();
        byte5 = stream.read();
        byte4 = stream.read();
        byte3 = stream.read();
        byte2 = stream.read();
        byte1 = stream.read();
        byte0 = stream.read();
        if((byte0 | byte1 | byte2 | byte3 | byte4 | byte5 | byte6 | byte7) < 0)
        {
            throw new EOFException("DataInputStream.readDouble: достигнут конец потока данных.");
        }
        return Double.longBitsToDouble(
            (long) (byte7 & 0xff) << 0x38 | (long) (byte6 & 0xff) << 0x30 | (long) (byte5 & 0xff) << 0x28 | (long) (byte4 & 0xff) << 0x20 |
            (long) (byte3 & 0xff) << 0x18 | (long) (byte2 & 0xff) << 0x10 | (long) (byte1 & 0xff) << 0x08 | (long) (byte0 & 0xff)
        );
    }

    public final byte readByte() throws IOException {
        int byte0;
        if((byte0 = in.read()) < 0)
        {
            throw new EOFException("DataInputStream.readByte: достигнут конец потока данных.");
        }
        return (byte) byte0;
    }

    public final short readShort() throws IOException {
        int byte0;
        int byte1;
        InputStream stream = in;
        byte1 = stream.read();
        byte0 = stream.read();
        if((byte0 | byte1) < 0)
        {
            throw new EOFException("DataInputStream.readShort: достигнут конец потока данных.");
        }
        return (short) (byte1 << 8 | byte0 & 0xff);
    }

    public final int skipBytes(int quantity) throws IOException {
        int skiped;
        int result;
        InputStream stream = in;
        for(result = 0; quantity > 0 && (skiped = (int) stream.skip((long) quantity)) > 0; quantity -= skiped, result += skiped);
        return result;
    }

    public final int readUnsignedByte() throws IOException {
        int byte0;
        if((byte0 = in.read()) < 0)
        {
            throw new EOFException("DataInputStream.readUnsignedByte: достигнут конец потока данных.");
        }
        return byte0 & 0xff;
    }

    public final int readUnsignedShort() throws IOException {
        int byte0;
        int byte1;
        InputStream stream = in;
        byte1 = stream.read();
        byte0 = stream.read();
        if((byte0 | byte1) < 0)
        {
            throw new EOFException("DataInputStream.readUnsignedShort: достигнут конец потока данных.");
        }
        return (byte1 & 0xff) << 8 | (byte0 & 0xff);
    }

    public final int readInt() throws IOException {
        int byte0;
        int byte1;
        int byte2;
        int byte3;
        InputStream stream = in;
        byte3 = stream.read();
        byte2 = stream.read();
        byte1 = stream.read();
        byte0 = stream.read();
        if((byte0 | byte1 | byte2 | byte3) < 0)
        {
            throw new EOFException("DataInputStream.readInt: достигнут конец потока данных.");
        }
        return (byte3 & 0xff) << 0x18 | (byte2 & 0xff) << 0x10 | (byte1 & 0xff) << 0x08 | (byte0 & 0xff);
    }

    public final long readLong() throws IOException {
        int byte0;
        int byte1;
        int byte2;
        int byte3;
        int byte4;
        int byte5;
        int byte6;
        int byte7;
        InputStream stream = in;
        byte7 = stream.read();
        byte6 = stream.read();
        byte5 = stream.read();
        byte4 = stream.read();
        byte3 = stream.read();
        byte2 = stream.read();
        byte1 = stream.read();
        byte0 = stream.read();
        if((byte0 | byte1 | byte2 | byte3 | byte4 | byte5 | byte6 | byte7) < 0)
        {
            throw new EOFException("DataInputStream.readLong: достигнут конец потока данных.");
        }
        return
            (long) (byte7 & 0xff) << 0x38 | (long) (byte6 & 0xff) << 0x30 | (long) (byte5 & 0xff) << 0x28 | (long) (byte4 & 0xff) << 0x20 |
            (long) (byte3 & 0xff) << 0x18 | (long) (byte2 & 0xff) << 0x10 | (long) (byte1 & 0xff) << 0x08 | (long) (byte0 & 0xff)
        ;
    }

    public final String readUTF() throws IOException {
        return readUTF(this);
    }
}
