CharInputStream.avt

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

/*
    Исходный код среды исполнения ПВТ-ОО.

    Этот исходный код является частью проекта ПВТ-ОО.

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

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

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

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <http://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) {
        MarkExtension ext0 = null;
        LimitedSizeExtension ext1 = 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 {
        CharDestination stream = readChars(1);
        return stream.position < 1 ? -1 : stream[0];
    }

    public int read(char[] dst, int offset, int length) throws IOException {
        if(dst == null)
        {
            throw new NullPointerException("аргумент dst равен нулевой ссылке");
        }
        Array.checkBounds(dst, offset, length);
        if(length <= 0) return 0;
        CharDestination stream = readChars(length);
        int result = Int.min(stream.position, 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[] buf = new char[224]; charsQuantity > 0L; )
        {
            int skipped = read(buf, 0, (int) Long.min(charsQuantity, 224L));
            if(skipped < 0) 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 CharDestination readChars(int length) throws CharacterDecodingException, IOException {
        ByteReader src = fldReader;
        CharDecoder decoder = fldDecoder;
        CharInputStreamStreamedExtension ext = fldStreamedExtension;
        CharDestination dst = ext.fldDestination;
        dst.discard(ext.fldReadedChars);
        ext.fldReadedChars = Int.MAX_VALUE;
        for(int readed = -1; readed != (readed = dst.position) && readed < length; )
        {
            int remaining = length - readed;
            decoder.decodeToWriter(dst, src, remaining >= Int.MAX_VALUE - 6 ? Int.MAX_VALUE : remaining + 6);
        }
        ext.fldReadedChars = length;
        return dst;
    }

    private void setDecoder(CharDecoder newDecoder) { fldDecoder = newDecoder != null ? newDecoder : Charset.getDefault().newDecoder(); }
}

final class CharInputStreamStreamedExtension(Object, Extension, StreamedExtension)
{
    int fldReadedChars;
    final CharDestination fldDestination;
    private final LimitedSizeExtension fldLimitedSizeExtension;

    public (LimitedSizeExtension ext) {
        fldDestination = new CharDestination();
        fldLimitedSizeExtension = ext;
    }

    public boolean ready() throws IOException {
        LimitedSizeExtension ext;
        return fldDestination.position > fldReadedChars || (ext = fldLimitedSizeExtension) != null && ext.available() > 0L;
    }
}

final class CharInputStreamMarkExtension(Object, Extension, MarkExtension)
{
    private final MarkExtension fldMarkExtension;

    public (MarkExtension ext) { fldMarkExtension = ext; }

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

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