/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
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;
}