I have not performed extensive testing, but I think that this code works.
type
TDynByteArray = packed array of byte;
procedure BufReplace(var BufStart: PByte; var BufLen: cardinal; const Find: TDynByteArray; const Replace: TDynByteArray);
var
pos: PByte;
BufEnd: PByte;
i: Integer;
Match: boolean;
begin
{$POINTERMATH ON}
if Find = nil then Exit;
pos := BufStart;
BufEnd := BufStart + BufLen;
while pos < BufEnd do
begin
Match := false;
if pos^ = Find[0] then
if pos + length(Find) < BufEnd then
begin
Match := true;
for i := 1 to high(Find) do
if PByte(pos + i)^ <> Find[i] then
begin
Match := false;
break;
end;
end;
if Match then
begin
if length(Find) = length(Replace) then
Move(Replace[0], pos^, length(Replace))
else
begin
if length(Replace) < length(Find) then
begin
Move(Replace[0], pos^, length(Replace));
MoveMemory(pos + length(Replace), pos + length(Find), BufEnd - pos - length(Find));
dec(BufLen, length(Find) - length(Replace));
ReallocMem(BufStart, BufLen);
end
else
begin
inc(BufLen, length(Replace) - length(Find));
ReallocMem(BufStart, BufLen);
MoveMemory(pos + length(Replace), pos + length(Find), BufEnd - pos - length(Find));
Move(Replace[0], pos^, length(Replace))
end;
end;
inc(pos, length(Replace));
end
else
inc(pos);
end;
end;
To test it:
procedure TestIt;
var
len: cardinal;
a, b: TDynByteArray;
begin
len := 16;
GetMem(buf, len);
FillChar(buf^, 16, $11);
PByte(buf + 3)^ := $55;
SetLength(a, 2);
a[0] := $55;
a[1] := $11;
SetLength(b, 1);
b[0] := $77;
BufReplace(buf, len, a, b);
end;