doublecmd/src/ufindmmap.pas

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.