pascalx.io.pas

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

{
    pascalx.io — модуль базового ввода-вывода.

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

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

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

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

unit pascalx.io;

{$MODE DELPHI}

interface

uses
    pascalx.lang;

{$ASMMODE INTEL,CALLING REGISTER,TYPEINFO ON}

{%region public }
type
    Closeable = interface;
    Input = interface;
    DataInput = interface;
    Output = interface;
    DataOutput = interface;
    InputStream = class;
    OutputStream = class;
    IOStream = class;
    DataInputStream = class;
    DataOutputStream = class;
    ByteArrayInputStream = class;
    ByteArrayOutputStream = class;
    ByteArrayIOStream = class;
    IOException = class;
    EOFException = class;
    UTFDataFormatException = class;

    Closeable = interface(_Interface) ['{74C86B60-AC5B-4E8D-8ACD-29A50B5C1500}']
        procedure close();
    end;

    Input = interface(Closeable) ['{74C86B60-AC5B-4E8D-8ACD-29A50B5C1501}']
        function seekSupported(): boolean;
        function seek(delta: long): long;
        function reset(position: long = 0): long;
        function position(): long;
        function available(): long;
        function size(): long;
        function read(): int; overload;
        function read(const dst: byte_Array1d): int; overload;
        function read(const dst: byte_Array1d; offset, length: int): int; overload;
    end;

    DataInput = interface(Input) ['{74C86B60-AC5B-4E8D-8ACD-29A50B5C1502}']
        function skipBytes(count: int): int;
        function readBoolean(): boolean;
        function readChar(): char;
        function readWChar(): wchar;
        function readByte(): int;
        function readShort(): int;
        function readInt(): int;
        function readLong(): long;
        function readFloat(): float;
        function readDouble(): double;
        function readReal(): real;
        function readUnsignedByte(): int;
        function readUnsignedShort(): int;
        function readWCharLE(): wchar;
        function readShortLE(): int;
        function readIntLE(): int;
        function readLongLE(): long;
        function readFloatLE(): float;
        function readDoubleLE(): double;
        function readRealLE(): real;
        function readUnsignedShortLE(): int;
        function readUTF(): UnicodeString;
        procedure readFully(const dst: byte_Array1d); overload;
        procedure readFully(const dst: byte_Array1d; offset, length: int); overload;
    end;

    Output = interface(Closeable) ['{74C86B60-AC5B-4E8D-8ACD-29A50B5C1503}']
        procedure flush();
        procedure write(data: int); overload;
        procedure write(const src: byte_Array1d); overload;
        procedure write(const src: byte_Array1d; offset, length: int); overload;
    end;

    DataOutput = interface(Output) ['{74C86B60-AC5B-4E8D-8ACD-29A50B5C1504}']
        procedure writeBoolean(data: boolean);
        procedure writeChar(data: char);
        procedure writeWChar(data: wchar);
        procedure writeByte(data: int);
        procedure writeShort(data: int);
        procedure writeInt(data: int);
        procedure writeLong(data: long);
        procedure writeFloat(data: float);
        procedure writeDouble(data: double);
        procedure writeReal(const data: real);
        procedure writeWCharLE(data: wchar);
        procedure writeShortLE(data: int);
        procedure writeIntLE(data: int);
        procedure writeLongLE(data: long);
        procedure writeFloatLE(data: float);
        procedure writeDoubleLE(data: double);
        procedure writeRealLE(const data: real);
        procedure writeUTF(const data: UnicodeString);
        procedure writeAnsiChars(const data: AnsiString);
        procedure writeUnicodeChars(const data: UnicodeString);
        procedure writeUnicodeCharsLE(const data: UnicodeString);
    end;

    InputStream = class(RefCountInterfacedObject, Closeable, Input)
    public
        function seekSupported(): boolean; virtual;
        function seek(delta: long): long; virtual;
        function reset(position: long = 0): long; virtual;
        function position(): long; virtual;
        function available(): long; virtual;
        function size(): long; virtual;
        function read(): int; virtual; abstract; overload;
        function read(const dst: byte_Array1d): int; virtual; overload;
        function read(const dst: byte_Array1d; offset, length: int): int; virtual; overload;
        procedure close(); virtual;
    end;

    OutputStream = class(RefCountInterfacedObject, Closeable, Output)
    public
        procedure flush(); virtual;
        procedure write(data: int); virtual; abstract; overload;
        procedure write(const src: byte_Array1d); virtual; overload;
        procedure write(const src: byte_Array1d; offset, length: int); virtual; overload;
        procedure close(); virtual;
    end;

    IOStream = class(_Object, Closeable)
    public
        function seekSupported(): boolean; virtual;
        function truncateSupported(): boolean; virtual;
        function seek(delta: long): long; virtual;
        function reset(position: long = 0): long; virtual;
        function position(): long; virtual;
        function truncate(): long; virtual;
        function getInputStream(): InputStream; virtual; abstract;
        function getOutputStream(): OutputStream; virtual; abstract;
        procedure close(); virtual;
    end;

    DataInputStream = class(InputStream, DataInput)
    protected
        stream: Input;
    public
        constructor create(stream: Input);
        function seekSupported(): boolean; override;
        function seek(delta: long): long; override;
        function reset(position: long = 0): long; override;
        function position(): long; override;
        function available(): long; override;
        function size(): long; override;
        function read(): int; override; overload;
        function read(const dst: byte_Array1d): int; override; overload;
        function read(const dst: byte_Array1d; offset, length: int): int; override; overload;
        function skipBytes(count: int): int;
        function readBoolean(): boolean;
        function readChar(): char;
        function readWChar(): wchar;
        function readByte(): int;
        function readShort(): int;
        function readInt(): int;
        function readLong(): long;
        function readFloat(): float;
        function readDouble(): double;
        function readReal(): real;
        function readUnsignedByte(): int;
        function readUnsignedShort(): int;
        function readWCharLE(): wchar;
        function readShortLE(): int;
        function readIntLE(): int;
        function readLongLE(): long;
        function readFloatLE(): float;
        function readDoubleLE(): double;
        function readRealLE(): real;
        function readUnsignedShortLE(): int;
        function readUTF(): UnicodeString;
        procedure readFully(const dst: byte_Array1d); overload;
        procedure readFully(const dst: byte_Array1d; offset, length: int); overload;
        procedure close(); override;
    end;

    DataOutputStream = class(OutputStream, DataOutput)
    protected
        stream: Output;
    public
        constructor create(stream: Output);
        procedure flush(); override;
        procedure write(data: int); override; overload;
        procedure write(const src: byte_Array1d); override; overload;
        procedure write(const src: byte_Array1d; offset, length: int); override; overload;
        procedure writeBoolean(data: boolean);
        procedure writeChar(data: char);
        procedure writeWChar(data: wchar);
        procedure writeByte(data: int);
        procedure writeShort(data: int);
        procedure writeInt(data: int);
        procedure writeLong(data: long);
        procedure writeFloat(data: float);
        procedure writeDouble(data: double);
        procedure writeReal(const data: real);
        procedure writeWCharLE(data: wchar);
        procedure writeShortLE(data: int);
        procedure writeIntLE(data: int);
        procedure writeLongLE(data: long);
        procedure writeFloatLE(data: float);
        procedure writeDoubleLE(data: double);
        procedure writeRealLE(const data: real);
        procedure writeUTF(const data: UnicodeString);
        procedure writeAnsiChars(const data: AnsiString);
        procedure writeUnicodeChars(const data: UnicodeString);
        procedure writeUnicodeCharsLE(const data: UnicodeString);
        procedure close(); override;
    end;

    ByteArrayInputStream = class(InputStream)
    protected
        offset: int;
        buffer: byte_Array1d;
    public
        constructor create(const buffer: byte_Array1d; offset: int = 0);
        function seekSupported(): boolean; override;
        function seek(delta: long): long; override;
        function reset(position: long = 0): long; override;
        function position(): long; override;
        function available(): long; override;
        function size(): long; override;
        function read(): int; override; overload;
        function read(const dst: byte_Array1d; offset, length: int): int; override; overload;
    end;

    ByteArrayOutputStream = class(OutputStream)
    protected
        offset: int;
        buffer: byte_Array1d;
    public
        constructor create(initialCapacity: int = 0);
        function toString(): AnsiString; override;
        function toByteArray(): byte_Array1d; virtual;
        function size(): int; virtual;
        procedure reset(); virtual;
        procedure write(data: int); override; overload;
        procedure write(const src: byte_Array1d; offset, length: int); override; overload;
    end;

    ByteArrayIOStream = class(IOStream)
    private
        inputPos: int;
        inputPtr: InputStream;
        inputIntf: Input;
        outputPos: int;
        outputPtr: OutputStream;
        outputIntf: Output;
        bufferSize: int;
        buffer: byte_Array1d;
    public
        constructor create(initialCapacity: int = 0); overload;
        constructor create(const buffer: byte_Array1d; writePosition: int = 0; readPosition: int = 0); overload;
        function toString(): AnsiString; override;
        function toByteArray(): byte_Array1d; virtual;
        function size(): int; virtual;
        function seekSupported(): boolean; override;
        function truncateSupported(): boolean; override;
        function seek(delta: long): long; override;
        function reset(position: long = 0): long; override;
        function position(): long; override;
        function truncate(): long; override;
        function getInputStream(): InputStream; override;
        function getOutputStream(): OutputStream; override;
        procedure close(); override;
    end;

    IOException = class(Exception);

    EOFException = class(IOException);

    UTFDataFormatException = class(IOException);

resourcestring
    msgTruncatingNotSupported = 'Обрезка не поддерживается';
    msgPositioningNotSupported = 'Позиционирование не поддерживается';
    msgEndOfStream = 'Достигнут конец потока данных';
    msgArrayFull = 'Достигнут максимальный размер массива';
    msgUTFDataTooLong = 'Размер данных, закодированных кодировкой UTF-8, не может превышать 65535 байт';
    msgParentIOStreamClosed = 'Родительский поток данных закрыт';
{%endregion}

implementation

{%region private }
type
    ByteArrayIOStream0InputStream = class;
    ByteArrayIOStream0OutputStream = class;

    ByteArrayIOStream0InputStream = class(InputStream)
    private
        owner: ByteArrayIOStream;
    public
        constructor create(owner: ByteArrayIOStream);
        function seekSupported(): boolean; override;
        function seek(delta: long): long; override;
        function reset(position: long = 0): long; override;
        function position(): long; override;
        function available(): long; override;
        function size(): long; override;
        function read(): int; override; overload;
        function read(const dst: byte_Array1d; offset, length: int): int; override; overload;
    end;

    ByteArrayIOStream0OutputStream = class(OutputStream)
    private
        owner: ByteArrayIOStream;
    public
        constructor create(owner: ByteArrayIOStream);
        procedure write(data: int); override; overload;
        procedure write(const src: byte_Array1d; offset, length: int); override; overload;
    end;
{%endregion}

{%region InputStream }
    function InputStream.seekSupported(): boolean;
    begin
        result := false;
    end;

    function InputStream.seek(delta: long): long;
    var
        i: long;
    begin
        if delta < 0 then begin
            raise IOException.create('InputStream.seek: ' + msgPositioningNotSupported);
        end;
        for i := 0 to delta - 1 do begin
            read();
        end;
        result := position();
    end;

    function InputStream.reset(position: long): long;
    begin
        raise IOException.create('InputStream.reset: ' + msgPositioningNotSupported);
    end;

    function InputStream.position(): long;
    begin
        result := 0;
    end;

    function InputStream.available(): long;
    begin
        result := 0;
    end;

    function InputStream.size(): long;
    begin
        result := 0;
    end;

    function InputStream.read(const dst: byte_Array1d): int;
    begin
        result := read(dst, 0, length(dst));
    end;

    function InputStream.read(const dst: byte_Array1d; offset, length: int): int;
    var
        readed: int;
    begin
        arrayCheckBounds('InputStream.read', system.length(dst), offset, length);
        result := 0;
        while result < length do begin
            try
                readed := read();
                if readed < 0 then begin
                    if result = 0 then dec(result);
                    break;
                end;
                dst[offset] := byte(readed);
                inc(offset);
            except
                on e: IOException do begin
                    if result > 0 then break;
                    raise;
                end;
            end;
            inc(result);
        end;
    end;

    procedure InputStream.close();
    begin
    end;
{%endregion}

{%region OutputStream }
    procedure OutputStream.flush();
    begin
    end;

    procedure OutputStream.write(const src: byte_Array1d);
    begin
        write(src, 0, length(src));
    end;

    procedure OutputStream.write(const src: byte_Array1d; offset, length: int);
    begin
        arrayCheckBounds('OutputStream.write', system.length(src), offset, length);
        while length > 0 do begin
            write(src[offset]);
            inc(offset);
            dec(length);
        end;
    end;

    procedure OutputStream.close();
    begin
    end;
{%endregion}

{%region IOStream }
    function IOStream.seekSupported(): boolean;
    begin
        result := false;
    end;

    function IOStream.truncateSupported(): boolean;
    begin
        result := false;
    end;

    function IOStream.seek(delta: long): long;
    begin
        raise IOException.create('IOStream.seek: ' + msgPositioningNotSupported);
    end;

    function IOStream.reset(position: long): long;
    begin
        raise IOException.create('IOStream.reset: ' + msgPositioningNotSupported);
    end;

    function IOStream.position(): long;
    begin
        result := seek(0);
    end;

    function IOStream.truncate(): long;
    begin
        raise IOException.create('IOStream.truncate: ' + msgTruncatingNotSupported);
    end;

    procedure IOStream.close();
    begin
        free();
    end;
{%endregion}

{%region DataInputStream }
    constructor DataInputStream.create(stream: Input);
    begin
        inherited create();
        self.stream := stream;
    end;

    function DataInputStream.seekSupported(): boolean;
    begin
        result := stream.seekSupported();
    end;

    function DataInputStream.seek(delta: long): long;
    begin
        result := stream.seek(delta);
    end;

    function DataInputStream.reset(position: long): long;
    begin
        result := stream.reset(position);
    end;

    function DataInputStream.position(): long;
    begin
        result := stream.position();
    end;

    function DataInputStream.available(): long;
    begin
        result := stream.available();
    end;

    function DataInputStream.size(): long;
    begin
        result := stream.size();
    end;

    function DataInputStream.read(): int;
    begin
        result := stream.read();
    end;

    function DataInputStream.read(const dst: byte_Array1d): int;
    begin
        result := stream.read(dst);
    end;

    function DataInputStream.read(const dst: byte_Array1d; offset, length: int): int;
    begin
        result := stream.read(dst, offset, length);
    end;

    function DataInputStream.skipBytes(count: int): int;
    var
        skiped: int;
        position: long;
        stream: Input;
    begin
        stream := self.stream;
        result := 0;
        while count > 0 do begin
            position := stream.position();
            skiped := int(stream.seek(count) - position);
            if skiped <= 0 then break;
            inc(result, skiped);
            dec(count, skiped);
        end;
    end;

    function DataInputStream.readBoolean(): boolean;
    var
        data: int;
    begin
        data := stream.read();
        if data < 0 then begin
            raise EOFException.create('DataInputStream.readBoolean: ' + msgEndOfStream);
        end;
        result := (data and $ff) > 0;
    end;

    function DataInputStream.readChar(): char;
    var
        data: int;
    begin
        data := stream.read();
        if data < 0 then begin
            raise EOFException.create('DataInputStream.readChar: ' + msgEndOfStream);
        end;
        result := char(data);
    end;

    function DataInputStream.readWChar(): wchar;
    var
        b0: int;
        b1: int;
        stream: Input;
    begin
        stream := self.stream;
        b1 := stream.read();
        b0 := stream.read();
        if (b0 or b1) < 0 then begin
            raise EOFException.create('DataInputStream.readWChar: ' + msgEndOfStream);
        end;
        result := wchar((b1 shl 8) or (b0 and $ff));
    end;

    function DataInputStream.readByte(): int;
    var
        data: int;
    begin
        data := stream.read();
        if data < 0 then begin
            raise EOFException.create('DataInputStream.readByte: ' + msgEndOfStream);
        end;
        result := byte(data);
    end;

    function DataInputStream.readShort(): int;
    var
        b0: int;
        b1: int;
        stream: Input;
    begin
        stream := self.stream;
        b1 := stream.read();
        b0 := stream.read();
        if (b0 or b1) < 0 then begin
            raise EOFException.create('DataInputStream.readShort: ' + msgEndOfStream);
        end;
        result := short((b1 shl 8) or (b0 and $ff));
    end;

    function DataInputStream.readInt(): int;
    var
        b0: int;
        b1: int;
        b2: int;
        b3: int;
        stream: Input;
    begin
        stream := self.stream;
        b3 := stream.read();
        b2 := stream.read();
        b1 := stream.read();
        b0 := stream.read();
        if (b0 or b1 or b2 or b3) < 0 then begin
            raise EOFException.create('DataInputStream.readInt: ' + msgEndOfStream);
        end;
        result := (b3 shl 24) or ((b2 and $ff) shl 16) or ((b1 and $ff) shl 8) or (b0 and $ff);
    end;

    function DataInputStream.readLong(): long;
    var
        b0: long;
        b1: long;
        b2: long;
        b3: long;
        b4: long;
        b5: long;
        b6: long;
        b7: long;
        stream: Input;
    begin
        stream := self.stream;
        b7 := stream.read();
        b6 := stream.read();
        b5 := stream.read();
        b4 := stream.read();
        b3 := stream.read();
        b2 := stream.read();
        b1 := stream.read();
        b0 := stream.read();
        if (b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7) < 0 then begin
            raise EOFException.create('DataInputStream.readLong: ' + msgEndOfStream);
        end;
        result := (b7 shl 56) or ((b6 and $ff) shl 48) or ((b5 and $ff) shl 40) or ((b4 and $ff) shl 32) or ((b3 and $ff) shl 24) or ((b2 and $ff) shl 16) or ((b1 and $ff) shl 8) or (b0 and $ff);
    end;

    function DataInputStream.readFloat(): float;
    var
        b0: int;
        b1: int;
        b2: int;
        b3: int;
        stream: Input;
    begin
        stream := self.stream;
        b3 := stream.read();
        b2 := stream.read();
        b1 := stream.read();
        b0 := stream.read();
        if (b0 or b1 or b2 or b3) < 0 then begin
            raise EOFException.create('DataInputStream.readFloat: ' + msgEndOfStream);
        end;
        result := intBitsToFloat((b3 shl 24) or ((b2 and $ff) shl 16) or ((b1 and $ff) shl 8) or (b0 and $ff));
    end;

    function DataInputStream.readDouble(): double;
    var
        b0: long;
        b1: long;
        b2: long;
        b3: long;
        b4: long;
        b5: long;
        b6: long;
        b7: long;
        stream: Input;
    begin
        stream := self.stream;
        b7 := stream.read();
        b6 := stream.read();
        b5 := stream.read();
        b4 := stream.read();
        b3 := stream.read();
        b2 := stream.read();
        b1 := stream.read();
        b0 := stream.read();
        if (b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7) < 0 then begin
            raise EOFException.create('DataInputStream.readDouble: ' + msgEndOfStream);
        end;
        result := longBitsToDouble((b7 shl 56) or ((b6 and $ff) shl 48) or ((b5 and $ff) shl 40) or ((b4 and $ff) shl 32) or ((b3 and $ff) shl 24) or ((b2 and $ff) shl 16) or ((b1 and $ff) shl 8) or (b0 and $ff));
    end;

    function DataInputStream.readReal(): real;
    var
        a0: int;
        a1: int;
        b0: long;
        b1: long;
        b2: long;
        b3: long;
        b4: long;
        b5: long;
        b6: long;
        b7: long;
        stream: Input;
    begin
        stream := self.stream;
        a1 := stream.read();
        a0 := stream.read();
        b7 := stream.read();
        b6 := stream.read();
        b5 := stream.read();
        b4 := stream.read();
        b3 := stream.read();
        b2 := stream.read();
        b1 := stream.read();
        b0 := stream.read();
        if (b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7 or long(a0) or long(a1)) < 0 then begin
            raise EOFException.create('DataInputStream.readReal: ' + msgEndOfStream);
        end;
        a0 := (a1 shl 8) or (a0 and $ff);
        b0 := (b7 shl 56) or ((b6 and $ff) shl 48) or ((b5 and $ff) shl 40) or ((b4 and $ff) shl 32) or ((b3 and $ff) shl 24) or ((b2 and $ff) shl 16) or ((b1 and $ff) shl 8) or (b0 and $ff);
        result := realBuild(a0, b0);
    end;

    function DataInputStream.readUnsignedByte(): int;
    var
        data: int;
    begin
        data := stream.read();
        if data < 0 then begin
            raise EOFException.create('DataInputStream.readUnsignedByte: ' + msgEndOfStream);
        end;
        result := data and $ff;
    end;

    function DataInputStream.readUnsignedShort(): int;
    var
        b0: int;
        b1: int;
        stream: Input;
    begin
        stream := self.stream;
        b1 := stream.read();
        b0 := stream.read();
        if (b0 or b1) < 0 then begin
            raise EOFException.create('DataInputStream.readUnsignedShort: ' + msgEndOfStream);
        end;
        result := ((b1 and $ff) shl 8) or (b0 and $ff);
    end;

    function DataInputStream.readWCharLE(): wchar;
    var
        b0: int;
        b1: int;
        stream: Input;
    begin
        stream := self.stream;
        b0 := stream.read();
        b1 := stream.read();
        if (b0 or b1) < 0 then begin
            raise EOFException.create('DataInputStream.readWCharLE: ' + msgEndOfStream);
        end;
        result := wchar((b1 shl 8) or (b0 and $ff));
    end;

    function DataInputStream.readShortLE(): int;
    var
        b0: int;
        b1: int;
        stream: Input;
    begin
        stream := self.stream;
        b0 := stream.read();
        b1 := stream.read();
        if (b0 or b1) < 0 then begin
            raise EOFException.create('DataInputStream.readShortLE: ' + msgEndOfStream);
        end;
        result := short((b1 shl 8) or (b0 and $ff));
    end;

    function DataInputStream.readIntLE(): int;
    var
        b0: int;
        b1: int;
        b2: int;
        b3: int;
        stream: Input;
    begin
        stream := self.stream;
        b0 := stream.read();
        b1 := stream.read();
        b2 := stream.read();
        b3 := stream.read();
        if (b0 or b1 or b2 or b3) < 0 then begin
            raise EOFException.create('DataInputStream.readIntLE: ' + msgEndOfStream);
        end;
        result := (b3 shl 24) or ((b2 and $ff) shl 16) or ((b1 and $ff) shl 8) or (b0 and $ff);
    end;

    function DataInputStream.readLongLE(): long;
    var
        b0: long;
        b1: long;
        b2: long;
        b3: long;
        b4: long;
        b5: long;
        b6: long;
        b7: long;
        stream: Input;
    begin
        stream := self.stream;
        b0 := stream.read();
        b1 := stream.read();
        b2 := stream.read();
        b3 := stream.read();
        b4 := stream.read();
        b5 := stream.read();
        b6 := stream.read();
        b7 := stream.read();
        if (b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7) < 0 then begin
            raise EOFException.create('DataInputStream.readLongLE: ' + msgEndOfStream);
        end;
        result := (b7 shl 56) or ((b6 and $ff) shl 48) or ((b5 and $ff) shl 40) or ((b4 and $ff) shl 32) or ((b3 and $ff) shl 24) or ((b2 and $ff) shl 16) or ((b1 and $ff) shl 8) or (b0 and $ff);
    end;

    function DataInputStream.readFloatLE(): float;
    var
        b0: int;
        b1: int;
        b2: int;
        b3: int;
        stream: Input;
    begin
        stream := self.stream;
        b0 := stream.read();
        b1 := stream.read();
        b2 := stream.read();
        b3 := stream.read();
        if (b0 or b1 or b2 or b3) < 0 then begin
            raise EOFException.create('DataInputStream.readFloatLE: ' + msgEndOfStream);
        end;
        result := intBitsToFloat((b3 shl 24) or ((b2 and $ff) shl 16) or ((b1 and $ff) shl 8) or (b0 and $ff));
    end;

    function DataInputStream.readDoubleLE(): double;
    var
        b0: long;
        b1: long;
        b2: long;
        b3: long;
        b4: long;
        b5: long;
        b6: long;
        b7: long;
        stream: Input;
    begin
        stream := self.stream;
        b0 := stream.read();
        b1 := stream.read();
        b2 := stream.read();
        b3 := stream.read();
        b4 := stream.read();
        b5 := stream.read();
        b6 := stream.read();
        b7 := stream.read();
        if (b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7) < 0 then begin
            raise EOFException.create('DataInputStream.readDoubleLE: ' + msgEndOfStream);
        end;
        result := longBitsToDouble((b7 shl 56) or ((b6 and $ff) shl 48) or ((b5 and $ff) shl 40) or ((b4 and $ff) shl 32) or ((b3 and $ff) shl 24) or ((b2 and $ff) shl 16) or ((b1 and $ff) shl 8) or (b0 and $ff));
    end;

    function DataInputStream.readRealLE(): real;
    var
        a0: int;
        a1: int;
        b0: long;
        b1: long;
        b2: long;
        b3: long;
        b4: long;
        b5: long;
        b6: long;
        b7: long;
        stream: Input;
    begin
        stream := self.stream;
        b0 := stream.read();
        b1 := stream.read();
        b2 := stream.read();
        b3 := stream.read();
        b4 := stream.read();
        b5 := stream.read();
        b6 := stream.read();
        b7 := stream.read();
        a0 := stream.read();
        a1 := stream.read();
        if (b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7 or long(a0) or long(a1)) < 0 then begin
            raise EOFException.create('DataInputStream.readRealLE: ' + msgEndOfStream);
        end;
        a0 := (a1 shl 8) or (a0 and $ff);
        b0 := (b7 shl 56) or ((b6 and $ff) shl 48) or ((b5 and $ff) shl 40) or ((b4 and $ff) shl 32) or ((b3 and $ff) shl 24) or ((b2 and $ff) shl 16) or ((b1 and $ff) shl 8) or (b0 and $ff);
        result := realBuild(a0, b0);
    end;

    function DataInputStream.readUnsignedShortLE(): int;
    var
        b0: int;
        b1: int;
        stream: Input;
    begin
        stream := self.stream;
        b0 := stream.read();
        b1 := stream.read();
        if (b0 or b1) < 0 then begin
            raise EOFException.create('DataInputStream.readUnsignedShortLE: ' + msgEndOfStream);
        end;
        result := ((b1 and $ff) shl 8) or (b0 and $ff);
    end;

    function DataInputStream.readUTF(): UnicodeString;
    var
        i: int;
        slen: int;
        rlen: int;
        char1: int;
        char2: int;
        char3: int;
        str: byte_Array1d;
        buf: short_Array1d;
    begin
        slen := readUnsignedShort();
        if slen <= 0 then begin
            result := '';
            exit;
        end;
        str := byte_Array1d_create(slen);
        readFully(str, 0, slen);
        rlen := 0;
        buf := short_Array1d_create(slen);
        i := 0;
        while i < slen do begin
            char1 := str[i] and $ff;
            inc(i);
            if (char1 >= $00) and (char1 < $80) then begin
                buf[rlen] := short(char1);
                inc(rlen);
            end else
            if (char1 >= $c0) and (char1 < $e0) then begin
                char2 := 0;
                if i < slen then begin
                    char2 := str[i] and $ff;
                    if (char2 and $c0) <> $80 then begin
                        char2 := 0;
                    end else begin
                        inc(i);
                    end;
                end;
                buf[rlen] := short(((char1 and $1f) shl 6) or (char2 and $3f));
                inc(rlen);
            end else
            if (char1 >= $e0) and (char1 < $f0) then begin
                char2 := 0;
                char3 := 0;
                if i < slen then begin
                    char2 := str[i] and $ff;
                    if (char2 and $c0) <> $80 then begin
                        char2 := 0;
                    end else begin
                        inc(i);
                    end;
                end;
                if i < slen then begin
                    char3 := str[i] and $ff;
                    if (char3 and $c0) <> $80 then begin
                        char3 := 0;
                    end else begin
                        inc(i);
                    end;
                end;
                buf[rlen] := short(((char1 and $0f) shl 12) or ((char2 and $3f) shl 6) or (char3 and $3f));
                inc(rlen);
            end;
        end;
        result := UnicodeString_create(buf, 0, rlen);
    end;

    procedure DataInputStream.readFully(const dst: byte_Array1d);
    var
        offset: int;
        length: int;
        readed: int;
        stream: Input;
    begin
        offset := 0;
        length := system.length(dst);
        stream := self.stream;
        while length > 0 do begin
            readed := stream.read(dst, offset, length);
            if readed <= 0 then begin
                raise EOFException.create('DataInputStream.readFully: ' + msgEndOfStream);
            end;
            inc(offset, readed);
            dec(length, readed);
        end;
    end;

    procedure DataInputStream.readFully(const dst: byte_Array1d; offset, length: int);
    var
        readed: int;
        stream: Input;
    begin
        arrayCheckBounds('DataInputStream.readFully', system.length(dst), offset, length);
        stream := self.stream;
        while length > 0 do begin
            readed := stream.read(dst, offset, length);
            if readed <= 0 then begin
                raise EOFException.create('DataInputStream.readFully: ' + msgEndOfStream);
            end;
            inc(offset, readed);
            dec(length, readed);
        end;
    end;

    procedure DataInputStream.close();
    begin
        stream.close();
    end;
{%endregion}

{%region DataOutputStream }
    constructor DataOutputStream.create(stream: Output);
    begin
        inherited create();
        self.stream := stream;
    end;

    procedure DataOutputStream.flush();
    begin
        stream.flush();
    end;

    procedure DataOutputStream.write(data: int);
    begin
        stream.write(data);
    end;

    procedure DataOutputStream.write(const src: byte_Array1d);
    begin
        stream.write(src);
    end;

    procedure DataOutputStream.write(const src: byte_Array1d; offset, length: int);
    begin
        stream.write(src, offset, length);
    end;

    procedure DataOutputStream.writeBoolean(data: boolean);
    begin
        if data then begin
            stream.write(1);
        end else begin
            stream.write(0);
        end;
    end;

    procedure DataOutputStream.writeChar(data: char);
    begin
        stream.write(int(data));
    end;

    procedure DataOutputStream.writeWChar(data: wchar);
    var
        stream: Output;
    begin
        stream := self.stream;
        stream.write(int(data) shr 8);
        stream.write(int(data));
    end;

    procedure DataOutputStream.writeByte(data: int);
    begin
        stream.write(data);
    end;

    procedure DataOutputStream.writeShort(data: int);
    var
        stream: Output;
    begin
        stream := self.stream;
        stream.write(data shr 8);
        stream.write(data);
    end;

    procedure DataOutputStream.writeInt(data: int);
    var
        stream: Output;
    begin
        stream := self.stream;
        stream.write(data shr $18);
        stream.write(data shr $10);
        stream.write(data shr $08);
        stream.write(data);
    end;

    procedure DataOutputStream.writeLong(data: long);
    var
        stream: Output;
    begin
        stream := self.stream;
        stream.write(int(data shr $38));
        stream.write(int(data shr $30));
        stream.write(int(data shr $28));
        stream.write(int(data shr $20));
        stream.write(int(data shr $18));
        stream.write(int(data shr $10));
        stream.write(int(data shr $08));
        stream.write(int(data));
    end;

    procedure DataOutputStream.writeFloat(data: float);
    begin
        writeInt(floatToIntBits(data));
    end;

    procedure DataOutputStream.writeDouble(data: double);
    begin
        writeLong(doubleToLongBits(data));
    end;

    procedure DataOutputStream.writeReal(const data: real);
    begin
        writeShort(realExponent(data));
        writeLong(realSignificand(data));
    end;

    procedure DataOutputStream.writeWCharLE(data: wchar);
    var
        stream: Output;
    begin
        stream := self.stream;
        stream.write(int(data));
        stream.write(int(data) shr 8);
    end;

    procedure DataOutputStream.writeShortLE(data: int);
    var
        stream: Output;
    begin
        stream := self.stream;
        stream.write(data);
        stream.write(data shr 8);
    end;

    procedure DataOutputStream.writeIntLE(data: int);
    var
        stream: Output;
    begin
        stream := self.stream;
        stream.write(data);
        stream.write(data shr $08);
        stream.write(data shr $10);
        stream.write(data shr $18);
    end;

    procedure DataOutputStream.writeLongLE(data: long);
    var
        stream: Output;
    begin
        stream := self.stream;
        stream.write(int(data));
        stream.write(int(data shr $08));
        stream.write(int(data shr $10));
        stream.write(int(data shr $18));
        stream.write(int(data shr $20));
        stream.write(int(data shr $28));
        stream.write(int(data shr $30));
        stream.write(int(data shr $38));
    end;

    procedure DataOutputStream.writeFloatLE(data: float);
    begin
        writeIntLE(floatToIntBits(data));
    end;

    procedure DataOutputStream.writeDoubleLE(data: double);
    begin
        writeLongLE(doubleToLongBits(data));
    end;

    procedure DataOutputStream.writeRealLE(const data: real);
    begin
        writeLongLE(realSignificand(data));
        writeShortLE(realExponent(data));
    end;

    procedure DataOutputStream.writeUTF(const data: UnicodeString);
    var
        i: int;
        slen: int;
        rlen: int;
        code: int;
        buf: byte_Array1d;
    begin
        slen := length(data);
        if (slen > $ffff) or (slen < 0) then begin
            raise UTFDataFormatException.create('DataOutputStream.writeUTF: ' + msgUTFDataTooLong);
        end;
        rlen := 0;
        for i := slen downto 1 do begin
            code := int(data[i]);
            if (code >= $0001) and (code < $0080) then begin
                inc(rlen, 1);
            end else
            if code < $0800 then begin
                inc(rlen, 2);
            end else begin
                inc(rlen, 3);
            end;
        end;
        if rlen > $ffff then begin
            raise UTFDataFormatException.create('DataOutputStream.writeUTF: ' + msgUTFDataTooLong);
        end;
        buf := byte_Array1d_create(rlen);
        rlen := 0;
        for i := 0 to slen - 1 do begin
            code := int(data[i + 1]);
            if (code >= $0001) and (code < $0080) then begin
                buf[rlen] := byte(code);
                inc(rlen);
            end else
            if code < $0800 then begin
                buf[rlen] := byte($c0 + (code shr 6));
                buf[rlen + 1] := byte($80 + (code and $3f));
                inc(rlen, 2);
            end else begin
                buf[rlen] := byte($e0 + (code shr 12));
                buf[rlen + 1] := byte($80 + ((code shr 6) and $3f));
                buf[rlen + 2] := byte($80 + (code and $3f));
                inc(rlen, 3);
            end;
        end;
        writeShort(rlen);
        write(buf, 0, rlen);
    end;

    procedure DataOutputStream.writeAnsiChars(const data: AnsiString);
    var
        i: int;
        stream: Output;
    begin
        stream := self.stream;
        for i := 0 to length(data) - 1 do begin
            stream.write(int(data[i + 1]));
        end;
    end;

    procedure DataOutputStream.writeUnicodeChars(const data: UnicodeString);
    var
        i: int;
        c: int;
        stream: Output;
    begin
        stream := self.stream;
        for i := 0 to length(data) - 1 do begin
            c := int(data[i + 1]);
            stream.write(c shr 8);
            stream.write(c);
        end;
    end;

    procedure DataOutputStream.writeUnicodeCharsLE(const data: UnicodeString);
    var
        i: int;
        c: int;
        stream: Output;
    begin
        stream := self.stream;
        for i := 0 to length(data) - 1 do begin
            c := int(data[i + 1]);
            stream.write(c);
            stream.write(c shr 8);
        end;
    end;

    procedure DataOutputStream.close();
    begin
        stream.close();
    end;
{%endregion}

{%region ByteArrayInputStream }
    constructor ByteArrayInputStream.create(const buffer: byte_Array1d; offset: int);
    begin
        inherited create();
        self.offset := offset;
        self.buffer := buffer;
    end;

    function ByteArrayInputStream.seekSupported(): boolean;
    begin
        result := true;
    end;

    function ByteArrayInputStream.seek(delta: long): long;
    var
        cap: int;
        pos: int;
        newpos: int;
    begin
        cap := length(buffer);
        pos := intBound(0, offset, cap);
        newpos := int(longBound(0, long(pos) + delta, long(cap)));
        self.offset := newpos;
        result := newpos;
    end;

    function ByteArrayInputStream.reset(position: long): long;
    var
        cap: int;
        newpos: int;
    begin
        cap := length(buffer);
        newpos := int(longBound(0, position, long(cap)));
        self.offset := newpos;
        result := newpos;
    end;

    function ByteArrayInputStream.position(): long;
    begin
        result := intBound(0, offset, length(buffer));
    end;

    function ByteArrayInputStream.available(): long;
    var
        cap: int;
    begin
        cap := length(buffer);
        result := cap - intBound(0, offset, cap);
    end;

    function ByteArrayInputStream.size(): long;
    begin
        result := length(buffer);
    end;

    function ByteArrayInputStream.read(): int;
    var
        buf: byte_Array1d;
        pos: int;
    begin
        buf := self.buffer;
        pos := self.offset;
        if pos < 0 then pos := 0;
        if pos >= system.length(buf) then begin
            result := -1;
            exit;
        end;
        self.offset := pos + 1;
        result := buf[pos] and $ff;
    end;

    function ByteArrayInputStream.read(const dst: byte_Array1d; offset, length: int): int;
    var
        buf: byte_Array1d;
        pos: int;
        cap: int;
        ready: int;
    begin
        arrayCheckBounds('ByteArrayInputStream.read', system.length(dst), offset, length);
        if length <= 0 then begin
            result := 0;
            exit;
        end;
        buf := self.buffer;
        pos := self.offset;
        cap := system.length(buf);
        if pos < 0 then pos := 0;
        if pos >= cap then begin
            result := -1;
            exit;
        end;
        ready := intMin(cap - pos, length);
        self.offset := pos + ready;
        arraycopyPrimitives(buf, pos, dst, offset, ready);
        result := ready;
    end;
{%endregion}

{%region ByteArrayOutputStream }
    constructor ByteArrayOutputStream.create(initialCapacity: int);
    begin
        inherited create();
        self.buffer := byte_Array1d_create(intMax(initialCapacity, $1f));
    end;

    function ByteArrayOutputStream.toString(): AnsiString;
    var
        buf: byte_Array1d;
    begin
        buf := buffer;
        result := AnsiString_create(buf, 0, intBound(0, offset, length(buf)));
    end;

    function ByteArrayOutputStream.toByteArray(): byte_Array1d;
    var
        buf: byte_Array1d;
        pos: int;
    begin
        buf := buffer;
        pos := intBound(0, offset, length(buf));
        result := byte_Array1d_create(pos);
        arraycopyPrimitives(buf, 0, result, 0, pos);
    end;

    function ByteArrayOutputStream.size(): int;
    begin
        result := intBound(0, offset, length(buffer));
    end;

    procedure ByteArrayOutputStream.reset();
    begin
        offset := 0;
    end;

    procedure ByteArrayOutputStream.write(data: int);
    var
        buf: byte_Array1d;
        cap: int;
        pos: int;
        newbuf: byte_Array1d;
        newcap: int;
    begin
        buf := self.buffer;
        cap := system.length(buf);
        pos := intBound(0, self.offset, cap);
        if pos = INT_MAX_VALUE then begin
            raise IOException.create('ByteArrayOutputStream.write: ' + msgArrayFull);
        end;
        if pos = cap then begin 
            newcap := int(longMin((long(cap) shl 1) + 1, INT_MAX_VALUE));
            newbuf := byte_Array1d_create(newcap);
            arraycopyPrimitives(buf, 0, newbuf, 0, pos);
            self.buffer := newbuf;
            buf := newbuf;
        end;
        self.offset := pos + 1;
        buf[pos] := byte(data);
    end;

    procedure ByteArrayOutputStream.write(const src: byte_Array1d; offset, length: int);
    var
        buf: byte_Array1d;
        cap: int;
        pos: int;
        newbuf: byte_Array1d;
        newcap: int;
        newpos: int;
    begin
        arrayCheckBounds('ByteArrayOutputStream.write', system.length(src), offset, length);
        if length <= 0 then exit;
        buf := self.buffer;
        cap := system.length(buf);
        pos := intBound(0, self.offset, cap);
        newpos := pos + length;
        if newpos < 0 then begin
            raise IOException.create('ByteArrayOutputStream.write: ' + msgArrayFull);
        end;
        if newpos > cap then begin
            newcap := int(longMin((long(cap) shl 1) + 1, INT_MAX_VALUE));
            if newcap < newpos then newcap := int(longMin(long(newpos) + $1f, INT_MAX_VALUE));
            newbuf := byte_Array1d_create(newcap);
            arraycopyPrimitives(buf, 0, newbuf, 0, pos);
            self.buffer := newbuf;
            buf := newbuf;
        end;
        self.offset := newpos;
        arraycopyPrimitives(src, offset, buf, pos, length);
    end;
{%endregion}

{%region ByteArrayIOStream }
    constructor ByteArrayIOStream.create(initialCapacity: int);
    var
        inputPtr: InputStream;
        outputPtr: OutputStream;
    begin
        inherited create();
        inputPtr := ByteArrayIOStream0InputStream.create(self);
        outputPtr := ByteArrayIOStream0OutputStream.create(self);
        if initialCapacity < $1f then initialCapacity := $1f;
        self.inputPtr := inputPtr;
        self.inputIntf := inputPtr;
        self.outputPtr := outputPtr;
        self.outputIntf := outputPtr;
        self.buffer := byte_Array1d_create(initialCapacity);
    end;

    constructor ByteArrayIOStream.create(const buffer: byte_Array1d; writePosition, readPosition: int);
    var
        len: int;
        cap: int;
        newbuf: byte_Array1d;
        inputPtr: InputStream;
        outputPtr: OutputStream;
    begin
        inherited create();
        len := length(buffer);
        cap := int(longMin(long(len) + $1f, INT_MAX_VALUE));
        newbuf := byte_Array1d_create(cap);
        arraycopyPrimitives(buffer, 0, newbuf, 0, len);
        inputPtr := ByteArrayIOStream0InputStream.create(self);
        outputPtr := ByteArrayIOStream0OutputStream.create(self);
        if writePosition < 0 then writePosition := 0;
        if writePosition > len then writePosition := len;
        if readPosition < 0 then readPosition := 0;
        if readPosition > len then readPosition := len;
        self.inputPos := readPosition;
        self.inputPtr := inputPtr;
        self.inputIntf := inputPtr;
        self.outputPos := writePosition;
        self.outputPtr := outputPtr;
        self.outputIntf := outputIntf;
        self.bufferSize := len;
        self.buffer := newbuf;
    end;

    function ByteArrayIOStream.toString(): AnsiString;
    begin
        result := AnsiString_create(buffer, 0, bufferSize);
    end;

    function ByteArrayIOStream.toByteArray(): byte_Array1d;
    var
        len: int;
    begin
        len := bufferSize;
        result := byte_Array1d_create(len);
        arraycopyPrimitives(buffer, 0, result, 0, len);
    end;

    function ByteArrayIOStream.size(): int;
    begin
        result := bufferSize;
    end;

    function ByteArrayIOStream.seekSupported(): boolean;
    begin
        result := true;
    end;

    function ByteArrayIOStream.truncateSupported(): boolean;
    begin
        result := true;
    end;

    function ByteArrayIOStream.seek(delta: long): long;
    var
        newpos: int;
    begin
        newpos := int(longBound(0, outputPos + delta, bufferSize));
        outputPos := newpos;
        result := newpos;
    end;

    function ByteArrayIOStream.reset(position: long): long;
    var
        newpos: int;
    begin
        newpos := int(longBound(0, position, bufferSize));
        outputPos := newpos;
        result := newpos;
    end;

    function ByteArrayIOStream.position(): long;
    begin
        result := outputPos;
    end;

    function ByteArrayIOStream.truncate(): long;
    var
        truncPos: int;
    begin
        truncPos := outputPos;
        if inputPos > truncPos then inputPos := truncPos;
        bufferSize := truncPos;
        result := truncPos;
    end;

    function ByteArrayIOStream.getInputStream(): InputStream;
    begin
        result := inputPtr;
    end;

    function ByteArrayIOStream.getOutputStream(): OutputStream;
    begin
        result := outputPtr;
    end;

    procedure ByteArrayIOStream.close();
    begin
        ByteArrayIOStream0InputStream(inputPtr).owner := nil;
        ByteArrayIOStream0OutputStream(outputPtr).owner := nil;
        inherited close();
    end;
{%endregion}

{%region ByteArrayIOStream0InputStream }
    constructor ByteArrayIOStream0InputStream.create(owner: ByteArrayIOStream);
    begin
        inherited create();
        self.owner := owner;
    end;

    function ByteArrayIOStream0InputStream.seekSupported(): boolean;
    begin
        result := true;
    end;

    function ByteArrayIOStream0InputStream.seek(delta: long): long;
    var
        newpos: int;
        owner: ByteArrayIOStream;
    begin
        owner := self.owner;
        if owner = nil then begin
            raise IOException.create('InputStream.seek: ' + msgParentIOStreamClosed);
        end;
        newpos := int(longBound(0, long(owner.inputPos) + delta, long(owner.bufferSize)));
        owner.inputPos := newpos;
        result := newpos;
    end;

    function ByteArrayIOStream0InputStream.reset(position: long): long;
    var
        newpos: int;
        owner: ByteArrayIOStream;
    begin
        owner := self.owner;
        if owner = nil then begin
            raise IOException.create('InputStream.reset: ' + msgParentIOStreamClosed);
        end;
        newpos := int(longBound(0, position, long(owner.bufferSize)));
        owner.inputPos := newpos;
        result := newpos;
    end;

    function ByteArrayIOStream0InputStream.position(): long;
    var
        owner: ByteArrayIOStream;
    begin
        owner := self.owner;
        if owner = nil then begin
            raise IOException.create('InputStream.position: ' + msgParentIOStreamClosed);
        end;
        result := owner.inputPos;
    end;

    function ByteArrayIOStream0InputStream.available(): long;
    var
        owner: ByteArrayIOStream;
    begin
        owner := self.owner;
        if owner = nil then begin
            raise IOException.create('InputStream.available: ' + msgParentIOStreamClosed);
        end;
        result := owner.bufferSize - owner.inputPos;
    end;

    function ByteArrayIOStream0InputStream.size(): long;
    var
        owner: ByteArrayIOStream;
    begin
        owner := self.owner;
        if owner = nil then begin
            raise IOException.create('InputStream.size: ' + msgParentIOStreamClosed);
        end;
        result := owner.bufferSize;
    end;

    function ByteArrayIOStream0InputStream.read(): int;
    var
        pos: int;
        owner: ByteArrayIOStream;
    begin
        owner := self.owner;
        if owner = nil then begin
            raise IOException.create('InputStream.read: ' + msgParentIOStreamClosed);
        end;
        pos := owner.inputPos;
        if pos >= owner.bufferSize then begin
            result := -1;
            exit;
        end;
        owner.inputPos := pos + 1;
        result := owner.buffer[pos] and $ff;
    end;

    function ByteArrayIOStream0InputStream.read(const dst: byte_Array1d; offset, length: int): int;
    var
        pos: int;
        ready: int;
        owner: ByteArrayIOStream;
    begin
        owner := self.owner;
        if owner = nil then begin
            raise IOException.create('InputStream.read: ' + msgParentIOStreamClosed);
        end;
        arrayCheckBounds('InputStream.read', system.length(dst), offset, length);
        if length <= 0 then begin
            result := 0;
            exit;
        end;
        pos := owner.inputPos;
        ready := intMin(owner.bufferSize - pos, length);
        arraycopyPrimitives(owner.buffer, pos, dst, offset, ready);
        owner.inputPos := pos + ready;
        result := ready;
    end;
{%endregion}

{%region ByteArrayIOStream0OutputStream }
    constructor ByteArrayIOStream0OutputStream.create(owner: ByteArrayIOStream);
    begin
        inherited create();
        self.owner := owner;
    end;

    procedure ByteArrayIOStream0OutputStream.write(data: int);
    var
        buf: byte_Array1d;
        pos: int;
        len: int;
        cap: int;
        newbuf: byte_Array1d;
        newpos: int;
        newcap: int;
        owner: ByteArrayIOStream;
    begin
        owner := self.owner;
        if owner = nil then begin
            raise IOException.create('OutputStream.write: ' + msgParentIOStreamClosed);
        end;
        buf := owner.buffer;
        pos := owner.outputPos;
        len := owner.bufferSize;
        cap := system.length(buf);
        newpos := pos + 1;
        if newpos < 0 then begin
            raise IOException.create('OutputStream.write: ' + msgArrayFull);
        end;
        if newpos > cap then begin
            newcap := int(longMin((long(cap) shl 1) + 1, INT_MAX_VALUE));
            newbuf := byte_Array1d_create(newcap);
            arraycopyPrimitives(buf, 0, newbuf, 0, len);
            owner.buffer := newbuf;
            buf := newbuf;
        end;
        buf[pos] := byte(data);
        owner.outputPos := newpos;
        if len < newpos then owner.bufferSize := newpos;
    end;

    procedure ByteArrayIOStream0OutputStream.write(const src: byte_Array1d; offset, length: int);
    var
        buf: byte_Array1d;
        pos: int;
        len: int;
        cap: int;
        newbuf: byte_Array1d;
        newpos: int;
        newcap: int;
        owner: ByteArrayIOStream;
    begin
        owner := self.owner;
        if owner = nil then begin
            raise IOException.create('OutputStream.write: ' + msgParentIOStreamClosed);
        end;
        arrayCheckBounds('OutputStream.write', system.length(src), offset, length);
        if length <= 0 then exit;
        buf := owner.buffer;
        pos := owner.outputPos;
        len := owner.bufferSize;
        cap := system.length(buf);
        newpos := pos + length;
        if newpos < 0 then begin
            raise IOException.create('OutputStream.write: ' + msgArrayFull);
        end;
        if newpos > cap then begin
            newcap := int(longMin((long(cap) shl 1) + 1, INT_MAX_VALUE));
            if newcap < newpos then newcap := int(longMin(long(newpos) + $1f, INT_MAX_VALUE));
            newbuf := byte_Array1d_create(newcap);
            arraycopyPrimitives(buf, 0, newbuf, 0, len);
            owner.buffer := newbuf;
            buf := newbuf;
        end;
        arraycopyPrimitives(src, offset, buf, pos, length);
        owner.outputPos := newpos;
        if len < newpos then owner.bufferSize := newpos;
    end;
{%endregion}

initialization
    classInfoAdd([
        typeInfo(Closeable),
        typeInfo(Input),
        typeInfo(DataInput),
        typeInfo(Output),
        typeInfo(DataOutput)
    ]);

end.