/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package avt.io;
import avt.io.charset.*;
import avt.io.extension.*;
public final class CharInputStream(Object, Closeable, CharReader, Extendable)
{
public static CharInputStream create(ByteReader reader, String charsetName) throws UnsupportedCharsetNameException {
CharDecoder decoder = Charset.get(charsetName).newDecoder();
return new CharInputStream(reader, decoder);
}
private CharDecoder fldDecoder;
private final ByteReader fldReader;
private final CharInputStreamMarkExtension fldMarkExtension;
private final CharInputStreamStreamedExtension fldStreamedExtension;
public (ByteReader reader): this(reader, Charset.getDefault().newDecoder()) { }
public (ByteReader reader, CharDecoder decoder) {
LimitedSizeExtension ext1 = null;
MarkExtension ext0 = null;
if(reader != null)
{
ext0 = (MarkExtension) reader.getExtension(MarkExtension.class);
ext1 = (LimitedSizeExtension) reader.getExtension(LimitedSizeExtension.class);
}
fldDecoder = decoder != null ? decoder : Charset.getDefault().newDecoder();
fldReader = reader;
fldMarkExtension = ext0 == null ? null : new CharInputStreamMarkExtension(ext0);
fldStreamedExtension = new CharInputStreamStreamedExtension(ext1);
}
public void close() throws IOException { fldReader.close(); }
public int read() throws IOException {
CharactersBuffer stream = readChars(1);
return stream.length < 1 ? -1 : stream[0];
}
public int read(char[] 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);
if(length <= 0) return 0;
CharactersBuffer stream = readChars(length);
int result = Int.min(stream.length, length);
if(result <= 0) return -1;
stream.getChars(0, result, dst, offset);
return result;
}
public long skip(long charsQuantity) throws IOException {
if(charsQuantity <= 0L) return 0L;
long result = 0L;
for(char[] buffer = new char[224]; charsQuantity > 0L; )
{
long skipped = (long) read(buffer, 0, (int) Long.min(charsQuantity, 224L));
if(skipped < 0L) break;
charsQuantity -= skipped;
result += skipped;
}
return result;
}
public Extension[] getExtensions() {
Extension ext1 = fldMarkExtension;
Extension ext0 = fldStreamedExtension;
return ext1 == null ? new Extension[] { ext0 } : new Extension[] { ext0, ext1 };
}
public Extension getExtension(Class type) {
Extension ext = fldStreamedExtension;
if(type == null || type.isAssignableFrom(ext.getClass())) return ext;
return (ext = fldMarkExtension) != null && (type == null || type.isAssignableFrom(ext.getClass())) ? ext : null;
}
public ByteReader reader { read = fldReader }
public CharDecoder decoder { read = fldDecoder, write = setDecoder }
private void setDecoder(CharDecoder newDecoder) { fldDecoder = newDecoder != null ? newDecoder : Charset.getDefault().newDecoder(); }
private CharactersBuffer readChars(int length) throws CharacterDecodingException, IOException {
ByteReader src = fldReader;
CharDecoder decoder = fldDecoder;
CharInputStreamStreamedExtension ext = fldStreamedExtension;
CharactersBuffer dst = ext.fldCharactersBuffer;
dst.discard(ext.fldCharactersReaded);
ext.fldCharactersReaded = Int.MAX_VALUE;
for(int readed = -1; readed != (readed = dst.length) && readed < length; )
{
int remained = length - readed;
decoder.decodeToWriter(dst, src, remained >= Int.MAX_VALUE - 6 ? Int.MAX_VALUE : remained + 6);
}
ext.fldCharactersReaded = length;
return dst;
}
}
class CharInputStreamMarkExtension(Object, Extension, MarkExtension)
{
private final MarkExtension fldMarkExtension;
(MarkExtension ext) { fldMarkExtension = ext; }
public void reset() throws IOException { fldMarkExtension.reset(); }
public void mark(int transferLimit) { fldMarkExtension.mark(transferLimit); }
}
class CharInputStreamStreamedExtension(Object, Extension, StreamedExtension)
{
int fldCharactersReaded;
final CharactersBuffer fldCharactersBuffer;
private final LimitedSizeExtension fldLimitedSizeExtension;
(LimitedSizeExtension ext) {
fldCharactersBuffer = new CharactersBuffer();
fldLimitedSizeExtension = ext;
}
public boolean ready() throws IOException {
LimitedSizeExtension ext;
return fldCharactersBuffer.length > fldCharactersReaded || (ext = fldLimitedSizeExtension) != null && ext.available() > 0L;
}
}