unit Searches;
interface
uses
windows, sysutils, classes;
type
TBaseSearch = class(TComponent)
private
fPos : pchar;
fEnd : pchar;
fPattern : string;
fPatLen : integer;
fPatInitialized : boolean;
fCaseSensitive : boolean;
JumpShift : integer;
Shift : array[#0..#255] of integer;
CaseBlindTable : array[#0..#255] of char;
procedure InitPattern;
procedure MakeCaseBlindTable;
procedure SetCaseSensitive(CaseSens: boolean);
procedure SetPattern(const Pattern: string);
procedure SetWsPattern(const WsPattern: widestring);
function FindCaseSensitive: integer;
function FindCaseInsensitive: integer;
protected
fStart : pchar;
fDataLength : integer;
procedure ClearData;
procedure SetData(Data: pchar; DataLength: integer); virtual;
public
constructor Create(aowner: tcomponent); override;
destructor Destroy; override;
function FindFirst: integer;
function FindNext: integer;
function FindFrom(StartPos: integer): integer;
property WsPattern: widestring write SetWsPattern;
property Data: pchar read fStart;
property DataSize: integer read fDataLength;
published
property CaseSensitive: boolean read fCaseSensitive write SetCaseSensitive;
property Pattern: string read fPattern write SetPattern;
end;
TSearch = class(TBaseSearch)
public
procedure SetData(Data: pchar; DataLength: integer); override;
end;
TFileSearch = class(TBaseSearch)
private
fFilename: string;
procedure SetFilename(const Filename: string);
procedure Closefile;
public
destructor Destroy; override;
published
property Filename: string read fFilename write SetFilename;
end;
procedure Register;
const
POSITION_EOF = -1;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TSearch, TFileSearch]);
end;
procedure TBaseSearch.MakeCaseBlindTable;
var
i: char;
begin
for i:= #0 to #255 do
CaseBlindTable[i]:= ansilowercase(i)[1];
end;
constructor TBaseSearch.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fStart := nil;
fPattern := '';
fPatLen := 0;
MakeCaseBlindTable;
fCaseSensitive := false;
fPatInitialized := false;
end;
destructor TBaseSearch.Destroy;
begin
ClearData;
inherited Destroy;
end;
procedure TBaseSearch.ClearData;
begin
fStart := nil;
fPos := nil;
fEnd := nil;
fDataLength := 0;
end;
procedure TBaseSearch.SetPattern(const Pattern: string);
begin
if fPattern = Pattern then exit;
fPattern := Pattern;
fPatLen := length(Pattern);
fPatInitialized := false;
end;
procedure TBaseSearch.SetWsPattern(const WsPattern: widestring);
begin
fPatLen := length(WsPattern)*2;
fPatInitialized := false;
if fPatLen = 0 then exit;
SetString(fPattern, pchar(pointer(WsPattern)), fPatLen);
end;
procedure TBaseSearch.SetData(Data: pchar; DataLength: integer);
begin
ClearData;
if (Data = nil) or (DataLength < 1) then exit;
fStart := Data;
fDataLength := DataLength;
fEnd := fStart + fDataLength;
end;
procedure TBaseSearch.SetCaseSensitive(CaseSens: boolean);
begin
if fCaseSensitive = CaseSens then exit;
fCaseSensitive := CaseSens;
fPatInitialized := false;
end;
procedure TBaseSearch.InitPattern;
var
j: integer;
i: char;
begin
if fPatLen = 0 then exit;
for i := #0 to #255 do Shift[i]:= fPatLen;
if fCaseSensitive then
begin
for j := 1 to fPatLen-1 do
Shift[fPattern[j]]:= fPatLen - j;
JumpShift := Shift[fPattern[fPatLen]];
Shift[fPattern[fPatLen]] := 0;
end else
begin
for j := 1 to fPatLen-1 do
Shift[CaseBlindTable[fPattern[j]]]:= fPatLen - j;
JumpShift := Shift[CaseBlindTable[fPattern[fPatLen]]];
Shift[CaseBlindTable[fPattern[fPatLen]]] := 0;
end;
fPatInitialized := true;
end;
function TBaseSearch.FindFirst: integer;
begin
fPos := fStart+fPatLen-1;
result := FindNext;
end;
function TBaseSearch.FindFrom(StartPos: integer): integer;
begin
if StartPos < fPatLen-1 then
fPos := fStart+fPatLen-1 else
fPos := fStart+StartPos;
result := FindNext;
end;
function TBaseSearch.FindNext: integer;
begin
if not fPatInitialized then InitPattern;
if (fPatLen = 0) or (fPatLen >= fDataLength) or (fPos >= fEnd) then
begin
fPos := fEnd;
result := POSITION_EOF;
exit;
end;
if fCaseSensitive then
result := FindCaseSensitive else
result := FindCaseInsensitive;
end;
function TBaseSearch.FindCaseSensitive: integer;
var
i: integer;
j: pchar;
begin
result:= POSITION_EOF;
while fPos < fEnd do
begin
i := Shift[fPos^];
if i <> 0 then
inc(fPos,i)
else
begin
i := 1;
j := fPos - fPatLen;
while (i < fPatLen) and (fPattern[i] = (j+i)^) do inc(i);
if (i = fPatLen) then
begin
result:= fPos-fStart-fPatLen+1;
inc(fPos,fPatLen);
break;
end
else
inc(fPos,JumpShift);
end;
end;
end;
function TBaseSearch.FindCaseInsensitive: integer;
var
i: integer;
j: pchar;
begin
result:= POSITION_EOF;
while fPos < fEnd do
begin
i := Shift[CaseBlindTable[fPos^]];
if i <> 0 then
inc(fPos,i)
else
begin
i := 1;
j := fPos - fPatLen;
while (i < fPatLen) and
(CaseBlindTable[fPattern[i]] = CaseBlindTable[(j+i)^]) do inc(i);
if (i = fPatLen) then
begin
result:= fPos-fStart-fPatLen+1;
inc(fPos,fPatLen);
break;
end
else
inc(fPos,JumpShift);
end;
end;
end;
procedure TSearch.SetData(Data: pchar; DataLength: integer);
begin
inherited;
end;
destructor TFileSearch.Destroy;
begin
CloseFile;
inherited Destroy;
end;
procedure TFileSearch.SetFilename(const Filename: string);
var
filehandle: integer;
filemappinghandle: thandle;
size, highsize: integer;
begin
if (csDesigning in ComponentState) then
begin
fFilename := Filename;
exit;
end;
CloseFile;
if (Filename = '') or not FileExists(Filename) then exit;
filehandle := sysutils.FileOpen(Filename, fmopenread or fmsharedenynone);
if filehandle = 0 then exit;
size := GetFileSize(filehandle, @highsize);
if (size <= 0) or (highsize <> 0) then
begin
CloseHandle(filehandle);
exit;
end;
filemappinghandle :=
CreateFileMapping(filehandle, nil, page_readonly, 0, 0, nil);
if GetLastError = error_already_exists then filemappinghandle := 0;
if filemappinghandle <> 0 then
SetData(MapViewOfFile(filemappinghandle,file_map_read,0,0,0),size);
if fStart <> nil then fFilename := Filename;
CloseHandle(filemappinghandle);
CloseHandle(filehandle);
end;
procedure TFileSearch.CloseFile;
begin
if (csDesigning in ComponentState) then exit;
if (fStart <> nil) then UnmapViewOfFile(fStart);
fFilename := '';
ClearData;
end;
end.
|