333 lines
8.2 KiB
ObjectPascal
333 lines
8.2 KiB
ObjectPascal
unit unitResFile;
|
|
|
|
interface
|
|
|
|
uses Windows, Classes, SysUtils, ConTnrs, unitResourceDetails;
|
|
|
|
type
|
|
TResourceList = class (TResourceModule)
|
|
private
|
|
fResourceList : TObjectList;
|
|
protected
|
|
function GetResourceCount: Integer; override;
|
|
function GetResourceDetails(idx: Integer): TResourceDetails; override;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Assign (src : TResourceModule);
|
|
procedure InsertResource (idx : Integer; details : TResourceDetails); override;
|
|
procedure DeleteResource (idx : Integer); override;
|
|
function AddResource (details : TResourceDetails) : Integer; override;
|
|
function IndexOfResource (details : TResourceDetails) : Integer; override;
|
|
procedure SortResources; override;
|
|
end;
|
|
|
|
TResModule = class (TResourceList)
|
|
private
|
|
f16Bit : boolean;
|
|
procedure ParseResource(header, data: PChar; dataSize: Integer);
|
|
protected
|
|
public
|
|
procedure SaveToStream (stream : TStream); override;
|
|
procedure LoadFromStream (stream : TStream); override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TResModule }
|
|
|
|
procedure TResModule.ParseResource (header, data : PChar; dataSize : Integer);
|
|
var
|
|
p : PChar;
|
|
sName, sType : string;
|
|
res : TResourceDetails;
|
|
language, memoryFlags : word;
|
|
version, dataVersion, characteristics : DWORD;
|
|
|
|
function GetName : string;
|
|
begin
|
|
if PWord (p)^ = $ffff then
|
|
begin
|
|
Inc (p, sizeof (word));
|
|
result := IntToStr (PWord (p)^);
|
|
Inc (p, sizeof (word))
|
|
end
|
|
else
|
|
begin
|
|
result := WideString (PWideChar (p));
|
|
Inc (p, (Length (result) + 1) * sizeof (WideChar))
|
|
end
|
|
end;
|
|
|
|
begin
|
|
p := header;
|
|
Inc (p, 2 * sizeof (Integer));
|
|
sType := GetName;
|
|
sName := GetName;
|
|
|
|
if (Integer (p) mod 4) <> 0 then
|
|
Inc (p, 4 - Integer (p) mod 4);
|
|
|
|
dataVersion := PDWORD (p)^;
|
|
Inc (p, sizeof (DWORD));
|
|
memoryFlags := PWORD (p)^;
|
|
Inc (p, sizeof (word));
|
|
language := PWORD (p)^;
|
|
Inc (p, sizeof (word));
|
|
version := PDWORD (p)^;
|
|
Inc (p, sizeof (DWORD));
|
|
characteristics := PDWORD (p)^;
|
|
Inc (p, sizeof (DWORD));
|
|
|
|
if (dataSize <> 0) or (sName <> '0') then
|
|
begin
|
|
res := TResourceDetails.CreateResourceDetails (self, language, sName, sType, dataSize, data);
|
|
res.Characteristics := characteristics;
|
|
res.Version := version;
|
|
res.MemoryFlags := memoryFlags;
|
|
res.DataVersion := dataVersion;
|
|
AddResource (res)
|
|
end
|
|
else // NB!!! 32 bit .RES files start with a dummy '32-bit indicator'
|
|
// resource !!! Is this documented? I don't think so!
|
|
|
|
f16Bit := False;
|
|
end;
|
|
|
|
procedure TResModule.LoadFromStream(stream: TStream);
|
|
var
|
|
buffer, p, q : PChar;
|
|
bufLen, n, DataSize, HeaderSize, ChunkSize : Integer;
|
|
begin
|
|
bufLen := stream.Size;
|
|
GetMem (buffer, bufLen);
|
|
try
|
|
stream.ReadBuffer (buffer^, bufLen); // Read the entite file
|
|
|
|
p := buffer;
|
|
n := 0;
|
|
f16Bit := True;
|
|
// Parse each resource
|
|
while n + 2 * sizeof (Integer) < bufLen do
|
|
begin
|
|
DataSize := PInteger (p)^;
|
|
q := p;
|
|
Inc (q, SizeOf (Integer));
|
|
HeaderSize := PInteger (q)^;
|
|
q := p;
|
|
Inc (q, HeaderSize);
|
|
|
|
ParseResource (p, q, DataSize);
|
|
ChunkSize := DataSize + HeaderSize;
|
|
ChunkSize := ((ChunkSize + 3) div 4) * 4;
|
|
Inc (p, ChunkSize);
|
|
Inc (n, ChunkSize);
|
|
end;
|
|
|
|
finally
|
|
FreeMem (buffer)
|
|
end
|
|
end;
|
|
|
|
procedure TResModule.SaveToStream(stream: TStream);
|
|
var
|
|
res : TResourceDetails;
|
|
dataSize, headerSize, totalSize : Integer;
|
|
header : array [0..1023] of char;
|
|
i : Integer;
|
|
|
|
function GetResHeader (header : PChar) : DWORD;
|
|
var
|
|
pos : DWORD;
|
|
len, dw : DWORD;
|
|
w : word;
|
|
i : Integer;
|
|
ws : WideString;
|
|
begin
|
|
pos := 0;
|
|
ZeroMemory (header, 1024);
|
|
|
|
i := ResourceNameToInt (res.ResourceType);
|
|
if i = -1 then
|
|
begin
|
|
ws := res.ResourceType;
|
|
len := (Length (ws) + 1) * sizeof (WideChar);
|
|
Move (PWideChar (ws)^, header [pos], len);
|
|
Inc (pos, len)
|
|
end
|
|
else
|
|
begin
|
|
w := $ffff;
|
|
Move (w, header [pos], sizeof (w));
|
|
Inc (pos, sizeof (w));
|
|
|
|
w := Word (i);
|
|
Move (w, header [pos], sizeof (w));
|
|
Inc (pos, sizeof (w))
|
|
end;
|
|
|
|
i := ResourceNameToInt (res.ResourceName);
|
|
if i = -1 then
|
|
begin
|
|
ws := res.ResourceName;
|
|
len := (Length (ws) + 1) * sizeof (WideChar);
|
|
Move (PWideChar (ws)^, header [pos], len);
|
|
Inc (pos, len)
|
|
end
|
|
else
|
|
begin
|
|
w := $ffff;
|
|
Move (w, header [pos], sizeof (w));
|
|
Inc (pos, sizeof (w));
|
|
|
|
w := Word (i);
|
|
Move (w, header [pos], sizeof (w));
|
|
Inc (pos, sizeof (w))
|
|
end;
|
|
|
|
if (pos mod 4) <> 0 then
|
|
Inc (pos, 4 - (pos mod 4));
|
|
|
|
dw := res.DataVersion;
|
|
Move (dw, header [pos], sizeof (DWORD));
|
|
Inc (pos, sizeof (DWORD));
|
|
|
|
w := res.MemoryFlags;
|
|
Move (w, header [pos], sizeof (WORD));
|
|
Inc (pos, sizeof (WORD));
|
|
|
|
w := res.ResourceLanguage;
|
|
Move (w, header [pos], sizeof (WORD));
|
|
Inc (pos, sizeof (WORD));
|
|
|
|
dw := res.Version;
|
|
Move (dw, header [pos], sizeof (DWORD));
|
|
Inc (pos, sizeof (DWORD));
|
|
|
|
dw := res.Characteristics;
|
|
Move (dw, header [pos], sizeof (DWORD));
|
|
Inc (pos, sizeof (DWORD));
|
|
result := pos;
|
|
end;
|
|
|
|
begin
|
|
if not f16Bit then // Write 32-bit resource indicator (An empty type 0 resource)
|
|
begin
|
|
res := TResourceDetails.CreateNew (nil, 0, '0');
|
|
try
|
|
dataSize := res.Data.Size;
|
|
|
|
stream.WriteBuffer (dataSize, sizeof (dataSize));
|
|
headerSize := GetResHeader (header);
|
|
|
|
totalSize := headerSize + 2 * sizeof (DWORD);
|
|
|
|
stream.WriteBuffer (totalSize, sizeof (headerSize));
|
|
stream.WriteBuffer (header, headerSize);
|
|
finally
|
|
res.Free
|
|
end
|
|
end;
|
|
|
|
dataSize := 0;
|
|
if ResourceCount > 0 then
|
|
for i := 0 to ResourceCount - 1 do
|
|
begin
|
|
res := ResourceDetails [i];
|
|
dataSize := res.Data.Size;
|
|
|
|
stream.WriteBuffer (dataSize, sizeof (dataSize));
|
|
headerSize := GetResHeader (header);
|
|
|
|
totalSize := headerSize + 2 * sizeof (DWORD);
|
|
|
|
stream.WriteBuffer (totalSize, sizeof (headerSize));
|
|
stream.WriteBuffer (header, headerSize);
|
|
stream.WriteBuffer (res.Data.Memory^, dataSize);
|
|
|
|
totalSize := dataSize + totalSize;
|
|
ZeroMemory (@header, sizeof (header));
|
|
|
|
if (totalSize mod 4) <> 0 then
|
|
stream.WriteBuffer (header, 4 - (totalSize mod 4));
|
|
end
|
|
end;
|
|
|
|
{ TResourceList }
|
|
|
|
function TResourceList.AddResource(details: TResourceDetails): Integer;
|
|
begin
|
|
Result := fResourceList.Add (details);
|
|
end;
|
|
|
|
procedure TResourceList.Assign(src: TResourceModule);
|
|
var
|
|
i : Integer;
|
|
res : TResourceDetails;
|
|
begin
|
|
fResourceList.Clear;
|
|
|
|
for i := 0 to src.ResourceCount - 1 do
|
|
begin
|
|
res := TResourceDetails.CreateResourceDetails (
|
|
Self,
|
|
src.ResourceDetails [i].ResourceLanguage,
|
|
src.ResourceDetails [i].ResourceName,
|
|
src.ResourceDetails [i].ResourceType,
|
|
src.ResourceDetails [i].Data.Size,
|
|
src.ResourceDetails [i].Data.Memory);
|
|
|
|
fResourceList.Add (res)
|
|
end
|
|
end;
|
|
|
|
constructor TResourceList.Create;
|
|
begin
|
|
fResourceList := TObjectList.Create;
|
|
end;
|
|
|
|
procedure TResourceList.DeleteResource(idx: Integer);
|
|
var
|
|
res : TResourceDetails;
|
|
begin
|
|
res := ResourceDetails [idx];
|
|
inherited;
|
|
idx := IndexOfResource (Res);
|
|
if idx <> -1 then
|
|
fResourceList.Delete (idx)
|
|
end;
|
|
|
|
destructor TResourceList.Destroy;
|
|
begin
|
|
fResourceList.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TResourceList.GetResourceCount: Integer;
|
|
begin
|
|
result := fResourceList.Count
|
|
end;
|
|
|
|
function TResourceList.GetResourceDetails(idx: Integer): TResourceDetails;
|
|
begin
|
|
result := TResourceDetails (fResourceList [idx])
|
|
end;
|
|
|
|
function TResourceList.IndexOfResource(details: TResourceDetails): Integer;
|
|
begin
|
|
result := fResourceList.IndexOf (details)
|
|
end;
|
|
|
|
procedure TResourceList.InsertResource(idx: Integer;
|
|
details: TResourceDetails);
|
|
begin
|
|
fResourceList.Insert (idx, details)
|
|
end;
|
|
|
|
procedure TResourceList.SortResources;
|
|
begin
|
|
fResourceList.Sort (compareDetails);
|
|
end;
|
|
|
|
end.
|