mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-28 10:02:14 +00:00
451 lines
13 KiB
ObjectPascal
451 lines
13 KiB
ObjectPascal
{
|
|
Seksi Commander
|
|
----------------------------
|
|
Licence : GNU GPL v 2.0
|
|
Author : radek.cervinka@centrum.cz
|
|
|
|
implementind memory searching with case
|
|
and mmap file to memory
|
|
|
|
contributors:
|
|
Copyright (C) 2006-2007 Koblov Alexander (Alexx2000@mail.ru)
|
|
}
|
|
|
|
|
|
unit uFindMmap;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
uFindByrMr;
|
|
|
|
type
|
|
TAbortFunction = function: Boolean of object;
|
|
|
|
{en
|
|
Searches data in memory for a string.
|
|
|
|
@param(pDataAddr Pointer to the beginning of the data buffer.)
|
|
@param(iDataLength Length of the data buffer in bytes.)
|
|
@param(iStartPos Position in the buffer from which to begin search.)
|
|
@param(sSearchText Text that is searched for in the data buffer.)
|
|
@param(bCaseSensitive If @true the search is case sensitive.)
|
|
@param(bSearchBackwards If @true the search is done in iStartPos..0.
|
|
If @false the search is done in iStartPos..(iLength-1).)
|
|
@returns(If the string was not found it returns -1.
|
|
If the string was found it returns pointer to the data buffer
|
|
where the searched text begins.)
|
|
|
|
}
|
|
function PosMem(pDataAddr: PChar; iDataLength, iStartPos: PtrInt; const sSearchText: String;
|
|
bCaseSensitive: Boolean; bSearchBackwards: Boolean): Pointer;
|
|
|
|
function PosMemU(pDataAddr: PChar; iDataLength, iStartPos: PtrInt;
|
|
const sSearchText: String; bSearchBackwards: Boolean): Pointer;
|
|
|
|
function PosMemW(pDataAddr: PChar; iDataLength, iStartPos: PtrInt;
|
|
const sSearchText: String; bSearchBackwards, bLittleEndian: Boolean): Pointer;
|
|
|
|
function PosMemA(pDataAddr: PChar; iDataLength, iStartPos: PtrInt;
|
|
const sSearchText: String; bCaseSensitive, bSearchBackwards: Boolean;
|
|
RecodeTable: TRecodeTable): Pointer;
|
|
|
|
{en
|
|
Searches a file for a string using memory mapping.
|
|
|
|
@param(sFileName File to search in.)
|
|
@param(sFindData String to search for.)
|
|
@param(bCase If @true the search is case-sensitive.)
|
|
@param(Abort This function is called repeatedly during searching.
|
|
If it returns @true the search is aborted.)
|
|
|
|
@returns(-1 in case of error
|
|
@br 0 if the string wasn't found
|
|
@br 1 if the string was found)
|
|
}
|
|
function FindMmap(const sFileName:String; const sFindData:String; bCase:Boolean;
|
|
Abort: TAbortFunction):Integer;
|
|
|
|
function FindMmapU(const sFileName: String; const sFindData: String): Integer;
|
|
|
|
function FindMmapW(const sFileName: String; const sFindData: String; bLittleEndian: Boolean): Integer;
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils, DCOSUtils, DCUnicodeUtils, LazUTF8, StrUtils, DCStrUtils;
|
|
|
|
function PosMem(pDataAddr: PChar; iDataLength, iStartPos: PtrInt; const sSearchText: String;
|
|
bCaseSensitive: Boolean; bSearchBackwards: Boolean): Pointer;
|
|
var
|
|
SearchTextLength: Integer;
|
|
|
|
function sPos2(pAdr: PChar):Boolean; inline;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := False;
|
|
for i := 1 to SearchTextLength do
|
|
begin
|
|
case bCaseSensitive of
|
|
False: if UpCase(pAdr^) <> UpCase(sSearchText[i]) then Exit; // Only for Ansi
|
|
True : if pAdr^ <> sSearchText[i] then Exit;
|
|
end;
|
|
Inc(pAdr);
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
var
|
|
pCurrentAddr, pEndAddr: PAnsiChar;
|
|
begin
|
|
Result := Pointer(-1);
|
|
|
|
SearchTextLength := Length(sSearchText);
|
|
if (SearchTextLength <= 0) or (iDataLength <= 0) then
|
|
Exit;
|
|
|
|
pCurrentAddr := pDataAddr + iStartPos;
|
|
pEndAddr := pDataAddr + iDataLength - SearchTextLength;
|
|
|
|
if bSearchBackwards and (pCurrentAddr > pEndAddr) then
|
|
// Move to the first possible position for searching backwards.
|
|
pCurrentAddr := pEndAddr;
|
|
|
|
if (pEndAddr < pDataAddr) or (pCurrentAddr < pDataAddr) or (pCurrentAddr > pEndAddr) then
|
|
Exit;
|
|
|
|
while True do
|
|
begin
|
|
if (pCurrentAddr > pEndAddr) or (pCurrentAddr < pDataAddr) then
|
|
Exit;
|
|
|
|
if sPos2(pCurrentAddr) then
|
|
begin
|
|
Result := pCurrentAddr;
|
|
Exit;
|
|
end;
|
|
|
|
case bSearchBackwards of
|
|
False: Inc(pCurrentAddr);
|
|
True : Dec(pCurrentAddr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function PosMemU(pDataAddr: PChar; iDataLength, iStartPos: PtrInt;
|
|
const sSearchText: String; bSearchBackwards: Boolean): Pointer;
|
|
const
|
|
BUFFER_SIZE = 4096;
|
|
var
|
|
iSize: PtrInt;
|
|
iLength: Integer;
|
|
iTextPos: Integer;
|
|
sTextBuffer: String;
|
|
sLowerCase: String;
|
|
begin
|
|
Result := Pointer(-1);
|
|
iLength:= Length(sSearchText);
|
|
if bSearchBackwards then
|
|
begin
|
|
iSize:= iStartPos;
|
|
if iLength > iSize then Exit;
|
|
sLowerCase:= UTF8LowerCase(sSearchText);
|
|
|
|
// While text size > buffer size
|
|
while iStartPos > BUFFER_SIZE do
|
|
begin
|
|
iStartPos:= iStartPos - BUFFER_SIZE;
|
|
SetString(sTextBuffer, pDataAddr + iStartPos, BUFFER_SIZE);
|
|
DCUnicodeUtils.Utf8FixBroken(sTextBuffer);
|
|
sTextBuffer:= UTF8LowerCase(sTextBuffer);
|
|
iTextPos:= RPos(sLowerCase, sTextBuffer);
|
|
if iTextPos > 0 then
|
|
Exit(pDataAddr + iStartPos + iTextPos - 1)
|
|
else begin
|
|
// Shift text buffer
|
|
iStartPos:= iStartPos + iLength;
|
|
end;
|
|
end;
|
|
// Process remaining buffer
|
|
if iLength > iStartPos then Exit;
|
|
SetString(sTextBuffer, pDataAddr, iStartPos);
|
|
DCUnicodeUtils.Utf8FixBroken(sTextBuffer);
|
|
sTextBuffer:= UTF8LowerCase(sTextBuffer);
|
|
iTextPos:= RPos(sLowerCase, sTextBuffer);
|
|
if iTextPos > 0 then Result:= pDataAddr + iTextPos - 1;
|
|
end
|
|
else begin
|
|
iSize:= iDataLength - iStartPos;
|
|
if iLength > iSize then Exit;
|
|
sLowerCase:= UTF8LowerCase(sSearchText);
|
|
|
|
// While text size > buffer size
|
|
while iSize > BUFFER_SIZE do
|
|
begin
|
|
SetString(sTextBuffer, pDataAddr + iStartPos, BUFFER_SIZE);
|
|
DCUnicodeUtils.Utf8FixBroken(sTextBuffer);
|
|
sTextBuffer:= UTF8LowerCase(sTextBuffer);
|
|
iTextPos:= Pos(sLowerCase, sTextBuffer);
|
|
if iTextPos > 0 then
|
|
Exit(pDataAddr + iStartPos + iTextPos - 1)
|
|
else begin
|
|
// Shift text buffer
|
|
iStartPos:= iStartPos + (BUFFER_SIZE - iLength);
|
|
end;
|
|
iSize:= iDataLength - iStartPos;
|
|
end;
|
|
// Process remaining buffer
|
|
if iLength > iSize then Exit;
|
|
SetString(sTextBuffer, pDataAddr + iStartPos, iSize);
|
|
DCUnicodeUtils.Utf8FixBroken(sTextBuffer);
|
|
sTextBuffer:= UTF8LowerCase(sTextBuffer);
|
|
iTextPos:= Pos(sLowerCase, sTextBuffer);
|
|
if iTextPos > 0 then Result:= pDataAddr + iStartPos + iTextPos - 1;
|
|
end;
|
|
end;
|
|
|
|
function PosMemW(pDataAddr: PChar; iDataLength, iStartPos: PtrInt;
|
|
const sSearchText: String; bSearchBackwards, bLittleEndian: Boolean): Pointer;
|
|
const
|
|
BUFFER_SIZE = 4096;
|
|
var
|
|
iSize: PtrInt;
|
|
iLength: Integer;
|
|
iTextPos: Integer;
|
|
bSwapEndian: Boolean;
|
|
sTextBuffer: UnicodeString;
|
|
sLowerCase: UnicodeString;
|
|
begin
|
|
Result := Pointer(-1);
|
|
iLength:= Length(sSearchText);
|
|
bSwapEndian:= {$IFDEF ENDIAN_BIG}bLittleEndian{$ELSE}not bLittleEndian{$ENDIF};
|
|
if bSearchBackwards then
|
|
begin
|
|
iSize:= iStartPos;
|
|
if iLength > iSize then Exit;
|
|
sLowerCase:= PUnicodeChar(Pointer(sSearchText + #0));
|
|
if bSwapEndian then Utf16SwapEndian(sLowerCase);
|
|
sLowerCase:= UnicodeLowerCase(sLowerCase);
|
|
|
|
// While text size > buffer size
|
|
while iStartPos > BUFFER_SIZE do
|
|
begin
|
|
iStartPos:= iStartPos - BUFFER_SIZE;
|
|
SetString(sTextBuffer, PUnicodeChar(pDataAddr + iStartPos), BUFFER_SIZE div 2);
|
|
if bSwapEndian then Utf16SwapEndian(sTextBuffer);
|
|
sTextBuffer:= UnicodeLowerCase(sTextBuffer);
|
|
iTextPos:= RPos(sLowerCase, sTextBuffer);
|
|
if iTextPos > 0 then
|
|
Exit(pDataAddr + iStartPos + iTextPos * 2 - 2)
|
|
else begin
|
|
// Shift text buffer
|
|
iStartPos:= iStartPos + iLength;
|
|
end;
|
|
end;
|
|
// Process remaining buffer
|
|
if iLength > iStartPos then Exit;
|
|
SetString(sTextBuffer, PUnicodeChar(pDataAddr), iStartPos div 2);
|
|
if bSwapEndian then Utf16SwapEndian(sTextBuffer);
|
|
sTextBuffer:= UnicodeLowerCase(sTextBuffer);
|
|
iTextPos:= RPos(sLowerCase, sTextBuffer);
|
|
if iTextPos > 0 then Result:= pDataAddr + iTextPos * 2 - 2
|
|
end
|
|
else begin
|
|
iSize:= iDataLength - iStartPos;
|
|
if iLength > iSize then Exit;
|
|
sLowerCase:= PUnicodeChar(Pointer(sSearchText + #0));
|
|
if bSwapEndian then Utf16SwapEndian(sLowerCase);
|
|
sLowerCase:= UnicodeLowerCase(sLowerCase);
|
|
|
|
// While text size > buffer size
|
|
while iSize > BUFFER_SIZE do
|
|
begin
|
|
SetString(sTextBuffer, PUnicodeChar(pDataAddr + iStartPos), BUFFER_SIZE div 2);
|
|
if bSwapEndian then Utf16SwapEndian(sTextBuffer);
|
|
sTextBuffer:= UnicodeLowerCase(sTextBuffer);
|
|
iTextPos:= Pos(sLowerCase, sTextBuffer);
|
|
if iTextPos > 0 then
|
|
Exit(pDataAddr + iStartPos + iTextPos * 2 - 2)
|
|
else begin
|
|
// Shift text buffer
|
|
iStartPos:= iStartPos + (BUFFER_SIZE - iLength);
|
|
end;
|
|
iSize:= iDataLength - iStartPos;
|
|
end;
|
|
// Process remaining buffer
|
|
if iLength > iSize then Exit;
|
|
SetString(sTextBuffer, PUnicodeChar(pDataAddr + iStartPos), iSize div 2);
|
|
if bSwapEndian then Utf16SwapEndian(sTextBuffer);
|
|
sTextBuffer:= UnicodeLowerCase(sTextBuffer);
|
|
iTextPos:= Pos(sLowerCase, sTextBuffer);
|
|
if iTextPos > 0 then Result:= pDataAddr + iStartPos + iTextPos * 2 - 2;
|
|
end;
|
|
end;
|
|
|
|
function PosMemA(pDataAddr: PChar; iDataLength, iStartPos: PtrInt;
|
|
const sSearchText: String; bCaseSensitive, bSearchBackwards: Boolean;
|
|
RecodeTable: TRecodeTable): Pointer;
|
|
var
|
|
SearchTextLength: Integer;
|
|
|
|
function sPos2(pAdr: PChar):Boolean; inline;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := False;
|
|
for i := 1 to SearchTextLength do
|
|
begin
|
|
case bCaseSensitive of
|
|
False: if Chr(RecodeTable[Ord(pAdr^)]) <> Chr(RecodeTable[Ord(sSearchText[i])]) then Exit;
|
|
True : if pAdr^ <> sSearchText[i] then Exit;
|
|
end;
|
|
Inc(pAdr);
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
var
|
|
pCurrentAddr, pEndAddr: PAnsiChar;
|
|
begin
|
|
Result := Pointer(-1);
|
|
|
|
SearchTextLength := Length(sSearchText);
|
|
if (SearchTextLength <= 0) or (iDataLength <= 0) then
|
|
Exit;
|
|
|
|
pCurrentAddr := pDataAddr + iStartPos;
|
|
pEndAddr := pDataAddr + iDataLength - SearchTextLength;
|
|
|
|
if bSearchBackwards and (pCurrentAddr > pEndAddr) then
|
|
// Move to the first possible position for searching backwards.
|
|
pCurrentAddr := pEndAddr;
|
|
|
|
if (pEndAddr < pDataAddr) or (pCurrentAddr < pDataAddr) or (pCurrentAddr > pEndAddr) then
|
|
Exit;
|
|
|
|
while True do
|
|
begin
|
|
if (pCurrentAddr > pEndAddr) or (pCurrentAddr < pDataAddr) then
|
|
Exit;
|
|
|
|
if sPos2(pCurrentAddr) then
|
|
begin
|
|
Result := pCurrentAddr;
|
|
Exit;
|
|
end;
|
|
|
|
case bSearchBackwards of
|
|
False: Inc(pCurrentAddr);
|
|
True : Dec(pCurrentAddr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function FindMmap(const sFileName: String; const sFindData: String;
|
|
bCase: Boolean; Abort: TAbortFunction): Integer;
|
|
|
|
function PosMem(pAdr:PChar; iLength:Integer):Pointer;
|
|
var
|
|
xIndex:Integer;
|
|
DataLength: Integer;
|
|
|
|
function sPos(pAdr:PChar):Boolean; inline;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
Result:=False;
|
|
for i:=1 to DataLength do
|
|
begin
|
|
case bCase of
|
|
False:if UpCase(pAdr^)<>UpCase(sFindData[i]) then Exit;
|
|
True: if pAdr^<>sFindData[i] then Exit;
|
|
end;
|
|
inc(pAdr);
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
begin
|
|
Result:=pointer(-1);
|
|
DataLength := Length(sFindData);
|
|
|
|
for xIndex:=0 to iLength - DataLength do
|
|
begin
|
|
if sPos(pAdr) then
|
|
begin
|
|
Result:=pAdr;
|
|
Exit;
|
|
end;
|
|
inc(pAdr);
|
|
|
|
if Abort() then
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
fmr : TFileMapRec;
|
|
begin
|
|
Result := -1;
|
|
|
|
if MapFile(sFileName, fmr) then
|
|
begin
|
|
try
|
|
begin
|
|
if PosMem(fmr.MappedFile, fmr.FileSize) <> Pointer(-1) then
|
|
Result := 1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
finally
|
|
UnMapFile(fmr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function FindMmapU(const sFileName: String; const sFindData: String): Integer;
|
|
var
|
|
fmr : TFileMapRec;
|
|
begin
|
|
Result := -1;
|
|
|
|
if MapFile(sFileName, fmr) then
|
|
begin
|
|
try
|
|
begin
|
|
if PosMemU(fmr.MappedFile, fmr.FileSize, 0, sFindData, False) <> Pointer(-1) then
|
|
Result := 1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
finally
|
|
UnMapFile(fmr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function FindMmapW(const sFileName: String; const sFindData: String; bLittleEndian: Boolean): Integer;
|
|
var
|
|
fmr : TFileMapRec;
|
|
begin
|
|
Result := -1;
|
|
|
|
if MapFile(sFileName, fmr) then
|
|
begin
|
|
try
|
|
begin
|
|
if PosMemW(fmr.MappedFile, fmr.FileSize, 0, sFindData, False, bLittleEndian) <> Pointer(-1) then
|
|
Result := 1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
finally
|
|
UnMapFile(fmr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end.
|