pascalx.io.bytearray.pas

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

{
    pascalx.io.bytearray — классы ввода-вывода, использующие массивы байтов
    в оперативной памяти.

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

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

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

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

unit pascalx.io.bytearray;

    {$MODE DELPHI}

interface

    {%region} uses
        pascalx.lang,
        pascalx.io,
        pascalx.io.extension;
    {%endregion}

    {$TYPEINFO ON}
    {$CALLING REGISTER}

    const UNIT_NAME = 'pascalx.io.bytearray';

    {%region} type
        ByteArrayInputStream          = class;
        ByteArrayOutputStream         = class;
        ByteArrayBidirectStream       = class;
        ByteArrayBidirectStreamReader = class;
        ByteArrayBidirectStreamWriter = class;

        ByteArrayInputStream = class(&Object, Extension, MarkExtension, ByteReader, SeekExtension, LimitedSizeExtension, Extendable)
        protected
            fldMarked: int;
            fldLength: int;
            fldPosition: int;
            fldArray: byte_Array1d;
        public
            constructor create(); overload;
            constructor create(const aarray: byte_Array1d); overload;
            constructor create(const aarray: byte_Array1d; length: int); overload;
            constructor create(const aarray: byte_Array1d; length, position: int); overload;
            procedure reset(); virtual;
            procedure mark(transferLimit: int); virtual;
            procedure close(); virtual;
            function read(): int; virtual; overload;
            function read(const dst: byte_Array1d): int; virtual; overload;
            function read(const dst: byte_Array1d; offset, length: int): int; virtual; overload;
            function skip(bytesQuantity: long): long; virtual;
            function seek(offset: long; from: SeekFrom): long; virtual;
            function position(): long; virtual;
            function size(): long; virtual;
            function available(): long; virtual;
            function getExtensions(): Extension_Array1d; virtual;
            function getExtension(const typ: ShortString): Extension; virtual;
        end;

        ByteArrayOutputStream = class(&Object, Extension, MarkExtension, ByteWriter, TruncateExtension, SeekExtension, LimitedSizeExtension, Extendable)
        protected
            fldMarked: int;
            fldLength: int;
            fldPosition: int;
            fldArray: byte_Array1d;
            function madeLarger(curLength, newLength: int): byte_Array1d; virtual;
        public
            constructor create(); overload;
            constructor create(const aarray: byte_Array1d); overload;
            constructor create(const aarray: byte_Array1d; length: int); overload;
            constructor create(const aarray: byte_Array1d; length, position: int); overload;
            procedure reset(); virtual;
            procedure mark(transferLimit: int); virtual;
            procedure close(); virtual;
            procedure write(byteData: int); virtual; overload;
            procedure write(const src: byte_Array1d); virtual; overload;
            procedure write(const src: byte_Array1d; offset, length: int); virtual; overload;
            procedure flush(); virtual;
            procedure truncate(); virtual;
            function toString(): AnsiString; override;
            function seek(offset: long; from: SeekFrom): long; virtual;
            function position(): long; virtual;
            function size(): long; virtual;
            function available(): long; virtual;
            function getExtensions(): Extension_Array1d; virtual;
            function getExtension(const typ: ShortString): Extension; virtual;
            function toByteArray(): byte_Array1d; virtual;
        end;

        ByteArrayBidirectStream = class(&Object, ByteStream, Extendable)
        private
            procedure setByte(index: int; value: byte);
            function getByte(index: int): byte;
            function getLength(): int;
            function getArray(): byte_Array1d;
            function getByteArrayReader(): ByteArrayInputStream;
            function getByteArrayWriter(): ByteArrayOutputStream;
        protected
            fldReader: ByteArrayBidirectStreamReader;
            fldWriter: ByteArrayBidirectStreamWriter;
            procedure setReadPosition(newReadPosition: int); virtual;
            procedure setWritePosition(newWritePosition: int); virtual;
            function getReadPosition(): int; virtual;
            function getWritePosition(): int; virtual;
            function createReader(const aarray: byte_Array1d; length, position: int): ByteArrayBidirectStreamReader; virtual;
            function createWriter(const aarray: byte_Array1d; length, position: int): ByteArrayBidirectStreamWriter; virtual;
        public
            constructor create(); overload;
            constructor create(const aarray: byte_Array1d); overload;
            constructor create(const aarray: byte_Array1d; length: int); overload;
            constructor create(const aarray: byte_Array1d; length, readPosition, writePosition: int); overload;
            destructor destroy; override;
            procedure close(); virtual;
            procedure setData(const aarray: byte_Array1d; length: int); virtual;
            function getExtensions(): Extension_Array1d; virtual;
            function getExtension(const typ: ShortString): Extension; virtual;
            function getReader(): ByteReader;
            function getWriter(): ByteWriter;
            property length: int read getLength;
            property byteArray: byte_Array1d read getArray;
            property bytes[index: int]: byte read getByte write setByte; default;
        published
            property reader: ByteReader read getReader;
            property writer: ByteWriter read getWriter;
            property readPosition: int read getReadPosition write setReadPosition;
            property writePosition: int read getWritePosition write setWritePosition;
            property byteArrayReader: ByteArrayInputStream read getByteArrayReader;
            property byteArrayWriter: ByteArrayOutputStream read getByteArrayWriter;
        end;

        ByteArrayBidirectStreamReader = class(ByteArrayInputStream)
        private
            fldCanDestroy: boolean;
        protected
            procedure setData(const newArray: byte_Array1d; newLength: int); virtual;
            procedure setPosition(newPosition: int); virtual;
            procedure notifyLengthChanged(newLength: int); virtual;
        public
            constructor create(const aarray: byte_Array1d; length, position: int);
            procedure beforeDestruction(); override;
            procedure close(); override; final;
        end;

        ByteArrayBidirectStreamWriter = class(ByteArrayOutputStream)
        private
            fldCanDestroy: boolean;
        protected
            fldSource: ByteArrayBidirectStreamReader;
            procedure setData(const newArray: byte_Array1d; newLength: int); virtual;
            procedure setPosition(newPosition: int); virtual;
            procedure notifyLengthChanged(newLength: int); virtual;
            function madeLarger(curLength, newLength: int): byte_Array1d; override;
        public
            constructor create(const aarray: byte_Array1d; length, position: int);
            procedure beforeDestruction(); override;
            procedure close(); override; final;
            procedure truncate(); override;
        end;
    {%endregion}

implementation

    {$CALLING REGISTER}

    {%region  ByteArrayInputStream }
        constructor ByteArrayInputStream.create();
        begin
            inherited create();
        end;

        constructor ByteArrayInputStream.create(const aarray: byte_Array1d);
        begin
            inherited create();
            fldLength := length(aarray);
            fldArray := aarray;
        end;

        constructor ByteArrayInputStream.create(const aarray: byte_Array1d; length: int);
        var
            alength: int;
        begin
            inherited create();
            if length > 0 then begin
                alength := system.length(aarray);
                if length < alength then begin
                    fldLength := length;
                end else begin
                    fldLength := alength;
                end;
                fldArray := aarray;
            end;
        end;

        constructor ByteArrayInputStream.create(const aarray: byte_Array1d; length, position: int);
        var
            alength: int;
            slength: int;
        begin
            inherited create();
            if length > 0 then begin
                alength := system.length(aarray);
                if length < alength then begin
                    slength := length;
                end else begin
                    slength := alength;
                end;
                fldLength := slength;
                if position < 0 then begin
                    fldPosition := 0;
                end else
                if position < slength then begin
                    fldPosition := position;
                end else begin
                    fldPosition := slength;
                end;
                fldArray := aarray;
            end;
        end;

        procedure ByteArrayInputStream.reset();
        begin
            fldPosition := fldMarked;
        end;

        procedure ByteArrayInputStream.mark(transferLimit: int);
        begin
            fldMarked := fldPosition;
        end;

        procedure ByteArrayInputStream.close();
        begin
            destroy;
        end;

        function ByteArrayInputStream.read(): int;
        var
            position: int;
        begin
            position := fldPosition;
            if position >= fldLength then begin
                result := -1;
                exit;
            end;
            fldPosition := position + 1;
            result := fldArray[position] and $ff;
        end;

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

        function ByteArrayInputStream.read(const dst: byte_Array1d; offset, length: int): int;
        var
            position: int;
            remainder: int;
        begin
            &Array.checkBounds(dst, offset, length);
            if length <= 0 then begin
                result := 0;
                exit;
            end;
            position := fldPosition;
            remainder := fldLength - position;
            if remainder <= 0 then begin
                result := -1;
                exit;
            end;
            if length > remainder then length := remainder;
            &Array.copyPrimitives(fldArray, position, dst, offset, length);
            fldPosition := position + length;
            result := length;
        end;

        function ByteArrayInputStream.skip(bytesQuantity: long): long;
        var
            length: int;
            position: int;
            remainder: int;
        begin
            if bytesQuantity <= 0 then begin
                result := 0;
                exit;
            end;
            if bytesQuantity < CoInt.MAX_VALUE then begin
                length := int(bytesQuantity);
            end else begin
                length := CoInt.MAX_VALUE;
            end;
            position := fldPosition;
            remainder := fldLength - position;
            if length > remainder then length := remainder;
            fldPosition := position + length;
            result := length;
        end;

        function ByteArrayInputStream.seek(offset: long; from: SeekFrom): long;
        var
            length: long;
            position: long;
        begin
            length := fldLength;
            case from of
            SeekFrom.sfBegin:
                position := offset;
            SeekFrom.sfEnd:
                position := offset + length;
            SeekFrom.sfCurrent:
                position := offset + fldPosition;
            else
                raise IllegalArgumentException.create(AnsiString.format(AResource.readUnitResourceAsAnsiString(pascalx.lang.UNIT_NAME, 'illegal-argument'), [ CoAnsiString.create('from') ]));
            end;
            if position < 0 then position := 0;
            if position > length then position := length;
            fldPosition := int(position);
            result := position;
        end;

        function ByteArrayInputStream.position(): long;
        begin
            result := fldPosition;
        end;

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

        function ByteArrayInputStream.available(): long;
        begin
            result := fldLength - fldPosition;
        end;

        function ByteArrayInputStream.getExtensions(): Extension_Array1d;
        begin
            result := [ self as Extension ];
        end;

        function ByteArrayInputStream.getExtension(const typ: ShortString): Extension;
        var
            ext: Extension;
        begin
            ext := self;
            if Lang.isInstance(ext, typ) then begin
                result := Extension(Lang.cast(ext, typ));
                exit;
            end;
            result := nil;
        end;
    {%endregion}

    {%region  ByteArrayOutputStream }
        function ByteArrayOutputStream.madeLarger(curLength, newLength: int): byte_Array1d;
        var
            curCapacity: int;
            newCapacity: int;
            curArray: byte_Array1d;
            newArray: byte_Array1d;
        begin
            if newLength < 0 then begin
                raise BufferTooLargeError.create(AResource.readUnitResourceAsAnsiString(pascalx.lang.UNIT_NAME, '!error.buffer-too-large'));
            end;
            newArray := fldArray;
            curArray := newArray;
            curCapacity := length(curArray);
            if curCapacity <= 0 then begin
                if newLength >= CoInt.MAX_VALUE - $7f then begin
                    newCapacity := CoInt.MAX_VALUE;
                end else begin
                    newCapacity := newLength + $7f;
                end;
                newArray := &Array.newByte1d(newCapacity);
                fldArray := newArray;
            end else
            if newLength > curCapacity then begin
                newCapacity := (curCapacity shl 1) or 1;
                if newCapacity < 0 then newCapacity := CoInt.MAX_VALUE;
                if newCapacity < newLength then begin
                    if newLength >= CoInt.MAX_VALUE - $7f then begin
                        newCapacity := CoInt.MAX_VALUE;
                    end else begin
                        newCapacity := newLength + $7f;
                    end;
                end;
                newArray := &Array.newByte1d(newCapacity);
                &Array.copyPrimitives(curArray, 0, newArray, 0, curLength);
                fldArray := newArray;
            end;
            fldLength := newLength;
            result := newArray;
        end;

        constructor ByteArrayOutputStream.create();
        begin
            inherited create();
            fldArray := &Array.newByte1d($7f);
        end;

        constructor ByteArrayOutputStream.create(const aarray: byte_Array1d);
        var
            slength: int;
            capacity: int;
            sarray: byte_Array1d;
        begin
            inherited create();
            slength := length(aarray);
            if slength >= CoInt.MAX_VALUE - $7f then begin
                capacity := CoInt.MAX_VALUE;
            end else begin
                capacity := slength + $7f;
            end;
            sarray := &Array.newByte1d(capacity);
            &Array.copyPrimitives(aarray, 0, sarray, 0, slength);
            fldLength := slength;
            fldPosition := slength;
            fldArray := sarray;
        end;

        constructor ByteArrayOutputStream.create(const aarray: byte_Array1d; length: int);
        var
            alength: int;
            slength: int;
            capacity: int;
            sarray: byte_Array1d;
        begin
            inherited create();
            alength := system.length(aarray);
            if length < 0 then begin
                slength := 0;
            end else
            if length < alength then begin
                slength := length;
            end else begin
                slength := alength;
            end;
            if slength >= CoInt.MAX_VALUE - $7f then begin
                capacity := CoInt.MAX_VALUE;
            end else begin
                capacity := slength + $7f;
            end;
            sarray := &Array.newByte1d(capacity);
            &Array.copyPrimitives(aarray, 0, sarray, 0, slength);
            fldLength := slength;
            fldPosition := slength;
            fldArray := sarray;
        end;

        constructor ByteArrayOutputStream.create(const aarray: byte_Array1d; length, position: int);
        var
            alength: int;
            slength: int;
            capacity: int;
            sarray: byte_Array1d;
        begin
            inherited create();
            alength := system.length(aarray);
            if length < 0 then begin
                slength := 0;
            end else
            if length < alength then begin
                slength := length;
            end else begin
                slength := alength;
            end;
            if slength >= CoInt.MAX_VALUE - $7f then begin
                capacity := CoInt.MAX_VALUE;
            end else begin
                capacity := slength + $7f;
            end;
            sarray := &Array.newByte1d(capacity);
            &Array.copyPrimitives(aarray, 0, sarray, 0, slength);
            fldLength := slength;
            if position < 0 then begin
                fldPosition := 0;
            end else
            if position < slength then begin
                fldPosition := position;
            end else begin
                fldPosition := slength;
            end;
            fldArray := sarray;
        end;

        procedure ByteArrayOutputStream.reset();
        begin
            fldPosition := fldMarked;
        end;

        procedure ByteArrayOutputStream.mark(transferLimit: int);
        begin
            fldMarked := fldPosition;
        end;

        procedure ByteArrayOutputStream.close();
        begin
            destroy;
        end;

        procedure ByteArrayOutputStream.write(byteData: int);
        var
            curLength: int;
            curPosition: int;
            newPosition: int;
            locArray: byte_Array1d;
        begin
            curLength := fldLength;
            curPosition := fldPosition;
            newPosition := curPosition + 1;
            if (newPosition >= 0) and (newPosition <= curLength) then begin
                locArray := fldArray;
            end else begin
                locArray := madeLarger(curLength, newPosition);
            end;
            locArray[curPosition] := byte(byteData);
            fldPosition := newPosition;
        end;

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

        procedure ByteArrayOutputStream.write(const src: byte_Array1d; offset, length: int);
        var
            curLength: int;
            curPosition: int;
            newPosition: int;
            locArray: byte_Array1d;
        begin
            &Array.checkBounds(src, offset, length);
            if length > 0 then begin
                curLength := fldLength;
                curPosition := fldPosition;
                newPosition := curPosition + length;
                if (newPosition >= 0) and (newPosition <= curLength) then begin
                    locArray := fldArray;
                end else begin
                    locArray := madeLarger(curLength, newPosition);
                end;
                &Array.copyPrimitives(src, offset, locArray, curPosition, length);
                fldPosition := newPosition;
            end;
        end;

        procedure ByteArrayOutputStream.flush();
        begin
        end;

        procedure ByteArrayOutputStream.truncate();
        var
            newLength: int;
        begin
            newLength := fldPosition;
            fldLength := newLength;
            if fldMarked > newLength then fldMarked := newLength;
        end;

        function ByteArrayOutputStream.toString(): AnsiString;
        begin
            result := AnsiString.create(fldArray, 0, fldLength);
        end;

        function ByteArrayOutputStream.seek(offset: long; from: SeekFrom): long;
        var
            length: long;
            position: long;
        begin
            length := fldLength;
            case from of
            SeekFrom.sfBegin:
                position := offset;
            SeekFrom.sfEnd:
                position := offset + length;
            SeekFrom.sfCurrent:
                position := offset + fldPosition;
            else
                raise IllegalArgumentException.create(AnsiString.format(AResource.readUnitResourceAsAnsiString(pascalx.lang.UNIT_NAME, 'illegal-argument'), [ CoAnsiString.create('from') ]));
            end;
            if position < 0 then position := 0;
            if position > length then position := length;
            fldPosition := int(position);
            result := position;
        end;

        function ByteArrayOutputStream.position(): long;
        begin
            result := fldPosition;
        end;

        function ByteArrayOutputStream.size(): long;
        begin
            result := fldLength;
        end;

        function ByteArrayOutputStream.available(): long;
        begin
            result := fldLength - fldPosition;
        end;

        function ByteArrayOutputStream.getExtensions(): Extension_Array1d;
        begin
            result := [ self as Extension ];
        end;

        function ByteArrayOutputStream.getExtension(const typ: ShortString): Extension;
        var
            ext: Extension;
        begin
            ext := self;
            if Lang.isInstance(ext, typ) then begin
                result := Extension(Lang.cast(ext, typ));
                exit;
            end;
            result := nil;
        end;

        function ByteArrayOutputStream.toByteArray(): byte_Array1d;
        var
            locLength: int;
            locArray: byte_Array1d;
        begin
            locLength := fldLength;
            locArray := &Array.newByte1d(locLength);
            &Array.copyPrimitives(fldArray, 0, locArray, 0, locLength);
            result := locArray;
        end;
    {%endregion}

    {%region  ByteArrayBidirectStream }
        procedure ByteArrayBidirectStream.setByte(index: int; value: byte);
        var
            writer: ByteArrayBidirectStreamWriter;
        begin
            writer := fldWriter;
            if (index < 0) or (index >= writer.fldLength) then begin
                raise ArrayIndexOutOfBoundsException.create(AResource.readUnitResourceAsAnsiString(pascalx.lang.UNIT_NAME, 'out-of-bounds.array-index'));
            end;
            writer.fldArray[index] := value;
        end;

        function ByteArrayBidirectStream.getByte(index: int): byte;
        var
            writer: ByteArrayBidirectStreamWriter;
        begin
            writer := fldWriter;
            if (index < 0) or (index >= writer.fldLength) then begin
                raise ArrayIndexOutOfBoundsException.create(AResource.readUnitResourceAsAnsiString(pascalx.lang.UNIT_NAME, 'out-of-bounds.array-index'));
            end;
            result := writer.fldArray[index];
        end;

        function ByteArrayBidirectStream.getLength(): int;
        begin
            result := fldWriter.fldLength;
        end;

        function ByteArrayBidirectStream.getArray(): byte_Array1d;
        begin
            result := fldWriter.fldArray;
        end;

        function ByteArrayBidirectStream.getByteArrayReader(): ByteArrayInputStream;
        begin
            result := fldReader;
        end;

        function ByteArrayBidirectStream.getByteArrayWriter(): ByteArrayOutputStream;
        begin
            result := fldWriter;
        end;

        procedure ByteArrayBidirectStream.setReadPosition(newReadPosition: int);
        begin
            fldReader.setPosition(newReadPosition);
        end;

        procedure ByteArrayBidirectStream.setWritePosition(newWritePosition: int);
        begin
            fldWriter.setPosition(newWritePosition);
        end;

        function ByteArrayBidirectStream.getReadPosition(): int;
        begin
            result := fldReader.fldPosition;
        end;

        function ByteArrayBidirectStream.getWritePosition(): int;
        begin
            result := fldWriter.fldPosition;
        end;

        function ByteArrayBidirectStream.createReader(const aarray: byte_Array1d; length, position: int): ByteArrayBidirectStreamReader;
        begin
            result := nil;
        end;

        function ByteArrayBidirectStream.createWriter(const aarray: byte_Array1d; length, position: int): ByteArrayBidirectStreamWriter;
        begin
            result := nil;
        end;

        constructor ByteArrayBidirectStream.create();
        begin
            create(nil, 0, 0, 0);
        end;

        constructor ByteArrayBidirectStream.create(const aarray: byte_Array1d);
        begin
            create(aarray, system.length(aarray), 0, 0);
        end;

        constructor ByteArrayBidirectStream.create(const aarray: byte_Array1d; length: int);
        begin
            create(aarray, length, 0, 0);
        end;

        constructor ByteArrayBidirectStream.create(const aarray: byte_Array1d; length, readPosition, writePosition: int);
        var
            barray: byte_Array1d;
            reader: ByteArrayBidirectStreamReader;
            writer: ByteArrayBidirectStreamWriter;
        begin
            inherited create();
            writer := createWriter(aarray, length, writePosition);
            if writer = nil then writer := ByteArrayBidirectStreamWriter.create(aarray, length, writePosition);
            barray := writer.fldArray;
            length := writer.fldLength;
            reader := createReader(barray, length, readPosition);
            if reader = nil then reader := ByteArrayBidirectStreamReader.create(barray, length, readPosition);
            writer.fldSource := reader;
            fldReader := reader;
            fldWriter := writer;
        end;

        destructor ByteArrayBidirectStream.destroy;
        var
            writer: ByteArrayBidirectStreamWriter;
            reader: ByteArrayBidirectStreamReader;
        begin
            writer := fldWriter;
            reader := fldReader;
            writer.fldCanDestroy := true;
            reader.fldCanDestroy := true;
            writer.free();
            reader.free();
            inherited destroy;
        end;

        procedure ByteArrayBidirectStream.close();
        begin
            destroy;
        end;

        procedure ByteArrayBidirectStream.setData(const aarray: byte_Array1d; length: int);
        var
            alength: int;
        begin
            alength := system.length(aarray);
            if length < 0 then begin
                length := 0;
            end else
            if length >= alength then begin
                length := alength;
            end;
            fldReader.setData(aarray, length);
            fldWriter.setData(aarray, length);
        end;

        function ByteArrayBidirectStream.getExtensions(): Extension_Array1d;
        begin
            result := nil;
        end;

        function ByteArrayBidirectStream.getExtension(const typ: ShortString): Extension;
        begin
            result := nil;
        end;

        function ByteArrayBidirectStream.getReader(): ByteReader;
        begin
            result := fldReader;
        end;

        function ByteArrayBidirectStream.getWriter(): ByteWriter;
        begin
            result := fldWriter;
        end;
    {%endregion}

    {%region  ByteArrayBidirectStreamReader }
        procedure ByteArrayBidirectStreamReader.setData(const newArray: byte_Array1d; newLength: int);
        begin
            fldArray := newArray;
            fldLength := newLength;
            notifyLengthChanged(newLength);
        end;

        procedure ByteArrayBidirectStreamReader.setPosition(newPosition: int);
        var
            length: int;
        begin
            length := fldLength;
            if newPosition < 0 then newPosition := 0;
            if newPosition > length then newPosition := length;
            fldPosition := newPosition;
        end;

        procedure ByteArrayBidirectStreamReader.notifyLengthChanged(newLength: int);
        begin
            if fldPosition > newLength then fldPosition := newLength;
            if fldMarked > newLength then fldMarked := newLength;
        end;

        constructor ByteArrayBidirectStreamReader.create(const aarray: byte_Array1d; length, position: int);
        begin
            inherited create(aarray, length, position);
        end;

        procedure ByteArrayBidirectStreamReader.beforeDestruction();
        begin
            if not fldCanDestroy then begin
                raise InvalidPointerError.create(AResource.readUnitResourceAsAnsiString(pascalx.lang.UNIT_NAME, '!error.invalid-pointer'));
            end;
        end;

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

    {%region  ByteArrayBidirectStreamWriter }
        procedure ByteArrayBidirectStreamWriter.setData(const newArray: byte_Array1d; newLength: int);
        begin
            fldArray := newArray;
            fldLength := newLength;
            notifyLengthChanged(newLength);
        end;

        procedure ByteArrayBidirectStreamWriter.setPosition(newPosition: int);
        var
            length: int;
        begin
            length := fldLength;
            if newPosition < 0 then newPosition := 0;
            if newPosition > length then newPosition := length;
            fldPosition := newPosition;
        end;

        procedure ByteArrayBidirectStreamWriter.notifyLengthChanged(newLength: int);
        begin
            if fldPosition > newLength then fldPosition := newLength;
            if fldMarked > newLength then fldMarked := newLength;
        end;

        function ByteArrayBidirectStreamWriter.madeLarger(curLength, newLength: int): byte_Array1d;
        var
            newArray: byte_Array1d;
            source: ByteArrayBidirectStreamReader;
        begin
            newArray := inherited madeLarger(curLength, newLength);
            source := fldSource;
            source.fldArray := newArray;
            source.fldLength := newLength;
            result := newArray;
        end;

        constructor ByteArrayBidirectStreamWriter.create(const aarray: byte_Array1d; length, position: int);
        begin
            inherited create(aarray, length, position);
        end;

        procedure ByteArrayBidirectStreamWriter.beforeDestruction();
        begin
            if not fldCanDestroy then begin
                raise InvalidPointerError.create(AResource.readUnitResourceAsAnsiString(pascalx.lang.UNIT_NAME, '!error.invalid-pointer'));
            end;
        end;

        procedure ByteArrayBidirectStreamWriter.close();
        begin
        end;

        procedure ByteArrayBidirectStreamWriter.truncate();
        var
            newLength: int;
        begin
            newLength := fldPosition;
            fldLength := newLength;
            self.notifyLengthChanged(newLength);
            fldSource.notifyLengthChanged(newLength);
        end;
    {%endregion}

end.