textfiles.pas

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

{
    TextFiles содержит методы для работы с текстовыми файлами: сохранение, загрузка,
    разбиение на массив строк, объединение массива строк.

    Copyright © 2016, 2017 Малик Разработчик

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

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

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

unit TextFiles;

{$MODE DELPHI,EXTENDEDSYNTAX ON}

interface

uses
    Lang, IOStream;

{$ASMMODE INTEL,CALLING REGISTER,INLINE ON,GOTO ON}
{$H+,I-,J-,M-,Q-,R-,T-}

function saveStringsToStream(stream: Output; const strings: String_Array1d; count: int): int;
function loadStringsFromStream(stream: Input): String_Array1d;
function splitTextToStrings(const text: String): String_Array1d;
function makeTextStringOf(const strings: String_Array1d; count: int): String;

implementation

{ functions }

function saveStringsToStream(stream: Output; const strings: String_Array1d; count: int): int;
begin
    result := stream.write(stringToByteArray(makeTextStringOf(strings, count)));
end;

function loadStringsFromStream(stream: Input): String_Array1d;
var
    b: byte_Array1d;
begin
    b := byte_Array1d_create(int(stream.available()));
    stream.read(b);
    result := splitTextToStrings(String_create(b, 0, length(b)));
end;

function splitTextToStrings(const text: String): String_Array1d;
const
    CR = #13;
    LF = #10;
var
    i: int;
    j: int;
    len: int;
    count: int;
    strings: String_Array1d;
begin
    len := length(text);
    if len = 0 then begin
        result := nil;
        exit;
    end;
    count := 0;
    strings := String_Array1d_create(1);
    if (len >= 3) and (text[1] = #$ef) and (text[2] = #$bb) and (text[3] = #$bf) then begin
        if len = 3 then begin
            result := nil;
            exit;
        end;
        i := 4;
    end else begin
        i := 1;
    end;
    j := i;
    repeat
        while (j <= len) and (not (text[j] in [CR, LF])) do begin
            inc(j);
        end;
        if count = length(strings) then begin
            result := String_Array1d_create((count shl 1) + 1);
            arraycopyStrings(strings, 0, result, 0, count);
            strings := result;
            result := nil;
        end;
        strings[count] := copy(text, i, j - i);
        inc(count);
        if j > len then begin
            break;
        end;
        if (j < len) and (text[j] = CR) and (text[j + 1] = LF) then begin
            inc(j, 2);
            i := j;
            continue;
        end;
        inc(j);
        i := j;
    until false;
    if count < length(strings) then begin
        result := String_Array1d_create(count);
        arraycopyStrings(strings, 0, result, 0, count);
        exit;
    end;
    result := strings;
end;

function makeTextStringOf(const strings: String_Array1d; count: int): String;
var
    i: int;
    j: int;
    len: int;
    rlen: int;
    str: String;
begin
    len := Math.min(length(strings), Math.max(0, count)) - 1;
    if len < 0 then begin
        result := '';
        exit;
    end;
    rlen := 0;
    for i := 0 to len do begin
        inc(rlen, length(strings[i]));
    end;
    inc(rlen, length(LINE_ENDING) * len);
    result := String_create(rlen);
    j := 1;
    for i := 0 to len do begin
        str := strings[i];
        rlen := length(str);
        move(str[1], result[j], rlen);
        inc(j, rlen);
        if i < len then begin
            str := LINE_ENDING;
            rlen := length(str);
            move(str[1], result[j], rlen);
            inc(j, rlen);
        end;
    end;
end;

end.