{
IOStreams содержит классы для создания потоков ввода-вывода.
Copyright © 2016, 2019, 2022–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять её и/или
изменять её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она может быть полезна,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
}
unit IOStreams;
{$MODE DELPHI}
interface
uses
Lang;
{%region public }
const
INPUT_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1503}';
DATA_INPUT_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1504}';
OUTPUT_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1505}';
DATA_OUTPUT_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1506}';
type
Input = interface;
DataInput = interface;
Output = interface;
DataOutput = interface;
IOException = class;
EOFException = class;
UTFDataFormatException = class;
InputStream = class;
OutputStream = class;
DataInputStream = class;
DataOutputStream = class;
InputOutputStream = class;
ByteArrayInputStream = class;
ByteArrayOutputStream = class;
ByteArrayStream = class;
Input = interface(_Interface) [INPUT_GUID]
function seekSupported(): boolean;
function size(): long;
function position(): long;
function available(): long;
function seek(delta: long): long;
function read(const dst: byte_Array1d; offset, length: int): int; overload;
function read(const dst: byte_Array1d): int; overload;
function read(): int; overload;
end;
DataInput = interface(Input) [DATA_INPUT_GUID]
function readBoolean(): boolean;
function readByte(): int;
function readShort(): int;
function readShortLE(): int;
function readInt(): int;
function readIntLE(): int;
function readLong(): long;
function readLongLE(): long;
function readFloat(): real;
function readFloatLE(): real;
function readDouble(): real;
function readDoubleLE(): real;
function readReal(): real;
function readRealLE(): real;
function readUnsignedByte(): int;
function readUnsignedShort(): int;
function readUnsignedShortLE(): int;
function readChar(): wchar;
function readCharLE(): wchar;
function readUTF(): UnicodeString;
function readExtUTF(): UnicodeString;
procedure readFully(const dst: byte_Array1d); overload;
procedure readFully(const dst: byte_Array1d; offset, length: int); overload;
procedure skipBytes(count: int);
end;
Output = interface(_Interface) [OUTPUT_GUID]
function write(const src: byte_Array1d; offset, length: int): int; overload;
function write(const src: byte_Array1d): int; overload;
function write(value: int): boolean; overload;
end;
DataOutput = interface(Output) [DATA_OUTPUT_GUID]
procedure writeBoolean(a: boolean);
procedure writeByte(a: int);
procedure writeShort(a: int);
procedure writeShortLE(a: int);
procedure writeInt(a: int);
procedure writeIntLE(a: int);
procedure writeLong(a: long);
procedure writeLongLE(a: long);
procedure writeFloat(a: real);
procedure writeFloatLE(a: real);
procedure writeDouble(a: real);
procedure writeDoubleLE(a: real);
procedure writeReal(a: real);
procedure writeRealLE(a: real);
procedure writeChar(a: wchar);
procedure writeCharLE(a: wchar);
procedure writeChars(const s: AnsiString);
procedure writeUTF(const s: UnicodeString);
procedure writeExtUTF(const s: UnicodeString);
procedure writeFully(const src: byte_Array1d); overload;
procedure writeFully(const src: byte_Array1d; offset, length: int); overload;
end;
IOException = class(Exception)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
EOFException = class(IOException)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
UTFDataFormatException = class(IOException)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
InputStream = class(RefCountInterfacedObject, Input)
public
constructor create();
function seekSupported(): boolean; virtual;
function size(): long; virtual; abstract;
function position(): long; virtual; abstract;
function available(): long; virtual;
function seek(delta: long): long; virtual;
function read(const dst: byte_Array1d; offset, length: int): int; overload; virtual;
function read(const dst: byte_Array1d): int; overload; virtual;
function read(): int; overload; virtual; abstract;
end;
OutputStream = class(RefCountInterfacedObject, Output)
public
constructor create();
function write(const src: byte_Array1d; offset, length: int): int; overload; virtual;
function write(const src: byte_Array1d): int; overload; virtual;
function write(value: int): boolean; overload; virtual; abstract;
end;
DataInputStream = class(InputStream, DataInput)
strict private
buffer: byte_Array1d;
protected
stream: Input;
public
constructor create(stream: Input);
function seekSupported(): boolean; override;
function size(): long; override;
function position(): long; override;
function available(): long; override;
function seek(delta: long): long; override;
function read(const dst: byte_Array1d; offset, length: int): int; overload; override;
function read(const dst: byte_Array1d): int; overload; override;
function read(): int; overload; override;
function readBoolean(): boolean;
function readByte(): int;
function readShort(): int;
function readShortLE(): int;
function readInt(): int;
function readIntLE(): int;
function readLong(): long;
function readLongLE(): long;
function readFloat(): real;
function readFloatLE(): real;
function readDouble(): real;
function readDoubleLE(): real;
function readReal(): real;
function readRealLE(): real;
function readUnsignedByte(): int;
function readUnsignedShort(): int;
function readUnsignedShortLE(): int;
function readChar(): wchar;
function readCharLE(): wchar;
function readUTF(): UnicodeString;
function readExtUTF(): UnicodeString;
procedure readFully(const dst: byte_Array1d); overload;
procedure readFully(const dst: byte_Array1d; offset, length: int); overload;
procedure skipBytes(count: int);
end;
DataOutputStream = class(OutputStream, DataOutput)
protected
stream: Output;
public
constructor create(stream: Output);
function write(const src: byte_Array1d; offset, length: int): int; overload; override;
function write(const src: byte_Array1d): int; overload; override;
function write(value: int): boolean; overload; override;
procedure writeBoolean(a: boolean);
procedure writeByte(a: int);
procedure writeShort(a: int);
procedure writeShortLE(a: int);
procedure writeInt(a: int);
procedure writeIntLE(a: int);
procedure writeLong(a: long);
procedure writeLongLE(a: long);
procedure writeFloat(a: real);
procedure writeFloatLE(a: real);
procedure writeDouble(a: real);
procedure writeDoubleLE(a: real);
procedure writeReal(a: real);
procedure writeRealLE(a: real);
procedure writeChar(a: wchar);
procedure writeCharLE(a: wchar);
procedure writeChars(const s: AnsiString);
procedure writeUTF(const s: UnicodeString);
procedure writeExtUTF(const s: UnicodeString);
procedure writeFully(const src: byte_Array1d); overload;
procedure writeFully(const src: byte_Array1d; offset, length: int); overload;
end;
InputOutputStream = class(RefCountInterfacedObject, Input, Output)
public
constructor create();
{ Input }
function seekSupported(): boolean; virtual;
function size(): long; virtual; abstract;
function position(): long; virtual; abstract;
function available(): long; virtual;
function seek(delta: long): long; virtual;
function read(const dst: byte_Array1d; offset, length: int): int; overload; virtual;
function read(const dst: byte_Array1d): int; overload; virtual;
function read(): int; overload; virtual; abstract;
{ Output }
function write(const src: byte_Array1d; offset, length: int): int; overload; virtual;
function write(const src: byte_Array1d): int; overload; virtual;
function write(value: int): boolean; overload; virtual; abstract;
{ Собственные методы }
function truncate(): long; virtual; abstract;
function getDataInput(): DataInput;
function getDataOutput(): DataOutput;
end;
ByteArrayInputStream = class(InputStream)
protected
start: int;
count: int;
pos: int;
buf: byte_Array1d;
public
constructor create(const buf: byte_Array1d); overload;
constructor create(const buf: byte_Array1d; offset, length: int); overload;
function seekSupported(): boolean; override;
function size(): long; override;
function position(): long; override;
function available(): long; override;
function seek(delta: long): long; override;
function read(const dst: byte_Array1d; offset, length: int): int; overload; override;
function read(): int; overload; override;
end;
ByteArrayOutputStream = class(OutputStream)
protected
count: int;
buf: byte_Array1d;
public
constructor create(); overload;
function write(const src: byte_Array1d; offset, length: int): int; overload; override;
function write(value: int): boolean; overload; override;
function toByteArray(): byte_Array1d; virtual;
end;
ByteArrayStream = class(InputOutputStream)
protected
count: int;
pos: int;
buf: byte_Array1d;
public
constructor create(); overload;
constructor create(const buf: byte_Array1d; count: int); overload;
function seekSupported(): boolean; override;
function size(): long; override;
function position(): long; override;
function available(): long; override;
function seek(delta: long): long; override;
function read(const dst: byte_Array1d; offset, length: int): int; overload; override;
function read(): int; overload; override;
function write(const src: byte_Array1d; offset, length: int): int; overload; override;
function write(value: int): boolean; overload; override;
function truncate(): long; override;
function toByteArray(): byte_Array1d; virtual;
end;
{%endregion}
{%region routine }
procedure copyBytes(inputStream: Input; outputStream: Output; bytesCount: long);
function readUTF(input: DataInput): UnicodeString;
function readExtUTF(input: DataInput): UnicodeString;
function writeUTF(output: DataOutput; const s: UnicodeString): int;
function writeExtUTF(output: DataOutput; const s: UnicodeString): int;
{%endregion}
implementation
{%region routine }
function readUTFchars(input: DataInput; length: int): UnicodeString;
var
strlen: int;
b1: int;
b2: int;
b3: int;
i: int;
src: byte_Array1d;
res: wchar_Array1d;
begin
strlen := 0;
src := byte_Array1d_create(length);
res := wchar_Array1d_create(length);
input.readFully(src);
i := 0;
while i < length do begin
b1 := int(src[i]) and $ff;
case b1 shr 4 of
$00..$07: begin
inc(i);
res[strlen] := wchar(b1);
inc(strlen);
end;
$0c..$0d: begin
inc(i, 2);
if i > length then begin
raise UTFDataFormatException.create('Ошибка в данных, закодированных кодировкой UTF-8.');
end;
b2 := src[i - 1];
if (b2 and $c0) <> $80 then begin
raise UTFDataFormatException.create('Ошибка в данных, закодированных кодировкой UTF-8.');
end;
res[strlen] := wchar(((b1 and $1f) shl 6) or (b2 and $3f));
inc(strlen);
end;
$0e: begin
inc(i, 3);
if i > length then begin
raise UTFDataFormatException.create('Ошибка в данных, закодированных кодировкой UTF-8.');
end;
b2 := src[i - 2];
b3 := src[i - 1];
if ((b2 and $c0) <> $80) or ((b3 and $c0) <> $80) then begin
raise UTFDataFormatException.create('Ошибка в данных, закодированных кодировкой UTF-8.');
end;
res[strlen] := wchar(((b1 and $0f) shl 12) or ((b2 and $3f) shl 6) or (b3 and $3f));
inc(strlen);
end;
else
raise UTFDataFormatException.create('Ошибка в данных, закодированных кодировкой UTF-8.');
end;
end;
result := UnicodeString_create(res, 0, strlen);
end;
function getUTFlength(const s: UnicodeString): int;
var
c: int;
i: int;
begin
result := 0;
for i := System.length(s) downto 1 do begin
c := int(s[i]);
if (c >= $0001) and (c < $0080) then begin
inc(result, 1);
end else
if c < $0800 then begin
inc(result, 2);
end else begin
inc(result, 3);
end;
end;
end;
procedure writeUTFchars(output: DataOutput; length: int; const s: UnicodeString);
var
res: byte_Array1d;
i: int;
j: int;
c: int;
begin
res := byte_Array1d_create(length);
j := 0;
for i := 1 to System.length(s) do begin
c := int(s[i]);
if (c >= $0001) and (c < $0080) then begin
res[j] := byte(c);
inc(j);
end else
if c < $0800 then begin
res[j] := byte($c0 or ((c shr 6) and $1f));
res[j + 1] := byte($80 or (c and $3f));
inc(j, 2);
end else begin
res[j] := byte($e0 or ((c shr 12) and $0f));
res[j + 1] := byte($80 or ((c shr 6) and $3f));
res[j + 2] := byte($80 or (c and $3f));
inc(j, 3);
end;
end;
output.writeFully(res);
end;
procedure copyBytes(inputStream: Input; outputStream: Output; bytesCount: long);
var
buffer: byte_Array1d;
fragment: long;
fragments: long;
remainder: long;
begin
buffer := byte_Array1d_create($10000);
fragments := divLong(bytesCount, System.length(buffer), remainder);
fragment := 0;
while fragment < fragments do begin
inputStream.read(buffer);
outputStream.write(buffer);
inc(fragment);
end;
if int(remainder) > 0 then begin
inputStream.read(buffer, 0, int(remainder));
outputStream.write(buffer, 0, int(remainder));
end;
end;
function readUTF(input: DataInput): UnicodeString;
var
length: int;
begin
length := input.readUnsignedShort();
if length = 0 then begin
result := '';
exit;
end;
result := readUTFchars(input, length);
end;
function readExtUTF(input: DataInput): UnicodeString;
var
length: int;
begin
length := input.readUnsignedShort();
if length = 0 then begin
result := '';
exit;
end;
if (length and $8000) <> 0 then begin
length := ((length and $7fff) shl 16) or input.readUnsignedShort();
if length = 0 then begin
result := '';
exit;
end;
end;
result := readUTFchars(input, length);
end;
function writeUTF(output: DataOutput; const s: UnicodeString): int;
var
length: int;
begin
length := getUTFlength(s);
if length >= $10000 then begin
raise UTFDataFormatException.create('Длина данных, закодированных кодировкой UTF-8, не может превышать 64 КБ.');
end;
output.writeShort(length);
writeUTFchars(output, length, s);
result := length + 2;
end;
function writeExtUTF(output: DataOutput; const s: UnicodeString): int;
var
length: int;
begin
length := getUTFlength(s);
if length >= $8000 then begin
output.writeInt(length or int($80000000));
result := length + 4;
end else begin
output.writeShort(length);
result := length + 2;
end;
writeUTFchars(output, length, s);
end;
{%endregion}
{%region IOException }
constructor IOException.create();
begin
inherited create();
end;
constructor IOException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region EOFException }
constructor EOFException.create();
begin
inherited create();
end;
constructor EOFException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region UTFDataFormatException }
constructor UTFDataFormatException.create();
begin
inherited create();
end;
constructor UTFDataFormatException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region InputStream }
constructor InputStream.create();
begin
inherited create();
end;
function InputStream.seekSupported(): boolean;
begin
result := false;
end;
function InputStream.available(): long;
begin
result := size() - position();
end;
function InputStream.seek(delta: long): long;
begin
result := 0;
raise IOException.create('InputStream.seek: класс ' + getClass().getName() + ' не поддерживает метод seek.');
end;
function InputStream.read(const dst: byte_Array1d; offset, length: int): int;
var
lim: int;
len: int;
i: int;
b: int;
begin
lim := offset + length;
len := System.length(dst);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('InputStream.read: индекс элемента массива выходит из диапазона.');
end;
for i := 0 to length - 1 do begin
b := read();
if b >= 0 then begin
dst[offset + i] := byte(b);
end else begin
result := i;
exit;
end;
end;
result := length;
end;
function InputStream.read(const dst: byte_Array1d): int;
begin
result := read(dst, 0, length(dst));
end;
{%endregion}
{%region OutputStream }
constructor OutputStream.create();
begin
inherited create();
end;
function OutputStream.write(const src: byte_Array1d; offset, length: int): int;
var
lim: int;
len: int;
i: int;
begin
lim := offset + length;
len := System.length(src);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('OutputStream.write: индекс элемента массива выходит из диапазона.');
end;
for i := 0 to length - 1 do begin
if not write(src[offset + i]) then begin
result := i;
exit;
end;
end;
result := length;
end;
function OutputStream.write(const src: byte_Array1d): int;
begin
result := write(src, 0, length(src));
end;
{%endregion}
{%region DataInputStream }
constructor DataInputStream.create(stream: Input);
begin
inherited create();
self.stream := stream;
self.buffer := byte_Array1d_create(4);
end;
function DataInputStream.seekSupported(): boolean;
begin
result := stream.seekSupported();
end;
function DataInputStream.size(): long;
begin
result := stream.size();
end;
function DataInputStream.position(): long;
begin
result := stream.position();
end;
function DataInputStream.available(): long;
begin
result := stream.available();
end;
function DataInputStream.seek(delta: long): long;
begin
result := stream.seek(delta);
end;
function DataInputStream.read(const dst: byte_Array1d; offset, length: int): int;
begin
result := stream.read(dst, offset, length);
end;
function DataInputStream.read(const dst: byte_Array1d): int;
begin
result := stream.read(dst);
end;
function DataInputStream.read(): int;
begin
result := stream.read();
end;
function DataInputStream.readBoolean(): boolean;
var
b: int;
begin
b := read();
if b < 0 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
result := b <> 0;
end;
function DataInputStream.readByte(): int;
var
b: int;
begin
b := read();
if b < 0 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
result := byte(b);
end;
function DataInputStream.readShort(): int;
var
b: byte_Array1d;
begin
b := buffer;
if read(b, 0, 2) < 2 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
result := short(((b[0] and $ff) shl 8) or (b[1] and $ff));
end;
function DataInputStream.readShortLE(): int;
var
b: byte_Array1d;
begin
b := buffer;
if read(b, 0, 2) < 2 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
result := short(((b[1] and $ff) shl 8) or (b[0] and $ff));
end;
function DataInputStream.readInt(): int;
var
b: byte_Array1d;
begin
b := buffer;
if read(b, 0, 4) < 4 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
result := ((b[0] and $ff) shl 24) or ((b[1] and $ff) shl 16) or ((b[2] and $ff) shl 8) or (b[3] and $ff);
end;
function DataInputStream.readIntLE(): int;
var
b: byte_Array1d;
begin
b := buffer;
if read(b, 0, 4) < 4 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
result := ((b[3] and $ff) shl 24) or ((b[2] and $ff) shl 16) or ((b[1] and $ff) shl 8) or (b[0] and $ff);
end;
function DataInputStream.readLong(): long;
var
i1: int;
i2: int;
begin
i1 := readInt();
i2 := readInt();
result := buildLong(i2, i1);
end;
function DataInputStream.readLongLE(): long;
var
i1: int;
i2: int;
begin
i1 := readIntLE();
i2 := readIntLE();
result := buildLong(i1, i2);
end;
function DataInputStream.readFloat(): real;
begin
result := toReal(intBitsToFloat(readInt()));
end;
function DataInputStream.readFloatLE(): real;
begin
result := toReal(intBitsToFloat(readIntLE()));
end;
function DataInputStream.readDouble(): real;
begin
result := toReal(longBitsToDouble(readLong()));
end;
function DataInputStream.readDoubleLE(): real;
begin
result := toReal(longBitsToDouble(readLongLE()));
end;
function DataInputStream.readReal(): real;
var
significand: long;
exponentAndSign: int;
begin
exponentAndSign := readUnsignedShort();
significand := readLong();
result := buildReal(exponentAndSign, significand);
end;
function DataInputStream.readRealLE(): real;
var
significand: long;
exponentAndSign: int;
begin
significand := readLongLE();
exponentAndSign := readUnsignedShortLE();
result := buildReal(exponentAndSign, significand);
end;
function DataInputStream.readUnsignedByte(): int;
var
b: int;
begin
b := read();
if b < 0 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
result := b;
end;
function DataInputStream.readUnsignedShort(): int;
var
b1: int;
b2: int;
begin
b1 := read();
b2 := read();
if (b1 or b2) < 0 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
result := (b1 shl 8) or b2;
end;
function DataInputStream.readUnsignedShortLE(): int;
var
b1: int;
b2: int;
begin
b1 := read();
b2 := read();
if (b1 or b2) < 0 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
result := (b2 shl 8) or b1;
end;
function DataInputStream.readChar(): wchar;
begin
result := wchar(readUnsignedShort());
end;
function DataInputStream.readCharLE(): wchar;
begin
result := wchar(readUnsignedShortLE());
end;
function DataInputStream.readUTF(): UnicodeString;
begin
result := IOStreams.readUTF(self);
end;
function DataInputStream.readExtUTF(): UnicodeString;
begin
result := IOStreams.readExtUTF(self);
end;
procedure DataInputStream.readFully(const dst: byte_Array1d);
begin
readFully(dst, 0, length(dst));
end;
procedure DataInputStream.readFully(const dst: byte_Array1d; offset, length: int);
var
lim: int;
len: int;
c: int;
n: int;
begin
lim := offset + length;
len := System.length(dst);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('DataInputStream.readFully: индекс элемента массива выходит из диапазона.');
end;
n := 0;
while n < length do begin
c := read(dst, offset + n, length - n);
if c < 0 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
inc(n, c);
end;
end;
procedure DataInputStream.skipBytes(count: int);
begin
while (count > 0) and (read() >= 0) do begin
dec(count);
end;
if count > 0 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
end;
{%endregion}
{%region DataOutputStream }
constructor DataOutputStream.create(stream: Output);
begin
inherited create();
self.stream := stream;
end;
function DataOutputStream.write(const src: byte_Array1d; offset, length: int): int;
begin
result := stream.write(src, offset, length);
end;
function DataOutputStream.write(const src: byte_Array1d): int;
begin
result := stream.write(src);
end;
function DataOutputStream.write(value: int): boolean;
begin
result := stream.write(value);
end;
procedure DataOutputStream.writeBoolean(a: boolean);
var
v: int;
begin
if a then begin
v := 1;
end else begin
v := 0;
end;
if not write(v) then begin
raise IOException.create('Поток вывода данных: не удалось записать данные.');
end;
end;
procedure DataOutputStream.writeByte(a: int);
begin
if not write(a) then begin
raise IOException.create('Поток вывода данных: не удалось записать данные.');
end;
end;
procedure DataOutputStream.writeShort(a: int);
begin
if not write(a shr 8) or not write(a) then begin
raise IOException.create('Поток вывода данных: не удалось записать данные.');
end;
end;
procedure DataOutputStream.writeShortLE(a: int);
begin
if not write(a) or not write(a shr 8) then begin
raise IOException.create('Поток вывода данных: не удалось записать данные.');
end;
end;
procedure DataOutputStream.writeInt(a: int);
begin
if not write(a shr 24) or not write(a shr 16) or not write(a shr 8) or not write(a) then begin
raise IOException.create('Поток вывода данных: не удалось записать данные.');
end;
end;
procedure DataOutputStream.writeIntLE(a: int);
begin
if not write(a) or not write(a shr 8) or not write(a shr 16) or not write(a shr 24) then begin
raise IOException.create('Поток вывода данных: не удалось записать данные.');
end;
end;
procedure DataOutputStream.writeLong(a: long);
begin
writeInt(LongRecord(a).hi);
writeInt(LongRecord(a).lo);
end;
procedure DataOutputStream.writeLongLE(a: long);
begin
writeIntLE(LongRecord(a).lo);
writeIntLE(LongRecord(a).hi);
end;
procedure DataOutputStream.writeFloat(a: real);
begin
writeInt(floatToIntBits(toFloat(a)));
end;
procedure DataOutputStream.writeFloatLE(a: real);
begin
writeIntLE(floatToIntBits(toFloat(a)));
end;
procedure DataOutputStream.writeDouble(a: real);
begin
writeLong(doubleToLongBits(toDouble(a)));
end;
procedure DataOutputStream.writeDoubleLE(a: real);
begin
writeLongLE(doubleToLongBits(toDouble(a)));
end;
procedure DataOutputStream.writeReal(a: real);
begin
writeShort(extractExponentAndSign(a));
writeLong(extractSignificand(a));
end;
procedure DataOutputStream.writeRealLE(a: real);
begin
writeLongLE(extractSignificand(a));
writeShortLE(extractExponentAndSign(a));
end;
procedure DataOutputStream.writeChar(a: wchar);
begin
writeShort(int(a));
end;
procedure DataOutputStream.writeCharLE(a: wchar);
begin
writeShortLE(int(a));
end;
procedure DataOutputStream.writeChars(const s: AnsiString);
begin
write(stringToByteArray(s));
end;
procedure DataOutputStream.writeUTF(const s: UnicodeString);
begin
IOStreams.writeUTF(self, s);
end;
procedure DataOutputStream.writeExtUTF(const s: UnicodeString);
begin
IOStreams.writeExtUTF(self, s);
end;
procedure DataOutputStream.writeFully(const src: byte_Array1d);
begin
writeFully(src, 0, length(src));
end;
procedure DataOutputStream.writeFully(const src: byte_Array1d; offset, length: int);
var
lim: int;
len: int;
c: int;
n: int;
begin
lim := offset + length;
len := System.length(src);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('DataOutputStream.writeFully: индекс элемента массива выходит из диапазона.');
end;
n := 0;
while n < length do begin
c := write(src, offset + n, length - n);
if c < 0 then begin
raise EOFException.create('Поток ввода данных: достигнут конец данных.');
end;
inc(n, c);
end;
end;
{%endregion}
{%region InputOutputStream }
constructor InputOutputStream.create();
begin
inherited create();
end;
function InputOutputStream.seekSupported(): boolean;
begin
result := false;
end;
function InputOutputStream.available(): long;
begin
result := size() - position();
end;
function InputOutputStream.seek(delta: long): long;
begin
result := 0;
raise IOException.create('InputOutputStream.seek: класс ' + getClass().getName() + ' не поддерживает метод seek.');
end;
function InputOutputStream.read(const dst: byte_Array1d; offset, length: int): int;
var
lim: int;
len: int;
i: int;
b: int;
begin
lim := offset + length;
len := System.length(dst);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('InputOutputStream.read: индекс элемента массива выходит из диапазона.');
end;
for i := 0 to length - 1 do begin
b := read();
if b >= 0 then begin
dst[offset + i] := byte(b);
end else begin
result := i;
exit;
end;
end;
result := length;
end;
function InputOutputStream.read(const dst: byte_Array1d): int;
begin
result := read(dst, 0, length(dst));
end;
function InputOutputStream.write(const src: byte_Array1d; offset, length: int): int;
var
lim: int;
len: int;
i: int;
begin
lim := offset + length;
len := System.length(src);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('InputOutputStream.write: индекс элемента массива выходит из диапазона.');
end;
for i := 0 to length - 1 do begin
if not write(src[offset + i]) then begin
result := i;
exit;
end;
end;
result := length;
end;
function InputOutputStream.write(const src: byte_Array1d): int;
begin
result := write(src, 0, length(src));
end;
function InputOutputStream.getDataInput(): DataInput;
begin
result := DataInputStream.create(self);
end;
function InputOutputStream.getDataOutput(): DataOutput;
begin
result := DataOutputStream.create(self);
end;
{%endregion}
{%region ByteArrayInputStream }
constructor ByteArrayInputStream.create(const buf: byte_Array1d);
begin
create(buf, 0, length(buf));
end;
constructor ByteArrayInputStream.create(const buf: byte_Array1d; offset, length: int);
begin
inherited create();
self.start := offset;
self.count := min(offset + length, System.length(buf));
self.pos := offset;
self.buf := buf;
end;
function ByteArrayInputStream.seekSupported(): boolean;
begin
result := true;
end;
function ByteArrayInputStream.size(): long;
begin
result := long(count) - long(start);
end;
function ByteArrayInputStream.position(): long;
begin
result := long(pos) - long(start);
end;
function ByteArrayInputStream.available(): long;
begin
result := long(count) - long(pos);
end;
function ByteArrayInputStream.seek(delta: long): long;
var
s: long;
p: long;
begin
s := start;
p := max(s, min(long(pos) + delta, long(count)));
pos := int(p);
result := p - s;
end;
function ByteArrayInputStream.read(const dst: byte_Array1d; offset, length: int): int;
var
lim: int;
len: int;
p: int;
begin
lim := offset + length;
len := System.length(dst);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('ByteArrayInputStream.read: индекс элемента массива выходит из диапазона.');
end;
p := pos;
result := min(count - p, length);
arraycopy(buf, p, dst, offset, result);
pos := p + result;
end;
function ByteArrayInputStream.read(): int;
var
p: int;
begin
p := pos;
if p < count then begin
result := int(buf[p]) and $ff;
pos := p + 1;
end else begin
result := -1;
end;
end;
{%endregion}
{%region ByteArrayOutputStream }
constructor ByteArrayOutputStream.create();
begin
inherited create();
count := 0;
buf := byte_Array1d_create(16);
end;
function ByteArrayOutputStream.write(const src: byte_Array1d; offset, length: int): int;
var
lim: int;
len: int;
cap: int;
nc: int;
c: int;
b: byte_Array1d;
t: byte_Array1d;
begin
lim := offset + length;
len := System.length(src);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('InputOutputStream.write: индекс элемента массива выходит из диапазона.');
end;
b := buf;
c := count;
nc := c + length;
cap := System.length(b);
if nc > cap then begin
t := byte_Array1d_create(max(cap shl 1, nc));
arraycopy(b, 0, t, 0, c);
b := t;
buf := t;
end;
arraycopy(src, offset, b, c, length);
count := nc;
result := length;
end;
function ByteArrayOutputStream.write(value: int): boolean;
var
cap: int;
nc: int;
c: int;
b: byte_Array1d;
t: byte_Array1d;
begin
b := buf;
c := count;
nc := c + 1;
cap := System.length(b);
if nc > cap then begin
t := byte_Array1d_create(max(cap shl 1, nc));
arraycopy(b, 0, t, 0, c);
b := t;
buf := t;
end;
b[c] := byte(value);
count := nc;
result := true;
end;
function ByteArrayOutputStream.toByteArray(): byte_Array1d;
var
c: int;
b: byte_Array1d;
begin
b := buf;
c := count;
if c <> System.length(b) then begin
result := byte_Array1d_create(c);
arraycopy(b, 0, result, 0, c);
end else begin
result := b;
end;
end;
{%endregion}
{%region ByteArrayStream }
constructor ByteArrayStream.create();
begin
inherited create();
self.buf := byte_Array1d_create(16);
end;
constructor ByteArrayStream.create(const buf: byte_Array1d; count: int);
begin
inherited create();
self.count := min(count, System.length(buf));
self.buf := buf;
end;
function ByteArrayStream.seekSupported(): boolean;
begin
result := true;
end;
function ByteArrayStream.size(): long;
begin
result := long(count);
end;
function ByteArrayStream.position(): long;
begin
result := long(pos);
end;
function ByteArrayStream.available(): long;
begin
result := long(count) - long(pos);
end;
function ByteArrayStream.seek(delta: long): long;
begin
result := max(0, min(long(pos) + delta, long(count)));
pos := int(result);
end;
function ByteArrayStream.read(const dst: byte_Array1d; offset, length: int): int;
var
lim: int;
len: int;
p: int;
begin
lim := offset + length;
len := System.length(dst);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('ByteArrayStream.read: индекс элемента массива выходит из диапазона.');
end;
p := pos;
result := min(count - p, length);
arraycopy(buf, p, dst, offset, result);
pos := p + result;
end;
function ByteArrayStream.read(): int;
var
p: int;
begin
p := pos;
if p < count then begin
result := int(buf[p]) and $ff;
pos := p + 1;
end else begin
result := -1;
end;
end;
function ByteArrayStream.write(const src: byte_Array1d; offset, length: int): int;
var
lim: int;
len: int;
cap: int;
nc: int;
c: int;
b: byte_Array1d;
t: byte_Array1d;
begin
lim := offset + length;
len := System.length(src);
if (lim > len) or (lim < offset) or (offset < 0) or (offset > len) then begin
raise ArrayIndexOutOfBoundsException.create('ByteArrayStream.write: индекс элемента массива выходит из диапазона.');
end;
b := buf;
c := count;
nc := c + length;
cap := System.length(b);
if nc > cap then begin
t := byte_Array1d_create(max(cap shl 1, nc));
arraycopy(b, 0, t, 0, c);
b := t;
buf := t;
end;
arraycopy(src, offset, b, c, length);
count := nc;
result := length;
end;
function ByteArrayStream.write(value: int): boolean;
var
cap: int;
nc: int;
c: int;
b: byte_Array1d;
t: byte_Array1d;
begin
b := buf;
c := count;
nc := c + 1;
cap := System.length(b);
if nc > cap then begin
t := byte_Array1d_create(max(cap shl 1, nc));
arraycopy(b, 0, t, 0, c);
b := t;
buf := t;
end;
b[c] := byte(value);
count := nc;
result := true;
end;
function ByteArrayStream.truncate(): long;
begin
result := long(pos);
count := int(result);
end;
function ByteArrayStream.toByteArray(): byte_Array1d;
var
c: int;
b: byte_Array1d;
begin
b := buf;
c := count;
if c <> System.length(b) then begin
result := byte_Array1d_create(c);
arraycopy(b, 0, result, 0, c);
end else begin
result := b;
end;
end;
{%endregion}
end.