{
    StaticRecompilers содержит классы для разработки
    статических рекомпиляторов под Малик Эмулятор.
    Этот исходный текст является частью Малик Эмулятора.

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

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

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

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

unit StaticRecompilers;

{$MODE DELPHI}

interface

uses
    Lang;

{%region public }
const
    STATIC_RECOMPILER_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1515}';
    ADJUSTABLE_RECOMPILER_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1516}';

type
    StaticRecompiler = interface;
    AdjustableRecompiler = interface;

    StaticRecompiler = interface(_Interface) [STATIC_RECOMPILER_GUID]
        function createInstance(): StaticRecompiler;
        function install(const archive, destinationDirectory: AnsiString): AnsiString;
        function getPlatformName(): AnsiString;
        function getArchiveTypeName(): AnsiString;
        function getArchiveExtension(): AnsiString;
    end;

    AdjustableRecompiler = interface(StaticRecompiler) [ADJUSTABLE_RECOMPILER_GUID]
        function getAlignment(): boolean;
        function getCompressionLevel(): int;
        function getStackSize(): int;
        function getHeapSize(): int;
        function getDescriptorsSize(): int;
        function getOutputExecutableFileName(): AnsiString;
        procedure setDefaults();
        procedure setAlignment(alignment: boolean);
        procedure setCompressionLevel(compressionLevel: int);
        procedure setStackSize(sizeInMB: int);
        procedure setHeapSize(sizeInKB: int);
        procedure setDescriptorsSize(sizeInKB: int);
        procedure setOutputExecutableFileName(const relativeFileName: AnsiString);
    end;
{%endregion}

{%region routine }
    function getRecompilersCount(): int;
    function getRecompiler(index: int): StaticRecompiler;
    function findRecompiler(const extension: AnsiString): StaticRecompiler;
    procedure addRecompiler(recompiler: StaticRecompiler);
{%endregion}

implementation

{%region private }
type
    StaticRecompiler_Array1d = packed array of StaticRecompiler;

var
    RECOMPILERS_COUNT: int;
    RECOMPILERS: StaticRecompiler_Array1d;
{%endregion}

{%region routine }
    function StaticRecompiler_Array1d_create(length: int): StaticRecompiler_Array1d;
    begin
        setLength(result, length);
    end;

    procedure arraycopy(const src: StaticRecompiler_Array1d; srcOffset: int; const dst: StaticRecompiler_Array1d; dstOffset: int; length: int);
    var
        lim: int;
        len: int;
        i: int;
    begin
        lim := srcOffset + length;
        len := System.length(src);
        if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
            raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
        end;
        lim := dstOffset + length;
        len := System.length(dst);
        if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
            raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
        end;
        if (src = dst) and (srcOffset < dstOffset) then begin
            for i := length - 1 downto 0 do begin
                dst[dstOffset + i] := src[srcOffset + i];
            end;
        end else begin
            for i := 0 to length - 1 do begin
                dst[dstOffset + i] := src[srcOffset + i];
            end;
        end;
    end;

    function getRecompilersCount(): int;
    begin
        result := RECOMPILERS_COUNT;
    end;

    function getRecompiler(index: int): StaticRecompiler;
    begin
        if (index < 0) or (index >= RECOMPILERS_COUNT) then begin
            raise ArrayIndexOutOfBoundsException.create(index);
        end;
        result := RECOMPILERS[index];
    end;

    function findRecompiler(const extension: AnsiString): StaticRecompiler;
    var
        i: int;
        r: StaticRecompiler;
        e: AnsiString;
    begin
        e := toLowerCase(extension);
        for i := RECOMPILERS_COUNT - 1 downto 0 do begin
            r := RECOMPILERS[i];
            if toLowerCase(r.getArchiveExtension()) = e then begin
                result := r;
                exit;
            end;
        end;
        result := nil;
    end;

    procedure addRecompiler(recompiler: StaticRecompiler);
    var
        r: StaticRecompiler_Array1d;
    begin
        r := RECOMPILERS;
        if RECOMPILERS_COUNT = length(r) then begin
            r := StaticRecompiler_Array1d_create(RECOMPILERS_COUNT * 2);
            arraycopy(RECOMPILERS, 0, r, 0, RECOMPILERS_COUNT);
            RECOMPILERS := r;
        end;
        r[RECOMPILERS_COUNT] := recompiler;
        inc(RECOMPILERS_COUNT);
    end;
{%endregion}

initialization {%region}
    RECOMPILERS_COUNT := 0;
    RECOMPILERS := StaticRecompiler_Array1d_create(1);
{%endregion}

end.

