Files
kam-mobile/code/ProbeAssets.pas
T

55 lines
2.3 KiB
ObjectPascal
Raw Normal View History

2026-09-11 18:18:40 +05:00
unit ProbeAssets;
{$mode objfpc}{$H+}
interface
uses ProbeReport;
function PrepareOptionalAssets(Report:TProbeReport;const WorkDir:string):string;
implementation
uses Classes,SysUtils,fpjson,jsonparser,CastleDownload,CastleFilesUtils;
function SafeRelative(const S:string):Boolean;
var Parts:TStringList; I:Integer;
begin
Result:=False;
if (S='') or (S[1]='/') or (Pos('\',S)>0) or (Pos(':',S)>0)
or (Pos(#0,S)>0) or (Pos(#10,S)>0) or (Pos(#13,S)>0) then Exit;
Parts:=TStringList.Create;
try
Parts.StrictDelimiter:=True;Parts.Delimiter:='/';Parts.DelimitedText:=S;
for I:=0 to Parts.Count-1 do
if (Parts[I]='') or (Parts[I]='.') or (Parts[I]='..') then Exit;
Result:=True;
finally Parts.Free;end;
end;
function PrepareOptionalAssets(Report:TProbeReport;const WorkDir:string):string;
var Manifest:TJSONData; Files:TJSONArray; I:Integer; Rel,Name,Url:string;
Src:TStream;Dst:TFileStream;Count,Expected:Int64;
begin
Result:=IncludeTrailingPathDelimiter(WorkDir)+'game/';
Manifest:=GetJSON(FileToString('castle-data:/assets-manifest.json'));
try
Files:=TJSONObject(Manifest).Arrays['files'];
if Files.Count=0 then begin
Report.Add('assets.native_adapter','NOT_RUN','No game resources supplied; code-only build is expected');
Exit;
end;
Count:=0;
for I:=0 to Files.Count-1 do begin
Rel:=Files.Objects[I].Strings['path'];
if not SafeRelative(Rel) then raise Exception.Create('Unsafe asset name: '+Rel);
Name:=Result+Rel; Url:=Files.Objects[I].Strings['url'];
if Pos('castle-data:/game/',Url)<>1 then raise Exception.Create('Unsupported asset URL');
Expected:=Files.Objects[I].Int64s['size'];
if not ForceDirectories(ExtractFileDir(Name)) then raise Exception.Create('Cannot create asset directory');
Src:=Download(Url);
try
Dst:=TFileStream.Create(Name,fmCreate);
try
Dst.CopyFrom(Src,0);
if Dst.Size<>Expected then raise Exception.Create('Size mismatch: '+Rel);
Count:=Count+Dst.Size;
finally Dst.Free;end;
finally Src.Free;end;
end;
Report.Add('assets.native_adapter','PASS',Format('%d files, %d bytes copied to native paths; formats unchanged; NOT full loader proof',[Files.Count,Count]));
finally Manifest.Free;end;
end;
end.