datalock/UPayload.pas

183 lines
3.8 KiB
Plaintext

unit UPayload;
{$MODE Delphi}
interface
type
TPayload = class(TObject)
private
fFileName: string;
fOldFileMode: Integer;
fFile: File;
procedure Open(Mode: Integer);
procedure Close;
public
constructor Create(const FileName: string);
function HasPayload: Boolean;
function PayloadSize: Integer;
procedure SetPayload(const Data; const DataSize: Integer);
procedure GetPayload(var Data);
procedure RemovePayload;
end;
implementation
uses
ActiveX;
type
TPayloadFooter = packed record
WaterMark: TGUID;
ExeSize: LongInt;
DataSize: LongInt;
end;
const
cWaterMarkGUID: TGUID =
'{9FABA105-EDA8-45C3-89F4-369315A947EB}';
cReadOnlyMode = 0;
cReadWriteMode = 2;
procedure InitFooter(out Footer: TPayloadFooter);
begin
FillChar(Footer, SizeOf(Footer), 0);
Footer.WaterMark := cWaterMarkGUID;
end;
function ReadFooter(var F: File;
out Footer: TPayloadFooter): Boolean;
var
FileLen: Integer;
begin
// Check that file is large enough for a footer!
FileLen := FileSize(F);
if FileLen > SizeOf(Footer) then
begin
// Big enough: move to start of footer and read it
Seek(F, FileLen - SizeOf(Footer));
BlockRead(F, Footer, SizeOf(Footer));
end
else
// File not large enough for footer: zero it
// .. this ensures watermark is invalid
FillChar(Footer, SizeOf(Footer), 0);
// Return if watermark is valid
Result := IsEqualGUID(Footer.WaterMark, cWaterMarkGUID);
end;
procedure TPayload.Close;
begin
// close file and restores previous file mode
CloseFile(fFile);
FileMode := fOldFileMode;
end;
constructor TPayload.Create(const FileName: string);
begin
inherited Create;
fFileName := FileName;
end;
procedure TPayload.GetPayload(var Data);
var
Footer: TPayloadFooter;
begin
// open file as read only
Open(cReadOnlyMode);
try
// read footer
if ReadFooter(fFile, Footer)
and (Footer.DataSize > 0) then
begin
// move to end of exe code and read data
Seek(fFile, Footer.ExeSize);
BlockRead(fFile, Data, Footer.DataSize);
end;
finally
// close file
Close;
end;
end;
function TPayload.HasPayload: Boolean;
begin
// we have a payload if size is greater than 0
Result := PayloadSize > 0;
end;
procedure TPayload.Open(Mode: Integer);
begin
// open file with given mode, recording current one
fOldFileMode := FileMode;
AssignFile(fFile, fFileName);
FileMode := Mode;
Reset(fFile, 1);
end;
function TPayload.PayloadSize: Integer;
var
Footer: TPayloadFooter;
begin
// open file and assume no data
Result := 0;
Open(cReadOnlyMode);
try
// read footer and if valid return data size
if ReadFooter(fFile, Footer) then
Result := Footer.DataSize;
finally
Close;
end;
end;
procedure TPayload.RemovePayload;
var
PLSize: Integer;
FileLen: Integer;
begin
// get size of payload
PLSize := PayloadSize;
if PLSize > 0 then
begin
// we have payload: open file and get size
Open(cReadWriteMode);
FileLen := FileSize(fFile);
try
// seek to end of exec code an truncate file there
Seek(fFile, FileLen - PLSize - SizeOf(TPayloadFooter));
Truncate(fFile);
finally
Close;
end;
end;
end;
procedure TPayload.SetPayload(const Data;
const DataSize: Integer);
var
Footer: TPayloadFooter;
begin
// remove any existing payload
RemovePayload;
if DataSize > 0 then
begin
// we have some data: open file for writing
Open(cReadWriteMode);
try
// create a new footer with required data
InitFooter(Footer);
Footer.ExeSize := FileSize(fFile);
Footer.DataSize := DataSize;
// write data and footer at end of exe code
Seek(fFile, Footer.ExeSize);
BlockWrite(fFile, Data, DataSize);
BlockWrite(fFile, Footer, SizeOf(Footer));
finally
Close;
end;
end;
end;
end.