patternMinor
Efficient binary patcher
Viewed 0 times
patcherefficientbinary
Problem
I am currently working on a little binary patcher. My current code works fine but I do want my code to be optimized (fast) and as clean as possible. Could you all please help me review this?
IDE: Delphi 7 and XE7
```
const
OriginalByte: array [0 .. 55] of Byte = ($64, $69, $6E, $67, $20, $6D, $65,
$20, $68, $69, $73, $00, $00, $00, $00, $27, $00, $00, $28, $00, $00, $00,
$21, $00, $00, $00, $63, $6F, $6D, $70, $75, $74, $65, $72, $2E, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $27, $00, $00, $28,
$00, $00, $00, $00);
BytetoWrite: array [0 .. 55] of Byte = ($63, $68, $6F, $67, $20, $6D, $65,
$20, $68, $69, $73, $00, $00, $00, $00, $27, $00, $00, $28, $00, $00, $00,
$21, $00, $00, $00, $63, $6F, $6D, $70, $75, $74, $65, $72, $2E, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $27, $00, $00, $28,
$00, $00, $00, $06);
function CompareByteArrays(FirstArray, SecondArray: array of Byte): Boolean;
var
Counter: Integer;
begin
Result := True;
if Length(FirstArray) <> Length(SecondArray) then
begin
Result := False;
Exit;
end;
for Counter := Low(FirstArray) to High(FirstArray) do
begin
if (FirstArray[Counter]) <> (SecondArray[Counter]) then
begin
Result := False;
Exit;
end
end;
end;
procedure DoMyPatch();
var
i: Integer;
FileName: string;
input: TFileStream;
FileByteArray, ExtractedByteArray: array of Byte;
begin
FileName := 'Cute1.res';
try
input := TFileStream.Create(FileName, fmOpenReadWrite);
except
on E: Exception do
begin
ShowMessage(E.Message);
Exit;
end
end;
input.Position := 0;
SetLength(FileByteArray, input.size);
input.Read(FileByteArray[0], Length(FileByteArray));
for i := Low(FileByteArray) to High(FileByteArray) do
begin
ExtractedByteArray := Copy(FileByteArray, i, Length(OriginalByte));
if CompareByteArrays(ExtractedByteArray, OriginalByte) = True then
begin
IDE: Delphi 7 and XE7
```
const
OriginalByte: array [0 .. 55] of Byte = ($64, $69, $6E, $67, $20, $6D, $65,
$20, $68, $69, $73, $00, $00, $00, $00, $27, $00, $00, $28, $00, $00, $00,
$21, $00, $00, $00, $63, $6F, $6D, $70, $75, $74, $65, $72, $2E, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $27, $00, $00, $28,
$00, $00, $00, $00);
BytetoWrite: array [0 .. 55] of Byte = ($63, $68, $6F, $67, $20, $6D, $65,
$20, $68, $69, $73, $00, $00, $00, $00, $27, $00, $00, $28, $00, $00, $00,
$21, $00, $00, $00, $63, $6F, $6D, $70, $75, $74, $65, $72, $2E, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $27, $00, $00, $28,
$00, $00, $00, $06);
function CompareByteArrays(FirstArray, SecondArray: array of Byte): Boolean;
var
Counter: Integer;
begin
Result := True;
if Length(FirstArray) <> Length(SecondArray) then
begin
Result := False;
Exit;
end;
for Counter := Low(FirstArray) to High(FirstArray) do
begin
if (FirstArray[Counter]) <> (SecondArray[Counter]) then
begin
Result := False;
Exit;
end
end;
end;
procedure DoMyPatch();
var
i: Integer;
FileName: string;
input: TFileStream;
FileByteArray, ExtractedByteArray: array of Byte;
begin
FileName := 'Cute1.res';
try
input := TFileStream.Create(FileName, fmOpenReadWrite);
except
on E: Exception do
begin
ShowMessage(E.Message);
Exit;
end
end;
input.Position := 0;
SetLength(FileByteArray, input.size);
input.Read(FileByteArray[0], Length(FileByteArray));
for i := Low(FileByteArray) to High(FileByteArray) do
begin
ExtractedByteArray := Copy(FileByteArray, i, Length(OriginalByte));
if CompareByteArrays(ExtractedByteArray, OriginalByte) = True then
begin
Solution
Some notes:
-
using
pattern is easy to follow and it prevents unintended memory leaks nicely
-
you can get some speed by comparing against the original byte array just offset by the
assuming the
- add definition of the undeclared variables
BytetoWrite,OriginalByteand how they are used/initialized
- format your code for better readability. Left indentation is not aligned. Too many void blank lines
-
using
resource := CreateResource;
try
// do something
finally
FreeAndNil(resource);
endpattern is easy to follow and it prevents unintended memory leaks nicely
- for byte-to-byte memory compare in
CompareByteArraysbetter use built-inCompareMemfunction instead of custom array traversal. In an old language runtime source codes this function was implemented in optimized assembly language
- using
Integerfor file-offset is not very future-friendly idea considering that it is normal (for average end-user) today to work with video files in 4K resolution where single file size can be >4GB
- using Memory Mapped Files for read-only file access will give you simpler code (whole file is an in-memory array) and faster I/O operations (on-demand reading managed by OS kernel code). This method can give you significant boost if the original file is big and the searched-pattern is located near the beginning of the file
- the loop should end at
High(FileByteArray) - Length(OriginalByte)(+/-1) as beyond this boundary the pattern can not be found anyway
-
you can get some speed by comparing against the original byte array just offset by the
i index. Creation of the intermediate ExtractedByteArray would not be necessary (throw away, safe some memory allocation and memory copy CPU-clocks). Like this:if CompareByteArrays(ExtractedByteArray, OriginalByte) = True thenif CompareMem(@FileByteArray[i], @OriginalByte[0], Length(OriginalByte)) = True thenassuming the
i...i + Length(OriginalByte) - 1 boundaries are withing the range Low(FileByteArray)...High(FileByteArray) as mentioned in (7)Code Snippets
resource := CreateResource;
try
// do something
finally
FreeAndNil(resource);
endif CompareByteArrays(ExtractedByteArray, OriginalByte) = True thenif CompareMem(@FileByteArray[i], @OriginalByte[0], Length(OriginalByte)) = True thenContext
StackExchange Code Review Q#75234, answer score: 2
Revisions (0)
No revisions yet.