{
EmulProgrammes содержит классы для хранения метаданных об установленных
на Малик Эмулятор программах.
Этот исходный текст является частью Малик Эмулятора.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Малик Эмулятор – свободная программа: вы можете перераспространять её и/или
изменять её на условиях Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Малик Эмулятор распространяется в надежде, что он может быть полезен,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
общественной лицензии GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
}
unit EmulProgrammes;
{$MODE DELPHI}
interface
uses
Classes,
Forms,
Graphics,
Lang,
FileIO,
Manifests,
EmulConstants;
{%region public }
type
ProgrammeInfo = class;
ProgrammeInfo_Array1d = packed array of ProgrammeInfo;
ProgrammeInfo = class(_Object)
strict private
debugInfoFileName: AnsiString;
executableFileName: AnsiString;
iconFileName: AnsiString;
manifestFileName: AnsiString;
programmeDirectory: AnsiString;
screenSizes: int;
exists: boolean;
procedure setScreenSizes(manifest: ProgrammeManifest); overload;
public
constructor create(const directory: AnsiString);
procedure saveManifest(manifest: ProgrammeManifest);
procedure loadManifest(manifest: ProgrammeManifest);
procedure loadIcon(icon: Graphics.TIcon);
procedure setScreenSizes(width, height: int); overload;
function resourceNameToFileName(const resName: AnsiString): AnsiString;
function getDebugInfoFileName(): AnsiString;
function getExecutableFileName(): AnsiString;
function getIconFileName(): AnsiString;
function getManifestFileName(): AnsiString;
function getProgrammeDirectory(): AnsiString;
function getScreenWidth(): int;
function getScreenHeight(): int;
function isDirectoryExists(): boolean;
public const
MANIFEST_FILE_NAME = 'META-INF' + DIRECTORY_SEPARATOR + 'MANIFEST.MF';
end;
{%endregion}
{%region routine }
function virtualFileNameToOSFileName(const fileName: AnsiString): AnsiString; overload;
function virtualFileNameToOSFileName(const fileName: UnicodeString): UnicodeString; overload;
function ProgrammeInfo_Array1d_create(length: int): ProgrammeInfo_Array1d;
procedure arraycopy(const src: ProgrammeInfo_Array1d; srcOffset: int; const dst: ProgrammeInfo_Array1d; dstOffset: int; length: int); overload;
{%endregion}
implementation
{%region routine }
function virtualFileNameToOSFileName(const fileName: AnsiString): AnsiString;
var
i: int;
begin
if (DIRECTORY_SEPARATOR <> '/') and (pos(DIRECTORY_SEPARATOR, fileName) > 0) then begin
result := copy(fileName, 1, length(fileName));
for i := 1 to length(result) do begin
if result[i] = '/' then begin
result[i] := DIRECTORY_SEPARATOR;
end;
end;
exit;
end;
result := fileName;
end;
function virtualFileNameToOSFileName(const fileName: UnicodeString): UnicodeString;
var
i: int;
begin
if (DIRECTORY_SEPARATOR <> '/') and (pos(DIRECTORY_SEPARATOR, fileName) > 0) then begin
result := copy(fileName, 1, length(fileName));
for i := 1 to length(result) do begin
if result[i] = '/' then begin
result[i] := DIRECTORY_SEPARATOR;
end;
end;
exit;
end;
result := fileName;
end;
function ProgrammeInfo_Array1d_create(length: int): ProgrammeInfo_Array1d;
begin
setLength(result, length);
end;
procedure arraycopy(const src: ProgrammeInfo_Array1d; srcOffset: int; const dst: ProgrammeInfo_Array1d; dstOffset: int; length: int);
var
lim: int;
len: 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;
move(src[srcOffset], dst[dstOffset], length * sizeof(_Object));
end;
{%endregion}
{%region ProgrammeInfo }
constructor ProgrammeInfo.create(const directory: AnsiString);
var
m: ProgrammeManifest;
e: AnsiString;
s: AnsiString;
begin
inherited create();
programmeDirectory := directory;
m := ProgrammeManifest.create();
try
manifestFileName := directory + MANIFEST_FILE_NAME;
exists := fileExists(manifestFileName);
if not exists then begin
exit;
end;
try
m.loadFromFile(manifestFileName);
except
exit;
end;
e := m.getValue(MANIFEST_PROPERTY_PROGRAMME_EXECUTABLE);
if (length(e) > 0) and (e[1] = '/') then begin
delete(e, 1, 1);
end;
e := virtualFileNameToOSFileName(e);
executableFileName := directory + e + '.mal';
s := m.getValue(MANIFEST_PROPERTY_PROGRAMME_ICON);
if length(s) > 0 then begin
if (length(s) > 0) and (s[1] = '/') then begin
delete(s, 1, 1);
end;
iconFileName := directory + virtualFileNameToOSFileName(s);
end else begin
iconFileName := directory + e + '.ico';
end;
debugInfoFileName := directory + e + '.dbg';
setScreenSizes(m);
finally
m.free();
end;
end;
procedure ProgrammeInfo.setScreenSizes(manifest: ProgrammeManifest);
var
sizesProperty: ProgrammeManifestProperty;
sizes: AnsiString_Array1d;
w: int;
h: int;
begin
sizesProperty := manifest.find(MANIFEST_PROPERTY_MALIK_SCREEN_SIZE);
if sizesProperty <> nil then begin
w := length(sizesProperty.getValue());
if (w >= 3) and (w < 9) then begin
sizes := sizesProperty.getValueComponents();
if length(sizes) = 2 then begin
w := parseDecInt(sizes[0], DEFAULT_SCREEN_WIDTH);
h := parseDecInt(sizes[1], DEFAULT_SCREEN_HEIGHT);
screenSizes := (h shl 16) + (w and $ffff);
exit;
end;
end;
end;
screenSizes := (DEFAULT_SCREEN_HEIGHT shl 16) + (DEFAULT_SCREEN_WIDTH and $ffff);
end;
procedure ProgrammeInfo.saveManifest(manifest: ProgrammeManifest);
begin
manifest.saveToFile(manifestFileName);
end;
procedure ProgrammeInfo.loadManifest(manifest: ProgrammeManifest);
begin
manifest.loadFromFile(manifestFileName);
end;
procedure ProgrammeInfo.loadIcon(icon: Graphics.TIcon);
var
hs: Classes.THandleStream;
begin
with FileInputStream.create(iconFileName) do begin
try
if isInvalidHandle() then begin
icon.assign(Forms.application.icon);
exit;
end;
hs := Classes.THandleStream.create(getHandle());
try
icon.loadFromStream(hs);
finally
hs.free();
end;
finally
free();
end;
end;
end;
procedure ProgrammeInfo.setScreenSizes(width, height: int);
begin
screenSizes := (height shl 16) + (width and $ffff);
end;
function ProgrammeInfo.resourceNameToFileName(const resName: AnsiString): AnsiString;
begin
if (length(resName) > 0) and (resName[1] = '/') then begin
result := programmeDirectory + virtualFileNameToOSFileName(copy(resName, 2, length(resName) - 1));
end else begin
result := programmeDirectory + virtualFileNameToOSFileName(resName);
end;
end;
function ProgrammeInfo.getDebugInfoFileName(): AnsiString;
begin
result := debugInfoFileName;
end;
function ProgrammeInfo.getExecutableFileName(): AnsiString;
begin
result := executableFileName;
end;
function ProgrammeInfo.getIconFileName(): AnsiString;
begin
result := iconFileName;
end;
function ProgrammeInfo.getManifestFileName(): AnsiString;
begin
result := manifestFileName;
end;
function ProgrammeInfo.getProgrammeDirectory(): AnsiString;
begin
result := programmeDirectory;
end;
function ProgrammeInfo.getScreenWidth(): int;
begin
result := screenSizes and $ffff;
end;
function ProgrammeInfo.getScreenHeight(): int;
begin
result := (screenSizes shr 16) and $ffff;
end;
function ProgrammeInfo.isDirectoryExists(): boolean;
begin
result := exists;
end;
{%endregion}
end.