{
pascalx.io — основной модуль для разработки классов ввода-вывода.
Copyright © 2021, 2026 Малик Разработчик
Это свободная программа: вы можете перераспространять её и/или изменять
её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
}
unit pascalx.io;
{$MODE OBJFPC}
interface
{%region} uses
{$IFDEF WINDOWS}
windows,
{$ENDIF}
pascalx.lang;
{%endregion}
{$TYPEINFO ON}
{$CALLING REGISTER}
const UNIT_NAME = 'pascalx.io';
{%region} type
Extension = interface;
Extendable = interface;
ByteReader = interface;
ByteWriter = interface;
ByteStream = interface;
UCharReader = interface;
UCharWriter = interface;
UCharStream = interface;
DataInput = interface;
DataOutput = interface;
DataInputStream = class;
DataOutputStream = class;
UCharInputStream = class;
UCharOutputStream = class;
PrintStream = class;
UResource = class;
SResource = class;
IOException = class;
EndOfStreamException = class;
EndOfFreeSpaceException = class;
InvalidDataFormatException = class;
MalformedLineSeparatorException = class;
UTFDataFormatException = class;
{ Extension[] } Extension_Array1d = specialize DynamicArray<Extension>;
Extension = interface(RawInterface) ['{C3512B0A-CC07-4A37-9514-C955A8359B10}']
end;
Extendable = interface(RawInterface) ['{C3512B0A-CC07-4A37-9514-C955A8359B11}']
function getExtensions(): Extension_Array1d;
function getExtension(const typ: ShortString): Extension;
end;
ByteReader = interface(Extendable) ['{C3512B0A-CC07-4A37-9514-C955A8359B12}']
procedure close();
function read(): int;
function read(const dst: byte_Array1d): int;
function read(const dst: byte_Array1d; offset, length: int): int;
function skip(bytesQuantity: long): long;
end;
ByteWriter = interface(Extendable) ['{C3512B0A-CC07-4A37-9514-C955A8359B13}']
procedure close();
procedure write(byteData: int);
procedure write(const src: byte_Array1d);
procedure write(const src: byte_Array1d; offset, length: int);
procedure flush();
end;
ByteStream = interface(Extendable) ['{C3512B0A-CC07-4A37-9514-C955A8359B14}']
procedure close();
function getReader(): ByteReader;
function getWriter(): ByteWriter;
property reader: ByteReader read getReader;
property writer: ByteWriter read getWriter;
end;
UCharReader = interface(Extendable) ['{C3512B0A-CC07-4A37-9514-C955A8359B15}']
procedure close();
function read(): int;
function read(const dst: uchar_Array1d): int;
function read(const dst: uchar_Array1d; offset, length: int): int;
function skip(ucharsQuantity: long): long;
end;
UCharWriter = interface(Extendable) ['{C3512B0A-CC07-4A37-9514-C955A8359B16}']
procedure close();
procedure write(ucharData: int);
procedure write(const src: uchar_Array1d);
procedure write(const src: uchar_Array1d; offset, length: int);
procedure flush();
end;
UCharStream = interface(Extendable) ['{C3512B0A-CC07-4A37-9514-C955A8359B17}']
procedure close();
function getReader(): UCharReader;
function getWriter(): UCharWriter;
property reader: UCharReader read getReader;
property writer: UCharWriter read getWriter;
end;
DataInput = interface(RawInterface) ['{C3512B0A-CC07-4A37-9514-C955A8359B18}']
procedure readFully(const dst: byte_Array1d);
procedure readFully(const dst: byte_Array1d; offset, length: int);
function readBoolean(): boolean;
function readChar(): char;
function readUChar(): uchar;
function readUnsignedByte(): int;
function readUnsignedShort(): int;
function readByte(): int;
function readShort(): int;
function readInt(): int;
function readLong(): long;
function readFloat(): float;
function readDouble(): double;
function readReal(): real;
function readUTF(): UnicodeString;
function readln(): UnicodeString;
function read(): UnicodeString;
end;
DataOutput = interface(RawInterface) ['{C3512B0A-CC07-4A37-9514-C955A8359B19}']
procedure write(const src: byte_Array1d);
procedure write(const src: byte_Array1d; offset, length: int);
procedure writeBoolean(const data: boolean);
procedure writeChar(const data: char);
procedure writeUChar(const data: uchar);
procedure writeByte(const data: int);
procedure writeShort(const data: int);
procedure writeInt(const data: int);
procedure writeLong(const data: long);
procedure writeFloat(const data: float);
procedure writeDouble(const data: double);
procedure writeReal(const data: real);
procedure writeUTF(const data: UnicodeString);
procedure writeln(const data: UnicodeString);
procedure write(const data: UnicodeString);
end;
DataInputStream = class sealed(&Object, ByteReader, Extendable)
private
fldCharsetName: AnsiString;
fldReader: ByteReader;
fldBigEndianDataInputAsInterface: DataInput;
fldBigEndianDataInputAsObject: &Object; { BigEndianDataInput }
fldLittleEndianDataInputAsInterface: DataInput;
fldLittleEndianDataInputAsObject: &Object; { LittleEndianDataInput }
procedure setCharsetName(const newCharsetName: AnsiString);
public
constructor create(reader: ByteReader);
constructor create(reader: ByteReader; const charsetName: AnsiString);
destructor destroy; override;
procedure close();
function read(): int;
function read(const dst: byte_Array1d): int;
function read(const dst: byte_Array1d; offset, length: int): int;
function skip(bytesQuantity: long): long;
function getExtensions(): Extension_Array1d;
function getExtension(const typ: ShortString): Extension;
published
property charsetName: AnsiString read fldCharsetName write setCharsetName;
property reader: ByteReader read fldReader;
property bigEndianDataInput: DataInput read fldBigEndianDataInputAsInterface;
property littleEndianDataInput: DataInput read fldLittleEndianDataInputAsInterface;
end;
DataOutputStream = class sealed(&Object, ByteWriter, Extendable)
private
fldCharsetName: AnsiString;
fldWriter: ByteWriter;
fldBigEndianDataOutputAsInterface: DataOutput;
fldBigEndianDataOutputAsObject: &Object; { BigEndianDataOutput }
fldLittleEndianDataOutputAsInterface: DataOutput;
fldLittleEndianDataOutputAsObject: &Object; { LittleEndianDataOutput }
procedure setCharsetName(const newCharsetName: AnsiString);
public
constructor create(writer: ByteWriter);
constructor create(writer: ByteWriter; const charsetName: AnsiString);
destructor destroy; override;
procedure close();
procedure write(byteData: int);
procedure write(const src: byte_Array1d);
procedure write(const src: byte_Array1d; offset, length: int);
procedure flush();
function getExtensions(): Extension_Array1d;
function getExtension(const typ: ShortString): Extension;
published
property charsetName: AnsiString read fldCharsetName write setCharsetName;
property writer: ByteWriter read fldWriter;
property bigEndianDataOutput: DataOutput read fldBigEndianDataOutputAsInterface;
property littleEndianDataOutput: DataOutput read fldLittleEndianDataOutputAsInterface;
end;
UCharInputStream = class sealed(&Object, UCharReader, Extendable)
private
fldCharsetName: AnsiString;
fldReader: ByteReader;
fldDecoderRef: &Object; { CharDecoder }
fldMarkExtension: &Object; { UCharInputStreamMarkExtension }
fldStreamedExtension: &Object; { UCharInputStreamStreamedExtension }
procedure setCharsetName(const newCharsetName: AnsiString);
function readChars(length: int): &Object; { CharactersBuffer }
public
constructor create(reader: ByteReader);
constructor create(reader: ByteReader; const charsetName: AnsiString);
destructor destroy; override;
procedure close();
function read(): int;
function read(const dst: uchar_Array1d): int;
function read(const dst: uchar_Array1d; offset, length: int): int;
function skip(ucharsQuantity: long): long;
function getExtensions(): Extension_Array1d;
function getExtension(const typ: ShortString): Extension;
published
property charsetName: AnsiString read fldCharsetName write setCharsetName;
property reader: ByteReader read fldReader;
end;
UCharOutputStream = class sealed(&Object, UCharWriter, Extendable)
private
fldCharsetName: AnsiString;
fldWriter: ByteWriter;
fldEncoderRef: &Object; { CharEncoder }
procedure setCharsetName(const newCharsetName: AnsiString);
public
constructor create(writer: ByteWriter);
constructor create(writer: ByteWriter; const charsetName: AnsiString);
destructor destroy; override;
procedure close();
procedure write(ucharData: int);
procedure write(const src: uchar_Array1d);
procedure write(const src: uchar_Array1d; offset, length: int);
procedure flush();
function getExtensions(): Extension_Array1d;
function getExtension(const typ: ShortString): Extension;
published
property charsetName: AnsiString read fldCharsetName write setCharsetName;
property writer: ByteWriter read fldWriter;
end;
PrintStream = class(&Object, ByteWriter, Extendable)
private
fldError: boolean;
fldCharsetName: AnsiString;
fldWriter: ByteWriter;
fldEncoderRef: &Object; { CharEncoder }
procedure write(const src: AnsiString);
procedure write(const src: UnicodeString);
procedure setCharsetName(const newCharsetName: AnsiString);
function setError(newError: boolean): boolean;
protected
procedure errorSet(); virtual;
procedure errorCleared(); virtual;
procedure error();
public
constructor create(writer: ByteWriter);
constructor create(writer: ByteWriter; const charsetName: AnsiString);
destructor destroy; override;
procedure close(); virtual;
procedure write(byteData: int); virtual;
procedure write(const src: byte_Array1d); virtual;
procedure write(const src: byte_Array1d; offset, length: int); virtual;
procedure flush(); virtual;
procedure print(const src: boolean); virtual;
procedure print(const src: int); virtual;
procedure print(const src: long); virtual;
procedure print(const src: float); virtual;
procedure print(const src: double); virtual;
procedure print(const src: real); virtual;
procedure print(const src: AnsiString); virtual;
procedure print(const src: UnicodeString); virtual;
procedure print(const src: TObject); virtual;
procedure print(const src: uchar_Array1d; offset, length: int); virtual;
procedure printf(const form: AnsiString; const data: array of Value); virtual;
procedure printf(const form: UnicodeString; const data: array of Value); virtual;
procedure println(); virtual;
procedure println(const src: boolean); virtual;
procedure println(const src: int); virtual;
procedure println(const src: long); virtual;
procedure println(const src: float); virtual;
procedure println(const src: double); virtual;
procedure println(const src: real); virtual;
procedure println(const src: AnsiString); virtual;
procedure println(const src: UnicodeString); virtual;
procedure println(const src: TObject); virtual;
procedure println(const src: uchar_Array1d; offset, length: int); virtual;
procedure printlnf(const form: AnsiString; const data: array of Value); virtual;
procedure printlnf(const form: UnicodeString; const data: array of Value); virtual;
function getExtensions(): Extension_Array1d; virtual;
function getExtension(const typ: ShortString): Extension; virtual;
function isError(): boolean;
published
property charsetName: AnsiString read fldCharsetName write setCharsetName;
property writer: ByteWriter read fldWriter;
end;
UResource = class sealed
public
class function readResourceAsUnicodeString(const rsrcName: AnsiString): UnicodeString; static;
class function readResourceAsUnicodeString(const rsrcName, charsetName: AnsiString): UnicodeString; static;
class function readUnitResourceAsUnicodeString(const __unitName, rstrName: AnsiString): UnicodeString; static;
class function readUnitResourceAsUnicodeString(const __unitName, rstrName, charsetName: AnsiString): UnicodeString; static;
end;
SResource = class sealed
public
class function isResourceExists(const rsrcName: AnsiString): boolean; static;
class function isUnitResourceExists(const __unitName, rsrcName: AnsiString): boolean; static;
class function openResourceAsStream(const rsrcName: AnsiString): ByteReader; static;
class function openUnitResourceAsStream(const __unitName, rsrcName: AnsiString): ByteReader; static;
end;
IOException = class(Exception);
EndOfStreamException = class(IOException);
EndOfFreeSpaceException = class(IOException);
InvalidDataFormatException = class(IOException);
MalformedLineSeparatorException = class(InvalidDataFormatException);
UTFDataFormatException = class(InvalidDataFormatException);
{%endregion}
implementation
{%region} uses
pascalx.io.charset,
pascalx.io.extension;
{%endregion}
{$R *.res}
{$WARN 7046 OFF} { позволить инструкции вида mov rsi, [rsi+offset <поле>] для чтения поля объекта }
{$ASMMODE INTEL}
{$TYPEINFO OFF}
{$CALLING REGISTER}
{%region} type
ResourceStream = class;
LittleEndianDataInput = class;
BigEndianDataInput = class;
LittleEndianDataOutput = class;
BigEndianDataOutput = class;
UCharInputStreamMarkExtension = class;
UCharInputStreamStreamedExtension = class;
ResourceStream = class(&Object, Extension, MarkExtension, ByteReader, SeekExtension, LimitedSizeExtension, Extendable)
private type
PByte = ^byte;
private
fldMarked: int;
fldLength: int;
fldPosition: int;
fldHandle: long;
fldData: PByte;
public
constructor create(handle: long; data: Pointer; length: int);
procedure reset();
procedure mark(transferLimit: int);
procedure close();
function read(): int;
function read(const dst: byte_Array1d): int;
function read(const dst: byte_Array1d; offset, length: int): int;
function skip(bytesQuantity: long): long;
function seek(offset: long; from: SeekFrom): long;
function position(): long;
function size(): long;
function available(): long;
function getExtensions(): Extension_Array1d;
function getExtension(const typ: ShortString): Extension;
end;
LittleEndianDataInput = class(&Object, DataInput)
protected
fldData: byte_Array1d;
fldReader: ByteReader;
fldCharsetRef: Charset;
procedure readData(length: int); virtual;
public
constructor create(reader: ByteReader; const data: byte_Array1d);
procedure readFully(const dst: byte_Array1d);
procedure readFully(const dst: byte_Array1d; offset, length: int);
function readBoolean(): boolean;
function readChar(): char;
function readUChar(): uchar;
function readUnsignedByte(): int;
function readUnsignedShort(): int;
function readByte(): int;
function readShort(): int;
function readInt(): int;
function readLong(): long;
function readFloat(): float;
function readDouble(): double;
function readReal(): real;
function readUTF(): UnicodeString;
function readln(): UnicodeString;
function read(): UnicodeString;
end;
BigEndianDataInput = class(LittleEndianDataInput)
protected
procedure readData(length: int); override;
end;
LittleEndianDataOutput = class(&Object, DataOutput)
protected
fldData: byte_Array1d;
fldWriter: ByteWriter;
fldCharsetRef: Charset;
procedure writeData(length: int); virtual;
public
constructor create(writer: ByteWriter; const data: byte_Array1d);
procedure write(const src: byte_Array1d);
procedure write(const src: byte_Array1d; offset, length: int);
procedure writeBoolean(const data: boolean);
procedure writeChar(const data: char);
procedure writeUChar(const data: uchar);
procedure writeByte(const data: int);
procedure writeShort(const data: int);
procedure writeInt(const data: int);
procedure writeLong(const data: long);
procedure writeFloat(const data: float);
procedure writeDouble(const data: double);
procedure writeReal(const data: real);
procedure writeUTF(const data: UnicodeString);
procedure writeln(const data: UnicodeString);
procedure write(const data: UnicodeString);
end;
BigEndianDataOutput = class(LittleEndianDataOutput)
protected
procedure writeData(length: int); override;
end;
UCharInputStreamMarkExtension = class(&Object, Extension, MarkExtension)
private
fldMarkExtension: MarkExtension;
public
constructor create(ext: MarkExtension);
procedure reset();
procedure mark(transferLimit: int);
end;
UCharInputStreamStreamedExtension = class(&Object, Extension, StreamedExtension)
private
fldCharactersReaded: int;
fldCharactersBuffer: CharactersBuffer;
fldLimitedSizeExtension: LimitedSizeExtension;
public
constructor create(ext: LimitedSizeExtension);
function ready(): boolean;
end;
{%endregion}
{%region DataInputStream }
procedure DataInputStream.setCharsetName(const newCharsetName: AnsiString);
var
useCharsetName: AnsiString;
useCharsetRef: Charset;
begin
try
useCharsetRef := Charset.get(newCharsetName);
useCharsetName := newCharsetName;
except
useCharsetRef := Charset.getDefault();
useCharsetName := useCharsetRef.name;
end;
fldCharsetName := useCharsetName;
pascalx.io.LittleEndianDataInput(fldBigEndianDataInputAsObject).fldCharsetRef := useCharsetRef;
pascalx.io.LittleEndianDataInput(fldLittleEndianDataInputAsObject).fldCharsetRef := useCharsetRef;
end;
constructor DataInputStream.create(reader: ByteReader);
begin
create(reader, 'UTF-8');
end;
constructor DataInputStream.create(reader: ByteReader; const charsetName: AnsiString);
var
useCharsetName: AnsiString;
useCharsetRef: Charset;
useData: byte_Array1d;
useLittleEndianDataInput: pascalx.io.LittleEndianDataInput;
useBigEndianDataInput: pascalx.io.LittleEndianDataInput;
begin
inherited create();
try
useCharsetRef := Charset.get(charsetName);
useCharsetName := charsetName;
except
useCharsetRef := Charset.getDefault();
useCharsetName := useCharsetRef.name;
end;
useData := &Array.newByte1d(10);
useLittleEndianDataInput := pascalx.io.LittleEndianDataInput.create(reader, useData);
useLittleEndianDataInput.fldCharsetRef := useCharsetRef;
useBigEndianDataInput := pascalx.io.BigEndianDataInput.create(reader, useData);
useBigEndianDataInput.fldCharsetRef := useCharsetRef;
fldCharsetName := useCharsetName;
fldReader := reader;
fldBigEndianDataInputAsInterface := useBigEndianDataInput;
fldBigEndianDataInputAsObject := useBigEndianDataInput;
fldLittleEndianDataInputAsInterface := useLittleEndianDataInput;
fldLittleEndianDataInputAsObject := useLittleEndianDataInput;
end;
destructor DataInputStream.destroy;
begin
fldLittleEndianDataInputAsObject.free();
fldBigEndianDataInputAsObject.free();
inherited destroy;
end;
procedure DataInputStream.close();
begin
fldReader.close();
destroy;
end;
function DataInputStream.read(): int;
begin
result := fldReader.read();
end;
function DataInputStream.read(const dst: byte_Array1d): int;
begin
result := fldReader.read(dst);
end;
function DataInputStream.read(const dst: byte_Array1d; offset, length: int): int;
begin
result := fldReader.read(dst, offset, length);
end;
function DataInputStream.skip(bytesQuantity: long): long;
begin
result := fldReader.skip(bytesQuantity);
end;
function DataInputStream.getExtensions(): Extension_Array1d;
begin
result := fldReader.getExtensions();
end;
function DataInputStream.getExtension(const typ: ShortString): Extension;
begin
result := fldReader.getExtension(typ);
end;
{%endregion}
{%region DataOutputStream }
procedure DataOutputStream.setCharsetName(const newCharsetName: AnsiString);
var
useCharsetName: AnsiString;
useCharsetRef: Charset;
begin
try
useCharsetRef := Charset.get(newCharsetName);
useCharsetName := newCharsetName;
except
useCharsetRef := Charset.getDefault();
useCharsetName := useCharsetRef.name;
end;
fldCharsetName := useCharsetName;
pascalx.io.LittleEndianDataOutput(fldBigEndianDataOutputAsObject).fldCharsetRef := useCharsetRef;
pascalx.io.LittleEndianDataOutput(fldLittleEndianDataOutputAsObject).fldCharsetRef := useCharsetRef;
end;
constructor DataOutputStream.create(writer: ByteWriter);
begin
create(writer, 'UTF-8');
end;
constructor DataOutputStream.create(writer: ByteWriter; const charsetName: AnsiString);
var
useCharsetName: AnsiString;
useCharsetRef: Charset;
useData: byte_Array1d;
useLittleEndianDataOutput: pascalx.io.LittleEndianDataOutput;
useBigEndianDataOutput: pascalx.io.LittleEndianDataOutput;
begin
inherited create();
try
useCharsetRef := Charset.get(charsetName);
useCharsetName := charsetName;
except
useCharsetRef := Charset.getDefault();
useCharsetName := useCharsetRef.name;
end;
useData := &Array.newByte1d(10);
useLittleEndianDataOutput := pascalx.io.LittleEndianDataOutput.create(writer, useData);
useLittleEndianDataOutput.fldCharsetRef := useCharsetRef;
useBigEndianDataOutput := pascalx.io.BigEndianDataOutput.create(writer, useData);
useBigEndianDataOutput.fldCharsetRef := useCharsetRef;
fldCharsetName := useCharsetName;
fldWriter := writer;
fldBigEndianDataOutputAsInterface := useBigEndianDataOutput;
fldBigEndianDataOutputAsObject := useBigEndianDataOutput;
fldLittleEndianDataOutputAsInterface := useLittleEndianDataOutput;
fldLittleEndianDataOutputAsObject := useLittleEndianDataOutput;
end;
destructor DataOutputStream.destroy;
begin
fldLittleEndianDataOutputAsObject.free();
fldBigEndianDataOutputAsObject.free();
inherited destroy;
end;
procedure DataOutputStream.close();
begin
fldWriter.close();
destroy;
end;
procedure DataOutputStream.write(byteData: int);
begin
fldWriter.write(byteData);
end;
procedure DataOutputStream.write(const src: byte_Array1d);
begin
fldWriter.write(src);
end;
procedure DataOutputStream.write(const src: byte_Array1d; offset, length: int);
begin
fldWriter.write(src, offset, length);
end;
procedure DataOutputStream.flush();
begin
fldWriter.flush();
end;
function DataOutputStream.getExtensions(): Extension_Array1d;
begin
result := fldWriter.getExtensions();
end;
function DataOutputStream.getExtension(const typ: ShortString): Extension;
begin
result := fldWriter.getExtension(typ);
end;
{%endregion}
{%region UCharInputStream }
procedure UCharInputStream.setCharsetName(const newCharsetName: AnsiString);
var
useCharsetName: AnsiString;
useCharsetRef: Charset;
oldDecoderRef: &Object;
begin
try
useCharsetRef := Charset.get(newCharsetName);
useCharsetName := newCharsetName;
except
useCharsetRef := Charset.getDefault();
useCharsetName := useCharsetRef.name;
end;
oldDecoderRef := fldDecoderRef;
fldCharsetName := useCharsetName;
fldDecoderRef := useCharsetRef.newDecoder();
oldDecoderRef.free();
end;
function UCharInputStream.readChars(length: int): &Object;
var
remained: int;
readedOld: int;
readedNew: int;
src: ByteReader;
dst: CharactersBuffer;
ext: UCharInputStreamStreamedExtension;
decoder: CharDecoder;
begin
decoder := CharDecoder(fldDecoderRef);
ext := UCharInputStreamStreamedExtension(fldStreamedExtension);
dst := ext.fldCharactersBuffer;
src := fldReader;
dst.discard(ext.fldCharactersReaded);
ext.fldCharactersReaded := CoInt.MAX_VALUE;
readedOld := -1;
repeat
readedNew := dst.length;
if readedOld = readedNew then break;
readedOld := readedNew;
if readedOld >= length then break;
remained := length - readedOld;
if remained >= CoInt.MAX_VALUE - 6 then begin
remained := CoInt.MAX_VALUE;
end else begin
remained := remained + 6;
end;
decoder.decodeToWriter(dst, src, remained);
until false;
ext.fldCharactersReaded := length;
result := dst;
end;
constructor UCharInputStream.create(reader: ByteReader);
begin
create(reader, 'UTF-8');
end;
constructor UCharInputStream.create(reader: ByteReader; const charsetName: AnsiString);
var
useCharsetName: AnsiString;
useCharsetRef: Charset;
ext0: MarkExtension;
ext1: LimitedSizeExtension;
begin
inherited create();
try
useCharsetRef := Charset.get(charsetName);
useCharsetName := charsetName;
except
useCharsetRef := Charset.getDefault();
useCharsetName := useCharsetRef.name;
end;
if reader = nil then begin
ext0 := nil;
ext1 := nil;
end else begin
ext0 := MarkExtension(reader.getExtension(MarkExtension));
ext1 := LimitedSizeExtension(reader.getExtension(LimitedSizeExtension));
end;
fldCharsetName := useCharsetName;
fldReader := reader;
fldDecoderRef := useCharsetRef.newDecoder();
if ext0 = nil then begin
fldMarkExtension := nil;
end else begin
fldMarkExtension := UCharInputStreamMarkExtension.create(ext0);
end;
fldStreamedExtension := UCharInputStreamStreamedExtension.create(ext1);
end;
destructor UCharInputStream.destroy;
begin
fldDecoderRef.free();
fldMarkExtension.free();
fldStreamedExtension.free();
inherited destroy;
end;
procedure UCharInputStream.close();
begin
fldReader.close();
destroy;
end;
function UCharInputStream.read(): int;
var
stream: CharactersBuffer;
begin
stream := CharactersBuffer(readChars(1));
if stream.length < 1 then begin
result := -1;
exit;
end;
result := int(stream[0]);
end;
function UCharInputStream.read(const dst: uchar_Array1d): int;
begin
result := read(dst, 0, length(dst));
end;
function UCharInputStream.read(const dst: uchar_Array1d; offset, length: int): int;
var
readed: int;
stream: CharactersBuffer;
begin
&Array.checkBounds(dst, offset, length);
if length <= 0 then begin
result := 0;
exit;
end;
stream := CharactersBuffer(readChars(length));
readed := CoInt.min(stream.length, length);
if readed <= 0 then begin
result := -1;
exit;
end;
stream.getChars(0, readed, dst, offset);
result := readed;
end;
function UCharInputStream.skip(ucharsQuantity: long): long;
var
total: long;
skipped: long;
buffer: uchar_Array1d;
begin
if ucharsQuantity <= 0 then begin
result := 0;
exit;
end;
total := 0;
buffer := &Array.newUChar1d(224);
while ucharsQuantity > 0 do begin
skipped := read(buffer, 0, int(CoLong.min(ucharsQuantity, 224)));
if skipped < 0 then break;
dec(ucharsQuantity, skipped);
inc(total, skipped);
end;
result := total;
end;
function UCharInputStream.getExtensions(): Extension_Array1d;
var
ext0: Extension;
ext1: Extension;
begin
ext0 := fldStreamedExtension as Extension;
ext1 := fldMarkExtension as Extension;
if ext1 = nil then begin
result := [ ext0 ];
exit;
end;
result := [ ext0, ext1 ];
end;
function UCharInputStream.getExtension(const typ: ShortString): Extension;
begin
if Lang.isType(typ, Extension) then begin
result := fldStreamedExtension as Extension;
exit;
end;
if Lang.isType(typ, MarkExtension) then begin
result := fldMarkExtension as MarkExtension;
exit;
end;
if Lang.isType(typ, StreamedExtension) then begin
result := fldStreamedExtension as StreamedExtension;
exit;
end;
result := nil;
end;
{%endregion}
{%region UCharOutputStream }
procedure UCharOutputStream.setCharsetName(const newCharsetName: AnsiString);
var
useCharsetName: AnsiString;
useCharsetRef: Charset;
oldEncoderRef: &Object;
begin
try
useCharsetRef := Charset.get(newCharsetName);
useCharsetName := newCharsetName;
except
useCharsetRef := Charset.getDefault();
useCharsetName := useCharsetRef.name;
end;
oldEncoderRef := fldEncoderRef;
fldCharsetName := useCharsetName;
fldEncoderRef := useCharsetRef.newEncoder();
oldEncoderRef.free();
end;
constructor UCharOutputStream.create(writer: ByteWriter);
begin
create(writer, 'UTF-8');
end;
constructor UCharOutputStream.create(writer: ByteWriter; const charsetName: AnsiString);
var
useCharsetName: AnsiString;
useCharsetRef: Charset;
begin
inherited create();
try
useCharsetRef := Charset.get(charsetName);
useCharsetName := charsetName;
except
useCharsetRef := Charset.getDefault();
useCharsetName := useCharsetRef.name;
end;
fldCharsetName := useCharsetName;
fldWriter := writer;
fldEncoderRef := useCharsetRef.newEncoder();
end;
destructor UCharOutputStream.destroy;
begin
fldEncoderRef.free();
inherited destroy;
end;
procedure UCharOutputStream.close();
begin
fldWriter.close();
destroy;
end;
procedure UCharOutputStream.write(ucharData: int);
begin
CharEncoder(fldEncoderRef).encodeToWriter(fldWriter, [ uchar(ucharData) ]);
end;
procedure UCharOutputStream.write(const src: uchar_Array1d);
begin
CharEncoder(fldEncoderRef).encodeToWriter(fldWriter, src, 0, length(src));
end;
procedure UCharOutputStream.write(const src: uchar_Array1d; offset, length: int);
begin
CharEncoder(fldEncoderRef).encodeToWriter(fldWriter, src, offset, length);
end;
procedure UCharOutputStream.flush();
begin
fldWriter.flush();
end;
function UCharOutputStream.getExtensions(): Extension_Array1d;
begin
result := nil;
end;
function UCharOutputStream.getExtension(const typ: ShortString): Extension;
begin
result := nil;
end;
{%endregion}
{%region PrintStream }
procedure PrintStream.write(const src: AnsiString);
begin
try
CharEncoder(fldEncoderRef).encodeToWriter(fldWriter, src.toUTF16().toUCharArray());
except
error();
end;
end;
procedure PrintStream.write(const src: UnicodeString);
begin
try
CharEncoder(fldEncoderRef).encodeToWriter(fldWriter, src.toUCharArray());
except
error();
end;
end;
procedure PrintStream.setCharsetName(const newCharsetName: AnsiString);
var
useCharsetName: AnsiString;
useCharsetRef: Charset;
oldEncoderRef: &Object;
begin
try
useCharsetRef := Charset.get(newCharsetName);
useCharsetName := newCharsetName;
except
useCharsetRef := Charset.getDefault();
useCharsetName := useCharsetRef.name;
end;
oldEncoderRef := fldEncoderRef;
fldCharsetName := useCharsetName;
fldEncoderRef := useCharsetRef.newEncoder();
oldEncoderRef.free();
end;
function PrintStream.setError(newError: boolean): boolean; assembler;
asm
{$IFDEF WINDOWS}
mov al, dl
{$ELSE}
lea rcx, [rdi+$00]
mov al, sil
{$ENDIF}
xchg byte [rcx+offset fldError], al
movsx eax, al
end;
procedure PrintStream.errorSet();
begin
end;
procedure PrintStream.errorCleared();
begin
end;
procedure PrintStream.error();
begin
if not setError(true) then errorSet();
end;
constructor PrintStream.create(writer: ByteWriter);
begin
create(writer, 'UTF-8');
end;
constructor PrintStream.create(writer: ByteWriter; const charsetName: AnsiString);
var
useCharsetName: AnsiString;
useCharsetRef: Charset;
begin
inherited create();
try
useCharsetRef := Charset.get(charsetName);
useCharsetName := charsetName;
except
useCharsetRef := Charset.getDefault();
useCharsetName := useCharsetRef.name;
end;
fldCharsetName := useCharsetName;
fldWriter := writer;
fldEncoderRef := useCharsetRef.newEncoder();
end;
destructor PrintStream.destroy;
begin
fldEncoderRef.free();
inherited destroy;
end;
procedure PrintStream.close();
begin
try
fldWriter.close();
except
error();
end;
destroy;
end;
procedure PrintStream.write(byteData: int);
begin
try
fldWriter.write(byteData);
except
error();
end;
end;
procedure PrintStream.write(const src: byte_Array1d);
begin
try
fldWriter.write(src);
except
error();
end;
end;
procedure PrintStream.write(const src: byte_Array1d; offset, length: int);
begin
try
fldWriter.write(src, offset, length);
except
error();
end;
end;
procedure PrintStream.flush();
begin
try
fldWriter.flush();
except
error();
end;
end;
procedure PrintStream.print(const src: boolean);
begin
if src then begin
write(UnicodeString('true'));
exit;
end;
write(UnicodeString('false'));
end;
procedure PrintStream.print(const src: int);
begin
write(CoInt.toString(src));
end;
procedure PrintStream.print(const src: long);
begin
write(CoLong.toString(src));
end;
procedure PrintStream.print(const src: float);
begin
write(CoFloat.toString(src));
end;
procedure PrintStream.print(const src: double);
begin
write(CoDouble.toString(src));
end;
procedure PrintStream.print(const src: real);
begin
write(CoReal.toString(src));
end;
procedure PrintStream.print(const src: AnsiString);
begin
write(src);
end;
procedure PrintStream.print(const src: UnicodeString);
begin
write(src);
end;
procedure PrintStream.print(const src: TObject);
begin
if src = nil then begin
write(UnicodeString('null'));
exit;
end;
write(src.toString());
end;
procedure PrintStream.print(const src: uchar_Array1d; offset, length: int);
begin
try
CharEncoder(fldEncoderRef).encodeToWriter(fldWriter, src, offset, length);
except
error();
end;
end;
procedure PrintStream.printf(const form: AnsiString; const data: array of Value);
begin
write(AnsiString.format(form, data));
end;
procedure PrintStream.printf(const form: UnicodeString; const data: array of Value);
begin
write(UnicodeString.format(form, data));
end;
procedure PrintStream.println();
begin
write(CoUnicodeString.LINE_ENDING);
end;
procedure PrintStream.println(const src: boolean);
begin
if src then begin
write(UnicodeString('true') + CoUnicodeString.LINE_ENDING);
exit;
end;
write(UnicodeString('false') + CoUnicodeString.LINE_ENDING);
end;
procedure PrintStream.println(const src: int);
begin
write(CoInt.toString(src) + CoAnsiString.LINE_ENDING);
end;
procedure PrintStream.println(const src: long);
begin
write(CoLong.toString(src) + CoAnsiString.LINE_ENDING);
end;
procedure PrintStream.println(const src: float);
begin
write(CoFloat.toString(src) + CoAnsiString.LINE_ENDING);
end;
procedure PrintStream.println(const src: double);
begin
write(CoDouble.toString(src) + CoAnsiString.LINE_ENDING);
end;
procedure PrintStream.println(const src: real);
begin
write(CoReal.toString(src) + CoAnsiString.LINE_ENDING);
end;
procedure PrintStream.println(const src: AnsiString);
begin
write(src + CoAnsiString.LINE_ENDING);
end;
procedure PrintStream.println(const src: UnicodeString);
begin
write(src + CoUnicodeString.LINE_ENDING);
end;
procedure PrintStream.println(const src: TObject);
begin
if src = nil then begin
write(UnicodeString('null') + CoUnicodeString.LINE_ENDING);
exit;
end;
write(src.toString() + CoAnsiString.LINE_ENDING);
end;
procedure PrintStream.println(const src: uchar_Array1d; offset, length: int);
begin
write(UnicodeString.create(src, offset, length) + CoUnicodeString.LINE_ENDING);
end;
procedure PrintStream.printlnf(const form: AnsiString; const data: array of Value);
begin
write(AnsiString.format(form, data) + CoAnsiString.LINE_ENDING);
end;
procedure PrintStream.printlnf(const form: UnicodeString; const data: array of Value);
begin
write(UnicodeString.format(form, data) + CoUnicodeString.LINE_ENDING);
end;
function PrintStream.getExtensions(): Extension_Array1d;
var
locWriter: ByteWriter;
begin
locWriter := fldWriter;
if locWriter = nil then begin
result := nil;
exit;
end;
result := locWriter.getExtensions();
end;
function PrintStream.getExtension(const typ: ShortString): Extension;
var
locWriter: ByteWriter;
begin
locWriter := fldWriter;
if locWriter = nil then begin
result := nil;
exit;
end;
result := locWriter.getExtension(typ);
end;
function PrintStream.isError(): boolean;
begin
if setError(false) then begin
errorCleared();
result := true;
exit;
end;
result := false;
end;
{%endregion}
{%region UResource }
class function UResource.readResourceAsUnicodeString(const rsrcName: AnsiString): UnicodeString;
begin
result := readResourceAsUnicodeString(rsrcName, 'UTF-8');
end;
class function UResource.readResourceAsUnicodeString(const rsrcName, charsetName: AnsiString): UnicodeString;
var
size: int;
inst: long;
desc: long;
handle: long;
rstring: byte_Array1d;
data: Pointer;
begin
inst := system.hInstance();
desc := long(system.findResource(inst, rsrcName, system.PAnsiChar({$IFDEF WINDOWS}windows{$ELSE}system{$ENDIF}.RT_RCDATA)));
if desc = 0 then begin
result := '';
exit;
end;
handle := long(system.loadResource(inst, desc));
if handle = 0 then begin
result := '';
exit;
end;
size := int(system.sizeofResource(inst, desc));
data := system.lockResource(handle);
try
rstring := &Array.newByte1d(size);
&Array.copyRaw(data^, rstring[0], size);
result := UnicodeString.create(Charset.get(charsetName).decode(rstring, 0, size));
finally
system.unlockResource(handle);
system.freeResource(handle);
end;
end;
class function UResource.readUnitResourceAsUnicodeString(const __unitName, rstrName: AnsiString): UnicodeString;
begin
result := readResourceAsUnicodeString(AResource.unitToTextResourceName(__unitName, rstrName), 'UTF-8');
end;
class function UResource.readUnitResourceAsUnicodeString(const __unitName, rstrName, charsetName: AnsiString): UnicodeString;
begin
result := readResourceAsUnicodeString(AResource.unitToTextResourceName(__unitName, rstrName), charsetName);
end;
{%endregion}
{%region SResource }
class function SResource.isResourceExists(const rsrcName: AnsiString): boolean;
begin
result := long(system.findResource(system.hInstance(), rsrcName, system.PAnsiChar({$IFDEF WINDOWS}windows{$ELSE}system{$ENDIF}.RT_RCDATA))) <> 0;
end;
class function SResource.isUnitResourceExists(const __unitName, rsrcName: AnsiString): boolean;
begin
result := isResourceExists(AResource.unitToTextResourceName(__unitName, rsrcName));
end;
class function SResource.openResourceAsStream(const rsrcName: AnsiString): ByteReader;
var
size: int;
inst: long;
desc: long;
handle: long;
data: Pointer;
begin
inst := system.hInstance();
desc := long(system.findResource(inst, rsrcName, system.PAnsiChar({$IFDEF WINDOWS}windows{$ELSE}system{$ENDIF}.RT_RCDATA)));
if desc = 0 then begin
result := nil;
exit;
end;
handle := long(system.loadResource(inst, desc));
if handle = 0 then begin
result := nil;
exit;
end;
size := int(system.sizeofResource(inst, desc));
data := system.lockResource(handle);
result := ResourceStream.create(handle, data, size);
end;
class function SResource.openUnitResourceAsStream(const __unitName, rsrcName: AnsiString): ByteReader;
begin
result := openResourceAsStream(AResource.unitToTextResourceName(__unitName, rsrcName));
end;
{%endregion}
{%region ResourceStream }
constructor ResourceStream.create(handle: long; data: Pointer; length: int);
begin
inherited create();
fldLength := length;
fldHandle := handle;
fldData := PByte(data);
end;
procedure ResourceStream.reset();
begin
fldPosition := fldMarked;
end;
procedure ResourceStream.mark(transferLimit: int);
begin
fldMarked := fldPosition;
end;
procedure ResourceStream.close();
var
handle: system.PtrUInt;
begin
handle := system.PtrUInt(fldHandle);
destroy;
system.unlockResource(handle);
system.freeResource(handle);
end;
function ResourceStream.read(): int;
var
locPosition: int;
begin
locPosition := fldPosition;
if locPosition >= fldLength then begin
result := -1;
exit;
end;
fldPosition := locPosition + 1;
result := (fldData + locPosition)^ and $ff;
end;
function ResourceStream.read(const dst: byte_Array1d): int;
begin
result := read(dst, 0, length(dst));
end;
function ResourceStream.read(const dst: byte_Array1d; offset, length: int): int;
var
locPosition: int;
locRemainder: int;
begin
&Array.checkBounds(dst, offset, length);
if length <= 0 then begin
result := 0;
exit;
end;
locPosition := fldPosition;
locRemainder := fldLength - locPosition;
if locRemainder <= 0 then begin
result := -1;
exit;
end;
if length > locRemainder then length := locRemainder;
&Array.copyRaw((fldData + locPosition)^, dst[offset], length);
fldPosition := locPosition + length;
result := length;
end;
function ResourceStream.skip(bytesQuantity: long): long;
var
locLength: int;
locPosition: int;
locRemainder: int;
begin
if bytesQuantity <= 0 then begin
result := 0;
exit;
end;
if bytesQuantity < CoInt.MAX_VALUE then begin
locLength := int(bytesQuantity);
end else begin
locLength := CoInt.MAX_VALUE;
end;
locPosition := fldPosition;
locRemainder := fldLength - locPosition;
if locLength > locRemainder then locLength := locRemainder;
fldPosition := locPosition + locLength;
result := locLength;
end;
function ResourceStream.seek(offset: long; from: SeekFrom): long;
var
locLength: long;
locPosition: long;
begin
locLength := fldLength;
case from of
SeekFrom.sfBegin:
locPosition := offset;
SeekFrom.sfEnd:
locPosition := offset + locLength;
SeekFrom.sfCurrent:
locPosition := offset + fldPosition;
else
raise IllegalArgumentException.create(AnsiString.format(AResource.readUnitResourceAsAnsiString(pascalx.lang.UNIT_NAME, 'illegal-argument'), [ CoAnsiString.create('from') ]));
end;
if locPosition < 0 then locPosition := 0;
if locPosition > locLength then locPosition := locLength;
fldPosition := int(locPosition);
result := locPosition;
end;
function ResourceStream.position(): long;
begin
result := fldPosition;
end;
function ResourceStream.size(): long;
begin
result := fldLength;
end;
function ResourceStream.available(): long;
begin
result := fldLength - fldPosition;
end;
function ResourceStream.getExtensions(): Extension_Array1d;
begin
result := [ self as Extension ];
end;
function ResourceStream.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 LittleEndianDataInput }
procedure LittleEndianDataInput.readData(length: int);
var
offset: int;
readed: int;
dst: byte_Array1d;
reader: ByteReader;
begin
dst := fldData;
offset := 0;
reader := fldReader;
while length > 0 do begin
readed := reader.read(dst, offset, length);
if readed <= 0 then begin
raise EndOfStreamException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'io.read.end-of-stream'));
end;
inc(offset, readed);
dec(length, readed);
end;
end;
constructor LittleEndianDataInput.create(reader: ByteReader; const data: byte_Array1d);
begin
inherited create();
fldData := data;
fldReader := reader;
end;
procedure LittleEndianDataInput.readFully(const dst: byte_Array1d);
begin
readFully(dst, 0, length(dst));
end;
procedure LittleEndianDataInput.readFully(const dst: byte_Array1d; offset, length: int);
var
readed: int;
reader: ByteReader;
begin
&Array.checkBounds(dst, offset, length);
reader := fldReader;
while length > 0 do begin
readed := reader.read(dst, offset, length);
if readed <= 0 then begin
raise EndOfStreamException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'io.read.end-of-stream'));
end;
inc(offset, readed);
dec(length, readed);
end;
end;
function LittleEndianDataInput.readBoolean(): boolean;
var
data: int;
begin
data := fldReader.read();
if data < 0 then begin
raise EndOfStreamException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'io.read.end-of-stream'));
end;
result := (data and $ff) <> 0;
end;
function LittleEndianDataInput.readChar(): char;
var
data: int;
begin
data := fldReader.read();
if data < 0 then begin
raise EndOfStreamException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'io.read.end-of-stream'));
end;
result := char(data);
end;
function LittleEndianDataInput.readUChar(): uchar;
begin
readData(2);
result := uchar((@(fldData[0]))^);
end;
function LittleEndianDataInput.readUnsignedByte(): int;
var
data: int;
begin
data := fldReader.read();
if data < 0 then begin
raise EndOfStreamException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'io.read.end-of-stream'));
end;
result := data and $ff;
end;
function LittleEndianDataInput.readUnsignedShort(): int;
begin
readData(2);
result := short((@(fldData[0]))^) and $ffff;
end;
function LittleEndianDataInput.readByte(): int;
var
data: int;
begin
data := fldReader.read();
if data < 0 then begin
raise EndOfStreamException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'io.read.end-of-stream'));
end;
result := byte(data);
end;
function LittleEndianDataInput.readShort(): int;
begin
readData(2);
result := short((@(fldData[0]))^);
end;
function LittleEndianDataInput.readInt(): int;
begin
readData(4);
result := int((@(fldData[0]))^);
end;
function LittleEndianDataInput.readLong(): long;
begin
readData(8);
result := long((@(fldData[0]))^);
end;
function LittleEndianDataInput.readFloat(): float;
begin
readData(4);
result := float((@(fldData[0]))^);
end;
function LittleEndianDataInput.readDouble(): double;
begin
readData(8);
result := double((@(fldData[0]))^);
end;
function LittleEndianDataInput.readReal(): real;
begin
readData(10);
result := real((@(fldData[0]))^);
end;
function LittleEndianDataInput.readUTF(): UnicodeString;
var
b1: int;
b2: int;
b3: int;
index: int;
utfLength: int;
resultLength: int;
utfData: byte_Array1d;
resultData: uchar_Array1d;
begin
utfLength := readUnsignedShort();
if utfLength <= 0 then begin
result := '';
exit;
end;
utfData := &Array.newByte1d(utfLength);
readFully(utfData, 0, utfLength);
resultLength := 0;
resultData := &Array.newUChar1d(utfLength);
index := 0;
while index < utfLength do begin
b1 := utfData[index] and $ff;
case b1 shr 4 of
$00..$07: begin
inc(index);
resultData[resultLength] := uchar(b1);
inc(resultLength);
end;
$0c..$0d: begin
inc(index, 2);
if index > utfLength then begin
raise UTFDataFormatException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'invalid-data-format'));
end;
b2 := utfData[index - 1];
if (b2 and $c0) <> $80 then begin
raise UTFDataFormatException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'invalid-data-format'));
end;
resultData[resultLength] := uchar(((b1 and $1f) shl 6) or (b2 and $3f));
inc(resultLength);
end;
$0e: begin
inc(index, 3);
if index > utfLength then begin
raise UTFDataFormatException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'invalid-data-format'));
end;
b2 := utfData[index - 2];
b3 := utfData[index - 1];
if ((b2 and $c0) <> $80) or ((b3 and $c0) <> $80) then begin
raise UTFDataFormatException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'invalid-data-format'));
end;
resultData[resultLength] := uchar(((b1 and $0f) shl 12) or ((b2 and $3f) shl 6) or (b3 and $3f));
inc(resultLength);
end;
else
raise UTFDataFormatException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'invalid-data-format'));
end;
end;
result := UnicodeString.create(resultData, 0, resultLength);
end;
function LittleEndianDataInput.readln(): UnicodeString;
var
b0: int;
index: int;
endingStart: int;
endingLength: int;
resultLength: int;
endingData: byte_Array1d;
resultData: byte_Array1d;
resultCopy: byte_Array1d;
charsetRef: Charset;
reader: ByteReader;
begin
resultLength := 0;
resultData := &Array.newByte1d($7f);
charsetRef := fldCharsetRef;
endingData := charsetRef.encode(CoUnicodeString.LINE_ENDING.toUCharArray());
endingStart := endingData[0] and $ff;
endingLength := length(endingData);
reader := fldReader;
while resultLength < CoInt.MAX_VALUE do begin
b0 := reader.read();
if b0 = endingStart then begin
for index := 1 to endingLength - 1 do if reader.read() <> (endingData[index] and $ff) then begin
raise MalformedLineSeparatorException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'invalid-data-format.malformed-line-separator'));
end;
break;
end;
if b0 < 0 then break;
if resultLength = length(resultData) then begin
resultCopy := &Array.newByte1d((resultLength shl 1) or 1);
&Array.copyPrimitives(resultData, 0, resultCopy, 0, resultLength);
resultData := resultCopy;
end;
resultData[resultLength] := byte(b0);
inc(resultLength);
end;
result := UnicodeString.create(charsetRef.decode(resultData, 0, resultLength));
end;
function LittleEndianDataInput.read(): UnicodeString;
var
b0: int;
index: int;
endingStart: int;
endingLength: int;
resultLength: int;
endingData: byte_Array1d;
resultData: byte_Array1d;
resultCopy: byte_Array1d;
charsetRef: Charset;
reader: ByteReader;
begin
resultLength := 0;
resultData := &Array.newByte1d($7f);
charsetRef := fldCharsetRef;
endingData := charsetRef.encode(CoUnicodeString.LINE_ENDING.toUCharArray());
endingStart := endingData[0] and $ff;
endingLength := length(endingData);
reader := fldReader;
repeat
b0 := reader.read();
if b0 < 0 then begin
result := '';
exit;
end;
if b0 > $20 then begin
resultData[0] := byte(b0);
resultLength := 1;
break;
end;
until false;
while resultLength < CoInt.MAX_VALUE do begin
b0 := reader.read();
if b0 = endingStart then begin
for index := 1 to endingLength - 1 do if reader.read() <> (endingData[index] and $ff) then begin
raise MalformedLineSeparatorException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'invalid-data-format.malformed-line-separator'));
end;
break;
end;
if b0 <= $20 then break;
if resultLength = length(resultData) then begin
resultCopy := &Array.newByte1d((resultLength shl 1) or 1);
&Array.copyPrimitives(resultData, 0, resultCopy, 0, resultLength);
resultData := resultCopy;
end;
resultData[resultLength] := byte(b0);
inc(resultLength);
end;
result := UnicodeString.create(charsetRef.decode(resultData, 0, resultLength));
end;
{%endregion}
{%region BigEndianDataInput }
procedure BigEndianDataInput.readData(length: int); assembler;
var
storageLength: int;
{$IFDEF WINDOWS}
storageRSI: long;
storageRDI: long;
{$ENDIF}
storageSelf: BigEndianDataInput;
asm
{$IFDEF WINDOWS}
mov qword [storageRSI], rsi
mov qword [storageRDI], rdi
mov qword [storageSelf], rcx
mov dword [storageLength], edx
{$ELSE}
mov qword [storageSelf], rdi
mov dword [storageLength], esi
{$ENDIF}
call LittleEndianDataInput.readData
mov ecx, [storageLength]
shr ecx, $01
jz @01
mov rsi, [storageSelf]
mov rsi, [rsi+offset fldData]
lea rdi, [rsi+rcx*2-$01]
@00: mov al, [rsi+$00]
mov dl, [rdi+$00]
mov byte [rsi+$00], dl
mov byte [rdi+$00], al
lea rsi, [rsi+$01]
lea rdi, [rdi-$01]
loop @00
@01:
{$IFDEF WINDOWS}
mov rdi, [storageRDI]
mov rsi, [storageRSI]
{$ENDIF}
end;
{%endregion}
{%region LittleEndianDataOutput }
procedure LittleEndianDataOutput.writeData(length: int);
begin
fldWriter.write(fldData, 0, length);
end;
constructor LittleEndianDataOutput.create(writer: ByteWriter; const data: byte_Array1d);
begin
inherited create();
fldData := data;
fldWriter := writer;
end;
procedure LittleEndianDataOutput.write(const src: byte_Array1d);
begin
fldWriter.write(src, 0, length(src));
end;
procedure LittleEndianDataOutput.write(const src: byte_Array1d; offset, length: int);
begin
fldWriter.write(src, offset, length);
end;
procedure LittleEndianDataOutput.writeBoolean(const data: boolean);
begin
if data then begin
fldWriter.write($01);
exit;
end;
fldWriter.write($00);
end;
procedure LittleEndianDataOutput.writeChar(const data: char);
begin
fldWriter.write(int(data));
end;
procedure LittleEndianDataOutput.writeUChar(const data: uchar);
begin
uchar((@(fldData[0]))^) := data;
writeData(2);
end;
procedure LittleEndianDataOutput.writeByte(const data: int);
begin
fldWriter.write(data);
end;
procedure LittleEndianDataOutput.writeShort(const data: int);
begin
short((@(fldData[0]))^) := data;
writeData(2);
end;
procedure LittleEndianDataOutput.writeInt(const data: int);
begin
int((@(fldData[0]))^) := data;
writeData(4);
end;
procedure LittleEndianDataOutput.writeLong(const data: long);
begin
long((@(fldData[0]))^) := data;
writeData(8);
end;
procedure LittleEndianDataOutput.writeFloat(const data: float);
begin
float((@(fldData[0]))^) := data;
writeData(4);
end;
procedure LittleEndianDataOutput.writeDouble(const data: double);
begin
double((@(fldData[0]))^) := data;
writeData(8);
end;
procedure LittleEndianDataOutput.writeReal(const data: real);
begin
real((@(fldData[0]))^) := data;
writeData(10);
end;
procedure LittleEndianDataOutput.writeUTF(const data: UnicodeString);
var
chr: int;
index: int;
resultLength: int;
stringLength: int;
resultData: byte_Array1d;
stringData: uchar_Array1d;
begin
stringLength := data.length;
if stringLength <= 0 then begin
writeShort(0);
exit;
end;
if stringLength > $00010000 then stringLength := $00010000;
stringData := &Array.newUChar1d(stringLength);
&Array.copyRaw(data[1], stringData[0], stringLength * sizeof(uchar));
resultLength := 0;
for index := stringLength - 1 downto 0 do begin
chr := int(stringData[index]);
if (chr > $0000) and (chr < $0080) then begin
inc(resultLength, 1);
end else
if chr < $0800 then begin
inc(resultLength, 2);
end else begin
inc(resultLength, 3);
end;
if resultLength > $ffff then begin
raise UTFDataFormatException.create(AResource.readUnitResourceAsAnsiString(pascalx.io.UNIT_NAME, 'invalid-data-format.utf.too-long'));
end;
end;
resultData := &Array.newByte1d(resultLength);
resultLength := 0;
for index := 0 to stringLength - 1 do begin
chr := int(stringData[index]);
if (chr > $0000) and (chr < $0080) then begin
resultData[resultLength + 0] := byte(chr);
inc(resultLength);
continue;
end;
if chr < $0800 then begin
resultData[resultLength + 0] := byte($c0 or (chr shr 6) and $1f);
resultData[resultLength + 1] := byte($80 or chr and $3f);
inc(resultLength, 2);
continue;
end;
resultData[resultLength + 0] := byte($e0 or (chr shr 12) and $0f);
resultData[resultLength + 1] := byte($80 or (chr shr 6) and $3f);
resultData[resultLength + 2] := byte($80 or chr and $3f);
inc(resultLength, 3);
end;
writeShort(resultLength);
write(resultData, 0, resultLength);
end;
procedure LittleEndianDataOutput.writeln(const data: UnicodeString);
begin
with fldWriter, fldCharsetRef do begin
write(encode(data.toUCharArray()));
write(encode(CoUnicodeString.LINE_ENDING.toUCharArray()));
end;
end;
procedure LittleEndianDataOutput.write(const data: UnicodeString);
begin
with fldWriter, fldCharsetRef do begin
write(encode(data.toUCharArray()));
write(encode(UnicodeString(#$0020).toUCharArray()));
end;
end;
{%endregion}
{%region BigEndianDataOutput }
procedure BigEndianDataOutput.writeData(length: int); assembler;
var
storageLength: int;
{$IFDEF WINDOWS}
storageRSI: long;
storageRDI: long;
{$ENDIF}
storageSelf: BigEndianDataOutput;
asm
{$IFDEF WINDOWS}
mov qword [storageRSI], rsi
mov qword [storageRDI], rdi
mov qword [storageSelf], rcx
mov dword [storageLength], edx
mov ecx, edx
{$ELSE}
mov qword [storageSelf], rdi
mov dword [storageLength], esi
mov ecx, esi
{$ENDIF}
shr ecx, $01
jz @01
mov rsi, [storageSelf]
mov rsi, [rsi+offset fldData]
lea rdi, [rsi+rcx*2-$01]
@00: mov al, [rsi+$00]
mov dl, [rdi+$00]
mov byte [rsi+$00], dl
mov byte [rdi+$00], al
lea rsi, [rsi+$01]
lea rdi, [rdi-$01]
loop @00
@01:
{$IFDEF WINDOWS}
mov rcx, [storageSelf]
mov edx, [storageLength]
{$ELSE}
mov rdi, [storageSelf]
mov esi, [storageLength]
{$ENDIF}
call LittleEndianDataOutput.writeData
{$IFDEF WINDOWS}
mov rdi, [storageRDI]
mov rsi, [storageRSI]
{$ENDIF}
end;
{%endregion}
{%region UCharInputStreamMarkExtension }
constructor UCharInputStreamMarkExtension.create(ext: MarkExtension);
begin
inherited create();
fldMarkExtension := ext;
end;
procedure UCharInputStreamMarkExtension.reset();
begin
fldMarkExtension.reset();
end;
procedure UCharInputStreamMarkExtension.mark(transferLimit: int);
begin
fldMarkExtension.mark(transferLimit);
end;
{%endregion}
{%region UCharInputStreamStreamedExtension }
constructor UCharInputStreamStreamedExtension.create(ext: LimitedSizeExtension);
begin
inherited create();
fldCharactersBuffer := CharactersBuffer.create();
fldLimitedSizeExtension := ext;
end;
function UCharInputStreamStreamedExtension.ready(): boolean;
var
ext: LimitedSizeExtension;
begin
if fldCharactersBuffer.length > fldCharactersReaded then begin
result := true;
exit;
end;
ext := fldLimitedSizeExtension;
result := (ext <> nil) and (ext.available() > 0);
end;
{%endregion}
{%region} initialization
Lang.registerInterfaces([
typeInfo(Extension),
typeInfo(Extendable),
typeInfo(ByteReader),
typeInfo(ByteWriter),
typeInfo(UCharReader),
typeInfo(UCharWriter),
typeInfo(DataInput),
typeInfo(DataOutput)
]);
{%endregion}
end.