program ResourceExtractor;
{$ifdef FPC}
{$mode delphi}{$H+}
{$endif}
uses
Classes,
SysUtils,
StrUtils;
var
ResCount: integer;
OutStream: TStringList;
procedure Init();
begin
OutStream := TStringList.Create();
OutStream.Add('const');
// placeholder for array-header (will be filled on file-saving)
OutStream.Add('');
end;
procedure SaveToFile(const OutFileName: string);
begin
// add array-header
OutStream[1] := ' resources: array[0..'+IntToStr(ResCount-1)+', 0..2] of string = (';
// add trailer
OutStream.Add(' );');
// save file
try
OutStream.SaveToFile(OutFileName);
except
OutStream.Free();
raise Exception.Create('Could not save to file: "' + OutFileName + '"');
end;
OutStream.Free();
end;
function AddResource(Fields: TStringList; const RCFileDir, ResDir: string): boolean;
var
ResName, ResType, ResFile: string;
begin
if (Fields.Count < 3) or
(AnsiStartsStr('//', Fields[0])) or
(Length(Fields[2]) < 3) then
begin
Result := false;
Exit;
end;
// add a trailing comma to the last line
if (ResCount > 0) then
OutStream[OutStream.Count-1] := OutStream[OutStream.Count-1] + ',';
ResName := Fields[0];
ResType := Fields[1];
ResFile := Fields[2];
Writeln('ADD: [' + ResType + ':' + ResName + ' = ' +ResFile + ']');
// quote fields
ResName := AnsiQuotedStr(ResName, '''')+',';
ResType := AnsiQuotedStr(ResType, '''')+',';
// strip surrounding quotes of filename
ResFile := AnsiMidStr(ResFile, 2, Length(Fields[2])-2);
// now translate the resource filename (relative to the RC-file) to be relative to the resource-dir
// 1st step: get absolute path of the resource
ResFile := ExpandFileName(RCFileDir + ResFile);
// 2nd step: get path of the resource relative to the resource-dir
// Note: both paths must be absolute and the base-path must have a trailing '/' or '\'
ResFile := ExtractRelativepath(ResDir, ResFile);
// 3rd step: ... and quote
ResFile := AnsiQuotedStr(ResFile, '''');
// compose line
OutStream.Add(Format(' (%-20S%-8S%S)', [ResName, ResType, ResFile]));
Inc(ResCount);
Result := true;
end;
procedure ExtractResources(const InFileName, ResDir: string);
var
Fields: TStringList;
LineIndex: integer;
Lines: TStringList;
RCFileDirAbs, ResDirAbs: string;
begin
// get absolute paths
RCFileDirAbs := ExtractFilePath(ExpandFileName(InFileName));
ResDirAbs := ExpandFileName(ResDir) + '/';
Lines := TStringList.Create();
try
Lines.LoadFromFile(InFileName);
except
raise Exception.Create('Failed to open file: "' + InFileName + '"');
end;
Fields := TStringList.Create();
for LineIndex := 0 to Lines.Count-1 do
begin
Fields.Clear();
// split line into [Name, Type, File]
ExtractStrings([' ', #9], [], PChar(Lines[LineIndex]), Fields);
if (not AddResource(Fields, RCFileDirAbs, ResDirAbs)) then
Writeln( 'SKIP: "'+Lines[LineIndex]+'"');
end;
Lines.Free();
Fields.Free();
end;
var
ProgName: string;
begin
if (ParamCount <> 3) then
begin
ProgName := ExtractFileName(ParamStr(0));
WriteLn('Usage: ' + ProgName + ' RC-File Resource-Dir Output-File');
Exit;
end;
WriteLn('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
WriteLn('Converting "' + ParamStr(1) + '" to "' + ParamStr(3) + '"');
WriteLn('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
try
Init();
ExtractResources(ParamStr(1), ParamStr(2));
SaveToFile(ParamStr(3));
except on E:Exception do
begin
WriteLn('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
WriteLn('Conversion failed: ' + E.Message + '!');
WriteLn('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
Exit;
end;
end;
WriteLn('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<');
WriteLn('Conversion finished!');
WriteLn('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<');
end.