mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-05 17:17:52 +02:00
395 lines
11 KiB
ObjectPascal
395 lines
11 KiB
ObjectPascal
{
|
|
***************************************************************************
|
|
* *
|
|
* This source is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This code is distributed in the hope that it will be useful, but *
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* General Public License for more details. *
|
|
* *
|
|
* A copy of the GNU General Public License is available on the World *
|
|
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
|
|
* obtain it by writing to the Free Software Foundation, *
|
|
* Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. *
|
|
* *
|
|
***************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
Name:
|
|
lazres - creates an lazarus resource file from files
|
|
|
|
Synopsis:
|
|
lazres resourcefilename filename1 [filename2 ... filenameN]
|
|
lazres resourcefilename @filelist
|
|
|
|
Description:
|
|
lazres creates a lazarus resource file from files.
|
|
|
|
}
|
|
program LazRes;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
{$IF FPC_FULLVERSION>=30301}
|
|
{$WARN 6058 off : Call to subroutine "$1" marked as inline is not inlined}
|
|
{$ENDIF}
|
|
|
|
uses
|
|
Classes, SysUtils, LazLoggerBase, LResources, resource, reswriter,
|
|
bitmapresource, groupresource, groupiconresource, groupcursorresource,
|
|
LazFileUtils, LazUTF8;
|
|
|
|
type
|
|
TOutputFileType = (ftLrs, ftRc, ftRes);
|
|
|
|
procedure ConvertFormToText(Stream: TMemoryStream);
|
|
var
|
|
TextStream: TMemoryStream;
|
|
begin
|
|
try
|
|
try
|
|
TextStream := TMemoryStream.Create;
|
|
FormDataToText(Stream, TextStream);
|
|
TextStream.Position := 0;
|
|
Stream.Clear;
|
|
Stream.CopyFrom(TextStream, TextStream.Size);
|
|
Stream.Position := 0;
|
|
except
|
|
on E: Exception do
|
|
begin
|
|
debugln('ERROR: unable to convert Delphi form to text: '+E.Message);
|
|
end;
|
|
end;
|
|
finally
|
|
TextStream.Free;
|
|
end;
|
|
end;
|
|
|
|
// lrs generation
|
|
|
|
procedure OutputLRSFile(BinFilename, ResourceName: String; ResMemStream: TMemoryStream);
|
|
var
|
|
BinExt,ResourceType: String;
|
|
BinFileStream: TFileStream;
|
|
BinMemStream: TMemoryStream;
|
|
begin
|
|
dbgout(BinFilename);
|
|
try
|
|
BinFileStream:=TFileStream.Create(BinFilename,fmOpenRead);
|
|
BinMemStream:=TMemoryStream.Create;
|
|
try
|
|
BinMemStream.CopyFrom(BinFileStream,BinFileStream.Size);
|
|
BinMemStream.Position:=0;
|
|
BinExt:=uppercase(ExtractFileExt(BinFilename));
|
|
if (BinExt='.LFM') or (BinExt='.DFM') or (BinExt='.XFM')
|
|
then begin
|
|
ResourceType:='FORMDATA';
|
|
ConvertFormToText(BinMemStream);
|
|
ResourceName:=FindLFMClassName(BinMemStream);
|
|
if ResourceName='' then begin
|
|
debugln(' ERROR: no resourcename');
|
|
halt(2);
|
|
end;
|
|
dbgout(' ResourceName=''', ResourceName, ''' Type=''', ResourceType, '''');
|
|
LFMtoLRSstream(BinMemStream,ResMemStream);
|
|
end
|
|
else begin
|
|
ResourceType := trim(copy(BinExt,2,length(BinExt)-1));
|
|
if ResourceName='' then begin
|
|
ResourceName := ExtractFileName(BinFilename);
|
|
ResourceName := trim(copy(ResourceName,1
|
|
,length(ResourceName)-length(BinExt)));
|
|
end;
|
|
if ResourceName='' then begin
|
|
debugln(' ERROR: no resourcename');
|
|
halt(2);
|
|
end;
|
|
dbgout(' ResourceName=''', ResourceName, ''' Type=''', ResourceType+'''');
|
|
BinaryToLazarusResourceCode(BinMemStream,ResMemStream
|
|
,ResourceName,ResourceType);
|
|
end;
|
|
finally
|
|
BinFileStream.Free;
|
|
BinMemStream.Free;
|
|
end;
|
|
except
|
|
debugln(' ERROR: unable to read file ''', BinFilename, '''');
|
|
halt(3);
|
|
end;
|
|
debugln('');
|
|
end;
|
|
|
|
// rc generation
|
|
|
|
procedure OutputRCFile(FileName, ResourceName: String; ResMemStream: TMemoryStream);
|
|
|
|
procedure WriteResource(ResourceType: String);
|
|
var
|
|
S: String;
|
|
begin
|
|
S := Format('%s %s "%s"'#$D#$A, [ResourceName, ResourceType, FileName]);
|
|
ResMemStream.Write(PChar(@S[1])^, Length(S));
|
|
end;
|
|
|
|
var
|
|
FileExt: String;
|
|
begin
|
|
FileExt := UpperCase(ExtractFileExt(FileName));
|
|
if ResourceName = '' then
|
|
begin
|
|
ResourceName := ExtractFileName(FileName);
|
|
ResourceName := Trim(Copy(ResourceName, 1, Length(ResourceName) - Length(FileExt)));
|
|
end;
|
|
case FileExt of
|
|
'.BMP': WriteResource('BITMAP');
|
|
'.CUR': WriteResource('CURSOR');
|
|
'.ICO': WriteResource('ICON');
|
|
else
|
|
WriteResource('RCDATA');
|
|
end;
|
|
end;
|
|
|
|
// Res generation
|
|
type
|
|
TGroupResourceClass = class of TGroupResource;
|
|
|
|
procedure AddResource(FileName, ResourceName: String; Resources: TResources);
|
|
var
|
|
FileExt: String;
|
|
|
|
function GetResourceStream: TMemoryStream;
|
|
var
|
|
FS: TFileStream;
|
|
begin
|
|
FS := TFileStream.Create(FileName, fmOpenRead);
|
|
Result := TMemoryStream.Create;
|
|
try
|
|
Result.CopyFrom(FS, FS.Size);
|
|
Result.Position:=0;
|
|
if (FileExt = '.LFM') or (FileExt = '.DFM') or (FileExt = '.XFM') or (FileExt = '.FMX') then
|
|
begin
|
|
ConvertFormToText(Result);
|
|
ResourceName := FindLFMClassName(Result);
|
|
if ResourceName = '' then
|
|
begin
|
|
debugln(' ERROR: no resourcename');
|
|
halt(2);
|
|
end;
|
|
end
|
|
finally
|
|
FS.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure AddBitmapResource;
|
|
var
|
|
Desc: TResourceDesc;
|
|
Res: TBitmapResource;
|
|
ResStream: TStream;
|
|
begin
|
|
Desc := TResourceDesc.Create(ResourceName);
|
|
Res := TBitmapResource.Create(nil, Desc);
|
|
Desc.Free;
|
|
ResStream := GetResourceStream;
|
|
try
|
|
if Assigned(ResStream) then
|
|
Res.BitmapData.CopyFrom(ResStream, ResStream.Size)
|
|
else
|
|
Res.BitmapData.Size:=0;
|
|
finally
|
|
ResStream.Free;
|
|
end;
|
|
Resources.Add(Res);
|
|
dbgout(' ResourceName=''', ResourceName, ''' Type=RT_BITMAP');
|
|
end;
|
|
|
|
procedure AddGroupResource(GroupResourceClass: TGroupResourceClass);
|
|
var
|
|
Desc: TResourceDesc;
|
|
Res: TGroupResource;
|
|
ResStream: TStream;
|
|
begin
|
|
Desc := TResourceDesc.Create(ResourceName);
|
|
Res := GroupResourceClass.Create(nil, Desc);
|
|
Desc.Free;
|
|
ResStream := GetResourceStream;
|
|
try
|
|
if Assigned(ResStream) then
|
|
Res.ItemData.CopyFrom(ResStream, ResStream.Size)
|
|
else
|
|
Res.ItemData.Size:=0;
|
|
finally
|
|
ResStream.Free;
|
|
end;
|
|
Resources.Add(Res);
|
|
if Res._Type.ID = RT_GROUP_ICON then
|
|
dbgout(' ResourceName=''', ResourceName, ''' Type=RT_GROUP_ICON')
|
|
else
|
|
dbgout(' ResourceName=''', ResourceName, ''' Type=RT_GROUP_CURSOR');
|
|
end;
|
|
|
|
procedure AddRCDataResource;
|
|
var
|
|
TypeDesc, NameDesc: TResourceDesc;
|
|
Res: TGenericResource;
|
|
ResStream: TStream;
|
|
begin
|
|
TypeDesc := TResourceDesc.Create(RT_RCDATA);
|
|
NameDesc := TResourceDesc.Create(ResourceName);
|
|
Res := TGenericResource.Create(TypeDesc, NameDesc);
|
|
TypeDesc.Free;
|
|
NameDesc.Free;
|
|
ResStream := GetResourceStream;
|
|
try
|
|
if Assigned(ResStream) then
|
|
Res.RawData.CopyFrom(ResStream, ResStream.Size)
|
|
else
|
|
Res.RawData.Size:=0;
|
|
finally
|
|
ResStream.Free;
|
|
end;
|
|
Resources.Add(Res);
|
|
dbgout(' ResourceName=''', ResourceName, ''' Type=RT_RCDATA');
|
|
end;
|
|
|
|
begin
|
|
dbgout(FileName);
|
|
FileExt := UpperCase(ExtractFileExt(FileName));
|
|
if ResourceName = '' then
|
|
begin
|
|
ResourceName := ExtractFileName(FileName);
|
|
ResourceName := Trim(Copy(ResourceName, 1, Length(ResourceName) - Length(FileExt)));
|
|
end;
|
|
case FileExt of
|
|
'.BMP': AddBitmapResource;
|
|
'.CUR': AddGroupResource(TGroupCursorResource);
|
|
'.ICO': AddGroupResource(TGroupIconResource);
|
|
else
|
|
AddRCDataResource;
|
|
end;
|
|
debugln('');
|
|
end;
|
|
|
|
procedure OutputResFile(FileList: TStringList; ResMemStream: TMemoryStream);
|
|
var
|
|
Writer: TResResourceWriter;
|
|
Resources: TResources;
|
|
I: Integer;
|
|
begin
|
|
Resources := TResources.Create;
|
|
Writer := TResResourceWriter.Create;
|
|
try
|
|
for I := 0 to FileList.Count - 1 do
|
|
AddResource(FileList.Names[I], Trim(FileList.ValueFromIndex[I]), Resources);
|
|
Resources.WriteToStream(ResMemStream, Writer);
|
|
finally
|
|
Writer.Free;
|
|
Resources.Free;;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
a: Integer;
|
|
ResourceFilename,FullResourceFilename:String;
|
|
ResFileStream:TFileStream;
|
|
ResMemStream:TMemoryStream;
|
|
FileList:TStringList;
|
|
S: String;
|
|
OutputFileType: TOutputFileType;
|
|
begin
|
|
if ParamCount<2 then begin
|
|
debugln('Usage: ',ExtractFileName(ParamStrUTF8(0))
|
|
,' resourcefilename filename1[=resname1] [filename2[=resname2] ... filenameN=resname[N]]');
|
|
debugln(' ',ExtractFileName(ParamStrUTF8(0))
|
|
,' resourcefilename @filelist');
|
|
exit;
|
|
end;
|
|
FileList:=TStringList.Create;
|
|
try
|
|
if ParamStrUTF8(2)[1] = '@' then
|
|
begin
|
|
S := ParamStrUTF8(2);
|
|
Delete(S, 1, 1);
|
|
S := ExpandFileNameUTF8(S);
|
|
if not FileExistsUTF8(S) then
|
|
begin
|
|
debugln('ERROR: file list not found: ',S);
|
|
exit;
|
|
end;
|
|
FileList.LoadFromFile(S);
|
|
for a:=FileList.Count-1 downto 0 do
|
|
if FileList[a]='' then
|
|
FileList.Delete(a);
|
|
end
|
|
else for a:=2 to ParamCount do FileList.Add(ParamStrUTF8(a));
|
|
// cleanup lines
|
|
for a:=fileList.Count-1 downto 0 do begin
|
|
s := Trim(filelist[a]);
|
|
if (s='') or (s[1]='#') then begin
|
|
filelist.Delete(a);
|
|
continue;
|
|
end;
|
|
filelist[a] := s;
|
|
if filelist.Names[a]='' then
|
|
filelist[a] := filelist[a] + '=';
|
|
end;
|
|
ResourceFilename := ParamStrUTF8(1);
|
|
FullResourceFilename := ExpandFileNameUTF8(ResourceFilename);
|
|
// check that all resources exists and are not the destination file
|
|
for a:=0 to FileList.Count-1 do begin
|
|
S := FileList.Names[a];
|
|
if not FileExistsUTF8(S)
|
|
then begin
|
|
debugln('ERROR: file not found: ', S);
|
|
exit;
|
|
end;
|
|
if ExpandFileNameUTF8(S) = FullResourceFilename
|
|
then begin
|
|
debugln(['ERROR: resourcefilename = file', a]);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
try
|
|
ResFileStream:=TFileStream.Create(ResourceFilename,fmCreate);
|
|
except
|
|
debugln('ERROR: unable to create file ''', ResourceFilename, '''');
|
|
halt(1);
|
|
end;
|
|
case LowerCase(ExtractFileExt(ResourceFilename)) of
|
|
'.rc': OutputFileType := ftRc;
|
|
'.res': OutputFileType := ftRes;
|
|
else
|
|
OutputFileType := ftLrs;
|
|
end;
|
|
ResMemStream := TMemoryStream.Create;
|
|
try
|
|
if OutputFileType in [ftRc, ftLrs] then
|
|
begin
|
|
for a := 0 to FileList.Count - 1 do
|
|
begin
|
|
if OutputFileType = ftRc then
|
|
OutputRCFile(FileList.Names[a], trim(FileList.ValueFromIndex[a]), ResMemStream)
|
|
else
|
|
OutputLRSFile(FileList.Names[a], trim(FileList.ValueFromIndex[a]), ResMemStream);
|
|
end;
|
|
end
|
|
else
|
|
OutputResFile(FileList, ResMemStream);
|
|
ResMemStream.Position := 0;
|
|
ResFileStream.CopyFrom(ResMemStream, ResMemStream.Size);
|
|
finally
|
|
ResMemStream.Free;
|
|
ResFileStream.Free;
|
|
end;
|
|
finally
|
|
FileList.Free;
|
|
end;
|
|
end.
|
|
|