{
osindepended.fileformats.text.plain — модуль для реализации простого текстового файлового формата.
Copyright © 2021 Малик Разработчик
Это свободная программа: вы можете перераспространять её и/или
изменять её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она может быть полезна,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
}
unit osindepended.fileformats.text.plain;
{$MODE DELPHI}
interface
uses
pascalx.lang,
pascalx.io,
osindepended.fileformats,
osindepended.fileformats.text;
{$ASMMODE INTEL,CALLING REGISTER,TYPEINFO ON}
{%region public }
type
PlainTextCodec = class;
PlainTextCodec = class(DynamicalyAllocatedObject, DataHolder, DataDecoder, DataEncoder, TextDecoder, TextEncoder)
private
count: int;
strings: AnsiString_Array1d;
lineEnding: AnsiString;
public
constructor create(); override;
function toString(): AnsiString; override;
function getLineEnding(): AnsiString;
function getAnsiStrings(): AnsiString_Array1d;
function getUnicodeStrings(): UnicodeString_Array1d;
function isEmpty(): boolean;
procedure clear();
procedure setLineEnding(const lineEnding: AnsiString);
procedure setAnsiStrings(const strings: AnsiString_Array1d);
procedure setUnicodeStrings(const strings: UnicodeString_Array1d);
procedure loadFromInputStream(stream: Input);
procedure loadFromDataInputStream(stream: DataInput);
procedure saveToOutputStream(stream: Output);
procedure saveToDataOutputStream(stream: DataOutput);
end;
{%endregion}
implementation
{%region PlainTextCodec }
constructor PlainTextCodec.create();
begin
inherited create();
self.lineEnding := LINE_ENDING;
end;
function PlainTextCodec.toString(): AnsiString;
var
i: int;
count: int;
text: AnsiString;
lineEnding: AnsiString;
strings: AnsiString_Array1d;
begin
count := self.count;
if count <= 0 then begin
result := '';
exit;
end;
lineEnding := self.lineEnding;
strings := self.strings;
text := strings[0];
for i := 1 to count - 1 do begin
text := text + lineEnding + strings[i];
end;
result := text;
end;
function PlainTextCodec.getLineEnding(): AnsiString;
begin
result := lineEnding;
end;
function PlainTextCodec.getAnsiStrings(): AnsiString_Array1d;
var
count: int;
astrings: AnsiString_Array1d;
begin
count := self.count;
astrings := AnsiString_Array1d_create(count);
arraycopyAnsiStrings(strings, 0, astrings, 0, count);
result := astrings;
end;
function PlainTextCodec.getUnicodeStrings(): UnicodeString_Array1d;
var
i: int;
count: int;
astrings: AnsiString_Array1d;
ustrings: UnicodeString_Array1d;
begin
count := self.count;
astrings := self.strings;
ustrings := UnicodeString_Array1d_create(count);
for i := count - 1 downto 0 do begin
ustrings[i] := stringToUTF16(astrings[i]);
end;
result := ustrings;
end;
function PlainTextCodec.isEmpty(): boolean;
begin
result := false;
end;
procedure PlainTextCodec.clear();
begin
count := 0;
strings := nil;
lineEnding := LINE_ENDING;
end;
procedure PlainTextCodec.setLineEnding(const lineEnding: AnsiString);
begin
if (lineEnding <> #$0d#$0a) and (lineEnding <> #$0d) and (lineEnding <> #$0a) then begin
raise InvalidDataFormatException.create('PlainTextCodec.setLineEnding: ' + msgInvalidDataFormat);
end;
self.lineEnding := lineEnding;
end;
procedure PlainTextCodec.setAnsiStrings(const strings: AnsiString_Array1d);
begin
self.count := length(strings);
self.strings := strings;
end;
procedure PlainTextCodec.setUnicodeStrings(const strings: UnicodeString_Array1d);
var
i: int;
count: int;
astrings: AnsiString_Array1d;
begin
count := length(strings);
astrings := AnsiString_Array1d_create(count);
for i := count - 1 downto 0 do begin
astrings[i] := stringToUTF8(strings[i]);
end;
self.count := count;
self.strings := astrings;
end;
procedure PlainTextCodec.loadFromInputStream(stream: Input);
var
i1: int;
i2: int;
len: int;
count: int;
data: byte_Array1d;
lineEnding: AnsiString;
strings: AnsiString_Array1d;
begin
len := int(longMin(stream.available(), INT_MAX_VALUE));
if len <= 0 then begin
self.count := 0;
self.strings := nil;
self.lineEnding := LINE_ENDING;
exit;
end;
data := byte_Array1d_create(len);
len := stream.read(data, 0, len);
if len <= 0 then begin
self.count := 0;
self.strings := nil;
self.lineEnding := LINE_ENDING;
exit;
end;
count := 1;
for i2 := 0 to len - 1 do begin
case int(data[i2]) of
$0d: begin
inc(count);
end;
$0a: begin
if (i2 <= 0) or (data[i2 - 1] <> $0d) then begin
inc(count);
end;
end;
end;
end;
lineEnding := LINE_ENDING;
strings := AnsiString_Array1d_create(count);
count := 0;
i1 := 0;
for i2 := 0 to len - 1 do begin
case int(data[i2]) of
$0d: begin
if count = 0 then begin
lineEnding := #$0d;
end;
strings[count] := AnsiString_create(data, i1, i2 - i1);
inc(count);
i1 := i2 + 1;
end;
$0a: begin
if (i2 <= 0) or (data[i2 - 1] <> $0d) then begin
if count = 0 then begin
lineEnding := #$0a;
end;
strings[count] := AnsiString_create(data, i1, i2 - i1);
inc(count);
end else begin
if count = 1 then begin
lineEnding := #$0d#$0a;
end;
end;
i1 := i2 + 1;
end;
end;
end;
strings[count] := AnsiString_create(data, i1, len - i1);
self.count := count + 1;
self.strings := strings;
self.lineEnding := lineEnding;
end;
procedure PlainTextCodec.loadFromDataInputStream(stream: DataInput);
begin
loadFromInputStream(stream);
end;
procedure PlainTextCodec.saveToOutputStream(stream: Output);
begin
saveToDataOutputStream(DataOutputStream.create(stream));
end;
procedure PlainTextCodec.saveToDataOutputStream(stream: DataOutput);
var
i: int;
count: int;
lineEnding: AnsiString;
strings: AnsiString_Array1d;
begin
count := self.count;
if count <= 0 then exit;
strings := self.strings;
lineEnding := self.lineEnding;
stream.writeAnsiChars(strings[0]);
for i := 1 to count - 1 do begin
stream.writeAnsiChars(lineEnding);
stream.writeAnsiChars(strings[i]);
end;
end;
{%endregion}
initialization
classInfoAdd([
typeInfo(PlainTextCodec)
]);
end.