mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
ADD: Feature [0001425] Search the contents of files (Alt-F7) in several encodings simultaneously
This commit is contained in:
parent
3c48189d0f
commit
20d1ccd840
7 changed files with 465 additions and 112 deletions
|
|
@ -307,7 +307,7 @@ end;"/>
|
|||
<PackageName Value="Image32"/>
|
||||
</Item13>
|
||||
</RequiredPackages>
|
||||
<Units Count="269">
|
||||
<Units Count="270">
|
||||
<Unit0>
|
||||
<Filename Value="doublecmd.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
|
|
@ -1972,6 +1972,14 @@ end;"/>
|
|||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="uDarwinFSWatch"/>
|
||||
</Unit268>
|
||||
<Unit269>
|
||||
<Filename Value="fchooseencoding.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<ComponentName Value="frmChooseEncoding"/>
|
||||
<HasResources Value="True"/>
|
||||
<ResourceBaseClass Value="Form"/>
|
||||
<UnitName Value="fChooseEncoding"/>
|
||||
</Unit269>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
|
|
|
|||
|
|
@ -413,6 +413,22 @@ object frmFindDlg: TfrmFindDlg
|
|||
Style = csDropDownList
|
||||
TabOrder = 7
|
||||
end
|
||||
object btnEncoding: TKASButton
|
||||
AnchorSideLeft.Control = cmbEncoding
|
||||
AnchorSideLeft.Side = asrBottom
|
||||
AnchorSideTop.Control = cmbEncoding
|
||||
AnchorSideBottom.Control = cmbEncoding
|
||||
AnchorSideBottom.Side = asrBottom
|
||||
Left = 219
|
||||
Height = 23
|
||||
Top = 77
|
||||
Width = 24
|
||||
Anchors = [akTop, akLeft, akBottom]
|
||||
BorderSpacing.Left = 6
|
||||
TabOrder = 8
|
||||
TabStop = True
|
||||
OnClick = btnEncodingClick
|
||||
end
|
||||
object cmbFindText: TComboBoxWithDelItems
|
||||
AnchorSideLeft.Control = CheksPanel
|
||||
AnchorSideLeft.Side = asrBottom
|
||||
|
|
@ -518,7 +534,7 @@ object frmFindDlg: TfrmFindDlg
|
|||
Width = 88
|
||||
Caption = 'Hexadeci&mal'
|
||||
OnChange = chkHexChange
|
||||
TabOrder = 8
|
||||
TabOrder = 9
|
||||
end
|
||||
object cbOfficeXML: TCheckBox
|
||||
AnchorSideLeft.Control = cbTextRegExp
|
||||
|
|
|
|||
180
src/fFindDlg.pas
180
src/fFindDlg.pas
|
|
@ -3,7 +3,7 @@
|
|||
-------------------------------------------------------------------------
|
||||
Find dialog, with searching in thread
|
||||
|
||||
Copyright (C) 2006-2021 Alexander Koblov (alexx2000@mail.ru)
|
||||
Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru)
|
||||
Copyright (C) 2003-2004 Radek Cervinka (radek.cervinka@centrum.cz)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -35,8 +35,8 @@ interface
|
|||
uses
|
||||
Graphics, SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, ComCtrls,
|
||||
ExtCtrls, Menus, EditBtn, Spin, Buttons, DateTimePicker, KASComboBox,
|
||||
fAttributesEdit, uDsxModule, DsxPlugin, uFindThread, uFindFiles, uRegExprU,
|
||||
uSearchTemplate, fSearchPlugin, uFileView, types, DCStrUtils,
|
||||
KASButton, fAttributesEdit, uDsxModule, DsxPlugin, uFindThread, uFindFiles,
|
||||
uRegExprU, uSearchTemplate, fSearchPlugin, uFileView, types, DCStrUtils,
|
||||
ActnList, uOSForms, uShellContextMenu, uExceptions, uFileSystemFileSource,
|
||||
uFormCommands, uHotkeyManager, LCLVersion, uWcxModule, uFileSource;
|
||||
|
||||
|
|
@ -127,6 +127,7 @@ type
|
|||
frmContentPlugins: TfrmSearchPlugin;
|
||||
gbDirectories: TGroupBox;
|
||||
gbFiles: TGroupBox;
|
||||
btnEncoding: TKASButton;
|
||||
lblAttributes: TLabel;
|
||||
lblExcludeDirectories: TLabel;
|
||||
lblCurrent: TLabel;
|
||||
|
|
@ -208,6 +209,7 @@ type
|
|||
procedure actExecute(Sender: TObject);
|
||||
procedure btnAddAttributeClick(Sender: TObject);
|
||||
procedure btnAttrsHelpClick(Sender: TObject);
|
||||
procedure btnEncodingClick(Sender: TObject);
|
||||
procedure btnNewSearchKeyDown(Sender: TObject; var Key: word;
|
||||
{%H-}Shift: TShiftState);
|
||||
procedure btnSearchDeleteClick(Sender: TObject);
|
||||
|
|
@ -309,6 +311,10 @@ type
|
|||
procedure AfterSearchStopped; //update button states after stop search(ThreadTerminate call this method)
|
||||
procedure AfterSearchFocus; //set correct focus after search stopped
|
||||
|
||||
procedure UpdateEncodings;
|
||||
function GetEncodings(AList: TCustomComboBox): String;
|
||||
procedure SetEncodings(const AEncodings: String; AList: TCustomComboBox);
|
||||
|
||||
procedure FindInArchive(AFileView: TFileView);
|
||||
procedure FillFindOptions(out FindOptions: TSearchTemplateRec; SetStartPath: boolean);
|
||||
procedure FindOptionsToDSXSearchRec(const AFindOptions: TSearchTemplateRec;
|
||||
|
|
@ -405,7 +411,7 @@ uses
|
|||
uFileViewNotebook, uKeyboard, uOSUtils, uArchiveFileSourceUtil,
|
||||
DCOSUtils, uRegExprA, uRegExprW, uDebug, uShowMsg, uConvEncoding,
|
||||
uColumns, uFileFunctions, uFileSorting, uWcxArchiveFileSource,
|
||||
DCConvertEncoding, WcxPlugin
|
||||
DCConvertEncoding, WcxPlugin, fChooseEncoding, dmCommonData
|
||||
{$IFDEF DARKWIN}
|
||||
, uDarkStyle
|
||||
{$ENDIF}
|
||||
|
|
@ -692,6 +698,7 @@ begin
|
|||
if I >= 0 then cmbEncoding.Items.Delete(I);
|
||||
cmbEncoding.Items.Insert(0, 'Default');
|
||||
cmbEncoding.ItemIndex := 0;
|
||||
cmbEncoding.Items.Objects[0]:= TObject(PtrInt(True));
|
||||
|
||||
// gray disabled fields
|
||||
cbUsePluginChange(Sender);
|
||||
|
|
@ -747,23 +754,17 @@ end;
|
|||
{ TfrmFindDlg.cmbEncodingSelect }
|
||||
procedure TfrmFindDlg.cmbEncodingSelect(Sender: TObject);
|
||||
var
|
||||
SupportedEncoding: Boolean;
|
||||
Encoding: String;
|
||||
Index, ItemIndex: Integer;
|
||||
begin
|
||||
Encoding := cmbEncoding.Text;
|
||||
SupportedEncoding:= SingleByteEncoding(Encoding);
|
||||
if (not SupportedEncoding) and TRegExprU.AvailableNew then
|
||||
if (cmbEncoding.Tag = 1) then
|
||||
begin
|
||||
Encoding := NormalizeEncoding(Encoding);
|
||||
if Encoding = EncodingDefault then Encoding := GetDefaultTextEncoding;
|
||||
SupportedEncoding := Encoding = EncodingUTF8;
|
||||
ItemIndex:= cmbEncoding.ItemIndex;
|
||||
for Index:= 0 to cmbEncoding.Items.Count - 1 do
|
||||
begin
|
||||
cmbEncoding.Items.Objects[Index]:= TObject(PtrInt((ItemIndex = Index)));
|
||||
end;
|
||||
end;
|
||||
|
||||
cbTextRegExp.Enabled := cbFindText.Checked and SupportedEncoding and (not chkHex.Checked);
|
||||
if not cbTextRegExp.Enabled then cbTextRegExp.Checked := False;
|
||||
|
||||
cbCaseSens.Enabled:= cbFindText.Checked and (not cbReplaceText.Checked) and (not chkHex.Checked) and (not cbTextRegExp.Checked);
|
||||
if cbFindText.Checked and (not cbCaseSens.Enabled) then cbCaseSens.Checked := not cbTextRegExp.Checked;
|
||||
UpdateEncodings;
|
||||
end;
|
||||
|
||||
{ TfrmFindDlg.Create }
|
||||
|
|
@ -786,6 +787,8 @@ begin
|
|||
C.Free;
|
||||
end;
|
||||
|
||||
dmComData.ilEditorImages.GetBitmap(44, btnEncoding.Glyph);
|
||||
|
||||
FCommands := TFormCommands.Create(Self, actList);
|
||||
end;
|
||||
|
||||
|
|
@ -831,7 +834,7 @@ begin
|
|||
EnableControl(cbOfficeXML, cbFindText.Checked);
|
||||
lblEncoding.Enabled := cbFindText.Checked;
|
||||
cbReplaceText.Checked := False;
|
||||
cmbEncodingSelect(nil);
|
||||
UpdateEncodings;
|
||||
|
||||
if not FUpdating and cmbFindText.Enabled and cmbFindText.CanSetFocus and (Sender = cbFindText) then
|
||||
begin
|
||||
|
|
@ -907,6 +910,7 @@ begin
|
|||
cbOfficeXML.Checked := False;
|
||||
cbNotContainingText.Checked := False;
|
||||
cmbEncoding.ItemIndex := 0;
|
||||
cmbEncoding.Tag := 1;
|
||||
cmbEncodingSelect(nil);
|
||||
|
||||
// duplicates
|
||||
|
|
@ -962,6 +966,39 @@ begin
|
|||
ShowHelpOrErrorForKeyword('', edtAttrib.HelpKeyword);
|
||||
end;
|
||||
|
||||
procedure TfrmFindDlg.btnEncodingClick(Sender: TObject);
|
||||
var
|
||||
I, Index, ACount: Integer;
|
||||
begin
|
||||
if ChooseEncoding(Self, cmbEncoding.Items) then
|
||||
begin
|
||||
I:= 0;
|
||||
ACount:= 0;
|
||||
for Index:= 0 to cmbEncoding.Items.Count - 1 do
|
||||
begin
|
||||
if (PtrInt(cmbEncoding.Items.Objects[Index]) <> 0) then
|
||||
begin
|
||||
I:= Index;
|
||||
Inc(ACount);
|
||||
end;
|
||||
end;
|
||||
if ACount > 1 then
|
||||
begin
|
||||
I:= 0;
|
||||
end
|
||||
else if (ACount = 0) then
|
||||
begin
|
||||
I:= 0;
|
||||
ACount:= 1;
|
||||
cmbEncoding.Items.Objects[I]:= TObject(PtrInt(True));
|
||||
end;
|
||||
cmbEncoding.Tag:= ACount;
|
||||
cmbEncoding.ItemIndex:= I;
|
||||
cmbEncoding.Enabled:= (ACount <= 1);
|
||||
UpdateEncodings;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TfrmFindDlg.actExecute }
|
||||
procedure TfrmFindDlg.actExecute(Sender: TObject);
|
||||
var
|
||||
|
|
@ -1073,7 +1110,7 @@ begin
|
|||
begin
|
||||
cbCaseSens.Checked := Boolean(cbCaseSens.Tag);
|
||||
end;
|
||||
cmbEncodingSelect(cmbEncoding);
|
||||
UpdateEncodings;
|
||||
end;
|
||||
|
||||
{ TfrmFindDlg.cbSelectedFilesChange }
|
||||
|
|
@ -1135,9 +1172,8 @@ begin
|
|||
begin
|
||||
cbCaseSens.Checked := Boolean(cbCaseSens.Tag);
|
||||
end;
|
||||
cmbEncoding.Enabled:= not chkHex.Checked;
|
||||
cbReplaceText.Enabled:= not (chkHex.Checked or cbOfficeXML.Checked);
|
||||
cmbEncodingSelect(cmbEncoding);
|
||||
UpdateEncodings;
|
||||
end;
|
||||
|
||||
{ TfrmFindDlg.btnSelDirClick }
|
||||
|
|
@ -1229,7 +1265,7 @@ begin
|
|||
CaseSensitive := cbCaseSens.Checked;
|
||||
NotContainingText := cbNotContainingText.Checked;
|
||||
TextRegExp := cbTextRegExp.Checked;
|
||||
TextEncoding := cmbEncoding.Text;
|
||||
TextEncoding := GetEncodings(cmbEncoding);
|
||||
OfficeXML := cbOfficeXML.Checked;
|
||||
{ Duplicates }
|
||||
Duplicates:= chkDuplicates.Checked;
|
||||
|
|
@ -1380,6 +1416,80 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmFindDlg.UpdateEncodings;
|
||||
var
|
||||
Index: Integer;
|
||||
Encoding: String;
|
||||
SupportedEncoding: Boolean;
|
||||
begin
|
||||
SupportedEncoding:= True;
|
||||
|
||||
for Index:= 0 to cmbEncoding.Items.Count - 1 do
|
||||
begin
|
||||
if (PtrInt(cmbEncoding.Items.Objects[Index]) <> 0) then
|
||||
begin
|
||||
Encoding:= cmbEncoding.Items[Index];
|
||||
SupportedEncoding:= SingleByteEncoding(Encoding);
|
||||
if (not SupportedEncoding) and TRegExprU.AvailableNew then
|
||||
begin
|
||||
Encoding := NormalizeEncoding(Encoding);
|
||||
if Encoding = EncodingDefault then Encoding := GetDefaultTextEncoding;
|
||||
SupportedEncoding := Encoding = EncodingUTF8;
|
||||
end;
|
||||
if not SupportedEncoding then Break;
|
||||
end;
|
||||
end;
|
||||
|
||||
btnEncoding.Visible:= not cbReplaceText.Checked;
|
||||
btnEncoding.Enabled:= cbFindText.Checked and (not chkHex.Checked);
|
||||
cmbEncoding.Enabled:= btnEncoding.Enabled and (cmbEncoding.Tag < 2);
|
||||
|
||||
cbTextRegExp.Enabled := cbFindText.Checked and SupportedEncoding and (not chkHex.Checked);
|
||||
if not cbTextRegExp.Enabled then cbTextRegExp.Checked := False;
|
||||
|
||||
cbCaseSens.Enabled:= cbFindText.Checked and (not cbReplaceText.Checked) and (not chkHex.Checked) and (not cbTextRegExp.Checked);
|
||||
if cbFindText.Checked and (not cbCaseSens.Enabled) then cbCaseSens.Checked := not cbTextRegExp.Checked;
|
||||
end;
|
||||
|
||||
function TfrmFindDlg.GetEncodings(AList: TCustomComboBox): String;
|
||||
var
|
||||
Index: Integer;
|
||||
begin
|
||||
Result:= EmptyStr;
|
||||
|
||||
for Index:= 0 to AList.Items.Count - 1 do
|
||||
begin
|
||||
if (PtrInt(AList.Items.Objects[Index]) <> 0) then
|
||||
begin
|
||||
Result+= AList.Items[Index] + '|';
|
||||
end;
|
||||
end;
|
||||
|
||||
if Length(Result) = 0 then Result:= AList.Text;
|
||||
end;
|
||||
|
||||
procedure TfrmFindDlg.SetEncodings(const AEncodings: String;
|
||||
AList: TCustomComboBox);
|
||||
var
|
||||
S: TStringArray;
|
||||
I, Index, ACount: Integer;
|
||||
begin
|
||||
ACount:= 0;
|
||||
S:= SplitString(AEncodings, '|');
|
||||
|
||||
for Index:= 0 to High(S) do
|
||||
begin
|
||||
I:= AList.Items.IndexOf(S[Index]);
|
||||
if (I >= 0) then
|
||||
begin
|
||||
Inc(ACount);
|
||||
AList.Items.Objects[I]:= TObject(PtrInt(True));
|
||||
end;
|
||||
end;
|
||||
AList.Tag:= ACount;
|
||||
if ACount = 1 then AList.ItemIndex:= I;
|
||||
end;
|
||||
|
||||
procedure TfrmFindDlg.FindInArchive(AFileView: TFileView);
|
||||
var
|
||||
AEnabled: Boolean;
|
||||
|
|
@ -1481,12 +1591,31 @@ end;
|
|||
|
||||
{ TfrmFindDlg.cbReplaceTextChange }
|
||||
procedure TfrmFindDlg.cbReplaceTextChange(Sender: TObject);
|
||||
var
|
||||
Index: Integer;
|
||||
begin
|
||||
EnableControl(cmbReplaceText, cbReplaceText.Checked and cbFindText.Checked);
|
||||
cbNotContainingText.Checked := False;
|
||||
cbNotContainingText.Enabled := (not cbReplaceText.Checked and cbFindText.Checked);
|
||||
|
||||
cmbEncodingSelect(cmbEncoding);
|
||||
if cmbReplaceText.Enabled and (cmbEncoding.Tag > 1) then
|
||||
begin
|
||||
for Index:= cmbEncoding.Items.Count - 1 downto 0 do
|
||||
begin
|
||||
if (PtrInt(cmbEncoding.Items.Objects[Index]) <> 0) then
|
||||
begin
|
||||
if cmbEncoding.Tag = 1 then
|
||||
begin
|
||||
cmbEncoding.ItemIndex:= Index;
|
||||
Break;
|
||||
end;
|
||||
cmbEncoding.Tag:= cmbEncoding.Tag - 1;
|
||||
cmbEncoding.Items.Objects[Index]:= nil;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
UpdateEncodings;
|
||||
|
||||
if not FUpdating and cmbReplaceText.Enabled and cmbReplaceText.CanSetFocus then
|
||||
begin
|
||||
|
|
@ -2336,8 +2465,9 @@ begin
|
|||
cbCaseSens.Checked := CaseSensitive;
|
||||
cbNotContainingText.Checked := NotContainingText;
|
||||
cbTextRegExp.Checked := TextRegExp;
|
||||
cmbEncoding.Text := TextEncoding;
|
||||
SetEncodings(TextEncoding, cmbEncoding);
|
||||
cbOfficeXML.Checked := OfficeXML;
|
||||
UpdateEncodings;
|
||||
|
||||
if cbFindInArchive.Enabled then
|
||||
begin
|
||||
|
|
|
|||
44
src/fchooseencoding.lfm
Normal file
44
src/fchooseencoding.lfm
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
object frmChooseEncoding: TfrmChooseEncoding
|
||||
Left = 522
|
||||
Height = 240
|
||||
Top = 145
|
||||
Width = 320
|
||||
BorderStyle = bsToolWindow
|
||||
Caption = 'Encoding'
|
||||
ClientHeight = 240
|
||||
ClientWidth = 320
|
||||
OnCreate = FormCreate
|
||||
Position = poOwnerFormCenter
|
||||
LCLVersion = '2.2.5.0'
|
||||
object ButtonPanel: TButtonPanel
|
||||
Left = 6
|
||||
Height = 34
|
||||
Top = 200
|
||||
Width = 308
|
||||
OKButton.Name = 'OKButton'
|
||||
OKButton.DefaultCaption = True
|
||||
HelpButton.Name = 'HelpButton'
|
||||
HelpButton.DefaultCaption = True
|
||||
CloseButton.Name = 'CloseButton'
|
||||
CloseButton.DefaultCaption = True
|
||||
CancelButton.Name = 'CancelButton'
|
||||
CancelButton.DefaultCaption = True
|
||||
TabOrder = 0
|
||||
ShowButtons = [pbOK, pbCancel]
|
||||
end
|
||||
object ScrollBox: TScrollBox
|
||||
Left = 0
|
||||
Height = 194
|
||||
Top = 0
|
||||
Width = 320
|
||||
HorzScrollBar.Page = 1
|
||||
VertScrollBar.Page = 1
|
||||
Align = alClient
|
||||
BorderStyle = bsNone
|
||||
ChildSizing.LeftRightSpacing = 6
|
||||
ChildSizing.TopBottomSpacing = 6
|
||||
ChildSizing.Layout = cclLeftToRightThenTopToBottom
|
||||
ChildSizing.ControlsPerLine = 1
|
||||
TabOrder = 1
|
||||
end
|
||||
end
|
||||
3
src/fchooseencoding.lrj
Normal file
3
src/fchooseencoding.lrj
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{"version":1,"strings":[
|
||||
{"hash":77966471,"name":"tfrmchooseencoding.caption","sourcebytes":[69,110,99,111,100,105,110,103],"value":"Encoding"}
|
||||
]}
|
||||
86
src/fchooseencoding.pas
Normal file
86
src/fchooseencoding.pas
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
unit fChooseEncoding;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ButtonPanel, StdCtrls;
|
||||
|
||||
type
|
||||
|
||||
{ TfrmChooseEncoding }
|
||||
|
||||
TfrmChooseEncoding = class(TForm)
|
||||
ButtonPanel: TButtonPanel;
|
||||
ScrollBox: TScrollBox;
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure CheckBoxChange(Sender: TObject);
|
||||
private
|
||||
FList: TStrings;
|
||||
public
|
||||
constructor Create(TheOwner: TComponent; AList: TStrings); reintroduce;
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
function ChooseEncoding(TheOwner: TComponent; AList: TStrings): Boolean;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
uConvEncoding;
|
||||
|
||||
function ChooseEncoding(TheOwner: TComponent; AList: TStrings): Boolean;
|
||||
begin
|
||||
with TfrmChooseEncoding.Create(TheOwner, AList) do
|
||||
try
|
||||
Result:= (ShowModal = mrOK);
|
||||
if Result then AList.Assign(FList);
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
{$R *.lfm}
|
||||
|
||||
{ TfrmChooseEncoding }
|
||||
|
||||
procedure TfrmChooseEncoding.CheckBoxChange(Sender: TObject);
|
||||
begin
|
||||
with TCheckBox(Sender) do
|
||||
begin
|
||||
FList.Objects[Tag]:= TObject(PtrInt(Checked));
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TfrmChooseEncoding.Create(TheOwner: TComponent; AList: TStrings);
|
||||
begin
|
||||
inherited Create(TheOwner);
|
||||
FList:= TStringList.Create;
|
||||
FList.Assign(AList);
|
||||
end;
|
||||
|
||||
destructor TfrmChooseEncoding.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
FList.Free;
|
||||
end;
|
||||
|
||||
procedure TfrmChooseEncoding.FormCreate(Sender: TObject);
|
||||
var
|
||||
Index: Integer;
|
||||
CheckBox: TCheckBox;
|
||||
begin
|
||||
for Index:= 0 to FList.Count - 1 do
|
||||
begin
|
||||
CheckBox:= TCheckBox.Create(Self);
|
||||
CheckBox.Parent:= ScrollBox;
|
||||
CheckBox.Caption:= FList[Index];
|
||||
CheckBox.Tag:= Index;
|
||||
CheckBox.OnChange:= @CheckBoxChange;
|
||||
CheckBox.Checked:= Boolean(PtrInt(FList.Objects[Index]));
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
|
@ -28,8 +28,8 @@ unit uFindThread;
|
|||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, DCStringHashListUtf8, uFindFiles, uFindEx, uFindByrMr,
|
||||
uMasks, uRegExpr, uRegExprW, uWcxModule;
|
||||
Classes, SysUtils, Contnrs, DCStringHashListUtf8, uFindFiles, uFindEx,
|
||||
uFindByrMr, uMasks, uRegExpr, uRegExprW, uWcxModule;
|
||||
|
||||
type
|
||||
|
||||
|
|
@ -44,6 +44,18 @@ type
|
|||
function Clone: TDuplicate;
|
||||
end;
|
||||
|
||||
{ TEncoding }
|
||||
|
||||
TEncoding = class
|
||||
FindText: String;
|
||||
ReplaceText: String;
|
||||
FRegExpr: TRegExprEx;
|
||||
RecodeTable: TRecodeTable;
|
||||
FTextSearchType: TTextSearch;
|
||||
public
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
{ TFindThread }
|
||||
|
||||
TFindThread = class(TThread)
|
||||
|
|
@ -54,19 +66,17 @@ type
|
|||
FFilesFound:Integer;
|
||||
FFoundFile:String;
|
||||
FCurrentDepth: Integer;
|
||||
FTextSearchType: TTextSearch;
|
||||
FSearchText: String;
|
||||
FSearchTemplate: TSearchTemplateRec;
|
||||
FSelectedFiles: TStringList;
|
||||
FFileChecks: TFindFileChecks;
|
||||
FLinkTargets: TStringList; // A list of encountered directories (for detecting cycles)
|
||||
RecodeTable:TRecodeTable;
|
||||
FFilesMasks: TMaskList;
|
||||
FExcludeFiles: TMaskList;
|
||||
FEncodings: TObjectList;
|
||||
FExcludeDirectories: TMaskList;
|
||||
FFilesMasksRegExp: TRegExprW;
|
||||
FExcludeFilesRegExp: TRegExprW;
|
||||
FRegExpr: TRegExprEx;
|
||||
FArchive: TWcxModule;
|
||||
FHeader: TWcxHeader;
|
||||
|
||||
|
|
@ -86,8 +96,8 @@ type
|
|||
function CheckFile(const Folder : String; const sr : TSearchRecEx) : Boolean;
|
||||
function CheckDirectory(const CurrentDir, FolderName : String) : Boolean;
|
||||
function CheckDuplicate(const Folder : String; const sr : TSearchRecEx): Boolean;
|
||||
function FindInFile(const sFileName: String;sData: String; bCase, bRegExp: Boolean): Boolean;
|
||||
procedure FileReplaceString(const FileName, SearchString, ReplaceString: string; bCase, bRegExp: Boolean);
|
||||
function FindInFile(const sFileName: String; bCase, bRegExp: Boolean): Boolean;
|
||||
procedure FileReplaceString(const FileName: String; bCase, bRegExp: Boolean);
|
||||
|
||||
protected
|
||||
procedure Execute; override;
|
||||
|
|
@ -141,12 +151,27 @@ begin
|
|||
Result.Index:= Self.Index;
|
||||
end;
|
||||
|
||||
{ TEncoding }
|
||||
|
||||
destructor TEncoding.Destroy;
|
||||
begin
|
||||
FRegExpr.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ TFindThread }
|
||||
|
||||
constructor TFindThread.Create(const AFindOptions: TSearchTemplateRec; SelectedFiles: TStringList);
|
||||
var
|
||||
S: String;
|
||||
Index: Integer;
|
||||
AEncoding: TEncoding;
|
||||
ATextEncoding: String;
|
||||
AEncodings: TStringArray;
|
||||
begin
|
||||
inherited Create(True);
|
||||
|
||||
FEncodings:= TObjectList.Create(True);
|
||||
FLinkTargets := TStringList.Create;
|
||||
FSearchTemplate := AFindOptions;
|
||||
FSelectedFiles := SelectedFiles;
|
||||
|
|
@ -162,40 +187,55 @@ begin
|
|||
begin
|
||||
FSearchText := FindText;
|
||||
|
||||
if HexValue then
|
||||
begin
|
||||
TextEncoding := EncodingAnsi;
|
||||
FindText := HexToBin(FindText);
|
||||
end
|
||||
else begin
|
||||
TextEncoding := NormalizeEncoding(TextEncoding);
|
||||
if TextRegExp then FRegExpr := TRegExprEx.Create(TextEncoding, True);
|
||||
FindText := ConvertEncoding(FindText, EncodingUTF8, TextEncoding);
|
||||
ReplaceText := ConvertEncoding(ReplaceText, EncodingUTF8, TextEncoding);
|
||||
end;
|
||||
AEncodings:= SplitString(TextEncoding, '|');
|
||||
|
||||
// Determine search type
|
||||
if SingleByteEncoding(TextEncoding) then
|
||||
for Index:= 0 to High(AEncodings) do
|
||||
begin
|
||||
FTextSearchType := tsAnsi;
|
||||
RecodeTable := InitRecodeTable(TextEncoding, CaseSensitive);
|
||||
end
|
||||
else if (CaseSensitive = False) then
|
||||
begin
|
||||
if TextEncoding = EncodingDefault then begin
|
||||
TextEncoding := GetDefaultTextEncoding;
|
||||
AEncoding:= TEncoding.Create;
|
||||
ATextEncoding:= AEncodings[Index];
|
||||
|
||||
if HexValue then
|
||||
begin
|
||||
ATextEncoding := EncodingAnsi;
|
||||
FindText := HexToBin(FindText);
|
||||
end
|
||||
else begin
|
||||
ATextEncoding := NormalizeEncoding(ATextEncoding);
|
||||
AEncoding.FindText := ConvertEncoding(FindText, EncodingUTF8, ATextEncoding);
|
||||
AEncoding.ReplaceText := ConvertEncoding(ReplaceText, EncodingUTF8, ATextEncoding);
|
||||
if TextRegExp then
|
||||
begin
|
||||
AEncoding.FRegExpr := TRegExprEx.Create(ATextEncoding, True);
|
||||
AEncoding.FRegExpr.Expression := FSearchText;
|
||||
end;
|
||||
end;
|
||||
if ((TextEncoding = EncodingUTF8) or (TextEncoding = EncodingUTF8BOM)) then
|
||||
FTextSearchType:= tsUtf8
|
||||
else if (TextEncoding = EncodingUTF16LE) then
|
||||
FTextSearchType:= tsUtf16le
|
||||
else if (TextEncoding = EncodingUTF16BE) then
|
||||
FTextSearchType:= tsUtf16be
|
||||
else
|
||||
FTextSearchType:= tsOther;
|
||||
end
|
||||
else begin
|
||||
FTextSearchType:= tsOther;
|
||||
|
||||
// Determine search type
|
||||
if SingleByteEncoding(ATextEncoding) then
|
||||
begin
|
||||
AEncoding.FTextSearchType := tsAnsi;
|
||||
AEncoding.RecodeTable := InitRecodeTable(ATextEncoding, CaseSensitive);
|
||||
end
|
||||
else if (CaseSensitive = False) then
|
||||
begin
|
||||
if ATextEncoding = EncodingDefault then begin
|
||||
ATextEncoding := GetDefaultTextEncoding;
|
||||
end;
|
||||
if ((ATextEncoding = EncodingUTF8) or (ATextEncoding = EncodingUTF8BOM)) then
|
||||
AEncoding.FTextSearchType:= tsUtf8
|
||||
else if (ATextEncoding = EncodingUTF16LE) then
|
||||
AEncoding.FTextSearchType:= tsUtf16le
|
||||
else if (ATextEncoding = EncodingUTF16BE) then
|
||||
AEncoding.FTextSearchType:= tsUtf16be
|
||||
else
|
||||
AEncoding.FTextSearchType:= tsOther;
|
||||
end
|
||||
else begin
|
||||
AEncoding.FTextSearchType:= tsOther;
|
||||
end;
|
||||
FEncodings.Add(AEncoding);
|
||||
|
||||
if HexValue then Break;
|
||||
end;
|
||||
end
|
||||
end;
|
||||
|
|
@ -228,7 +268,7 @@ var
|
|||
Index: Integer;
|
||||
begin
|
||||
// FItems.Add('End');
|
||||
FreeAndNil(FRegExpr);
|
||||
FreeAndNil(FEncodings);
|
||||
FreeAndNil(FFilesMasks);
|
||||
FreeAndNil(FExcludeFiles);
|
||||
FreeThenNil(FLinkTargets);
|
||||
|
|
@ -328,7 +368,7 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function TFindThread.FindInFile(const sFileName: String; sData: String;
|
||||
function TFindThread.FindInFile(const sFileName: String;
|
||||
bCase, bRegExp: Boolean): Boolean;
|
||||
var
|
||||
fs: TFileStreamEx;
|
||||
|
|
@ -347,15 +387,18 @@ var
|
|||
end;
|
||||
|
||||
var
|
||||
lastPos,
|
||||
sDataLength,
|
||||
DataRead: Longint;
|
||||
BufferSize: Integer;
|
||||
Buffer: PAnsiChar = nil;
|
||||
S: String;
|
||||
Index: Integer;
|
||||
lastPos: Pointer;
|
||||
DataRead: Integer;
|
||||
fmr : TFileMapRec;
|
||||
BufferSize: Integer;
|
||||
sDataLength: Integer;
|
||||
AEncoding: TEncoding;
|
||||
Buffer: PAnsiChar = nil;
|
||||
begin
|
||||
Result := False;
|
||||
if sData = '' then Exit;
|
||||
if FSearchText = '' then Exit;
|
||||
|
||||
if FSearchTemplate.OfficeXML and OfficeMask.Matches(sFileName) then
|
||||
begin
|
||||
|
|
@ -387,47 +430,66 @@ begin
|
|||
finally
|
||||
fs.Free;
|
||||
end;
|
||||
FRegExpr.Expression := sData;
|
||||
FRegExpr.SetInputString(Pointer(S), Length(S));
|
||||
Exit(FRegExpr.Exec());
|
||||
for Index:= 0 to FEncodings.Count - 1 do
|
||||
begin
|
||||
AEncoding:= TEncoding(FEncodings[Index]);
|
||||
AEncoding.FRegExpr.SetInputString(Pointer(S), Length(S));
|
||||
if AEncoding.FRegExpr.Exec() then Exit(True);
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if gUseMmapInSearch then
|
||||
begin
|
||||
// Memory mapping should be slightly faster and use less memory
|
||||
case FTextSearchType of
|
||||
tsAnsi: lastPos:= FindMmapBM(sFileName, sData, RecodeTable, @IsAborting);
|
||||
tsUtf8: lastPos:= FindMmapU(sFileName, sData);
|
||||
tsUtf16le: lastPos:= FindMmapW(sFileName, sData, True);
|
||||
tsUtf16be: lastPos:= FindMmapW(sFileName, sData, False);
|
||||
else lastPos:= FindMmap(sFileName, sData, bCase, @IsAborting);
|
||||
end;
|
||||
case lastPos of
|
||||
0 : Exit(False);
|
||||
1 : Exit(True);
|
||||
// else fall back to searching via stream reading
|
||||
if MapFile(sFileName, fmr) then
|
||||
try
|
||||
for Index:= 0 to FEncodings.Count - 1 do
|
||||
begin
|
||||
AEncoding:= TEncoding(FEncodings[Index]);
|
||||
with AEncoding do
|
||||
begin
|
||||
case FTextSearchType of
|
||||
tsAnsi: lastPos:= Pointer(PosMemBoyerMur(fmr.MappedFile, fmr.FileSize, FindText, RecodeTable));
|
||||
tsUtf8: lastPos:= PosMemU(fmr.MappedFile, fmr.FileSize, 0, FindText, False);
|
||||
tsUtf16le: lastPos:= PosMemW(fmr.MappedFile, fmr.FileSize, 0, FindText, False, True);
|
||||
tsUtf16be: lastPos:= PosMemW(fmr.MappedFile, fmr.FileSize, 0, FindText, False, False);
|
||||
else lastPos:= PosMem(fmr.MappedFile, fmr.FileSize, 0, FindText, bCase, False);
|
||||
end;
|
||||
end;
|
||||
if (lastPos <> Pointer(-1)) then Exit(True);
|
||||
end;
|
||||
Exit;
|
||||
finally
|
||||
UnMapFile(fmr);
|
||||
end;
|
||||
// else fall back to searching via stream reading
|
||||
end;
|
||||
|
||||
BufferSize := gCopyBlockSize;
|
||||
sDataLength := Length(sData);
|
||||
|
||||
if sDataLength > BufferSize then
|
||||
raise Exception.Create(rsMsgErrSmallBuf);
|
||||
|
||||
fs := TFileStreamEx.Create(sFileName, fmOpenRead or fmShareDenyNone or fmOpenNoATime);
|
||||
try
|
||||
if sDataLength > fs.Size then // string longer than file, cannot search
|
||||
Exit;
|
||||
BufferSize := gCopyBlockSize;
|
||||
|
||||
// Buffer is extended by sDataLength-1 and BufferSize + sDataLength - 1
|
||||
// bytes are read. Then strings of length sDataLength are compared with
|
||||
// sData starting from offset 0 to BufferSize-1. The remaining part of the
|
||||
// buffer [BufferSize, BufferSize+sDataLength-1] is moved to the beginning,
|
||||
// buffer is filled up with BufferSize bytes and the search continues.
|
||||
for Index:= 0 to FEncodings.Count - 1 do
|
||||
begin
|
||||
fs.Seek(0, soFromBeginning);
|
||||
AEncoding:= TEncoding(FEncodings[Index]);
|
||||
sDataLength := Length(AEncoding.FindText);
|
||||
|
||||
GetMem(Buffer, BufferSize + sDataLength - 1);
|
||||
if Assigned(Buffer) then
|
||||
if sDataLength > BufferSize then
|
||||
raise Exception.Create(rsMsgErrSmallBuf);
|
||||
|
||||
if sDataLength > fs.Size then // string longer than file, cannot search
|
||||
Continue;
|
||||
|
||||
// Buffer is extended by sDataLength-1 and BufferSize + sDataLength - 1
|
||||
// bytes are read. Then strings of length sDataLength are compared with
|
||||
// sData starting from offset 0 to BufferSize-1. The remaining part of the
|
||||
// buffer [BufferSize, BufferSize+sDataLength-1] is moved to the beginning,
|
||||
// buffer is filled up with BufferSize bytes and the search continues.
|
||||
|
||||
GetMem(Buffer, BufferSize + sDataLength - 1);
|
||||
if Assigned(Buffer) then
|
||||
try
|
||||
if FillBuffer(Buffer, sDataLength-1) = sDataLength-1 then
|
||||
begin
|
||||
|
|
@ -437,26 +499,26 @@ begin
|
|||
if DataRead = 0 then
|
||||
Break;
|
||||
|
||||
case FTextSearchType of
|
||||
case AEncoding.FTextSearchType of
|
||||
tsAnsi:
|
||||
begin
|
||||
if PosMemBoyerMur(@Buffer[0], DataRead + sDataLength - 1, sData, RecodeTable) <> -1 then
|
||||
if PosMemBoyerMur(@Buffer[0], DataRead + sDataLength - 1, AEncoding.FindText, AEncoding.RecodeTable) <> -1 then
|
||||
Exit(True);
|
||||
end;
|
||||
tsUtf8:
|
||||
begin
|
||||
if PosMemU(@Buffer[0], DataRead + sDataLength - 1, 0, sData, False) <> Pointer(-1) then
|
||||
if PosMemU(@Buffer[0], DataRead + sDataLength - 1, 0, AEncoding.FindText, False) <> Pointer(-1) then
|
||||
Exit(True);
|
||||
end;
|
||||
tsUtf16le,
|
||||
tsUtf16be:
|
||||
begin
|
||||
if PosMemW(@Buffer[0], DataRead + sDataLength - 1, 0, sData, False, FTextSearchType = tsUtf16le) <> Pointer(-1) then
|
||||
if PosMemW(@Buffer[0], DataRead + sDataLength - 1, 0, AEncoding.FindText, False, AEncoding.FTextSearchType = tsUtf16le) <> Pointer(-1) then
|
||||
Exit(True);
|
||||
end;
|
||||
else
|
||||
begin
|
||||
if PosMem(@Buffer[0], DataRead + sDataLength - 1, 0, sData, bCase, False) <> Pointer(-1) then
|
||||
if PosMem(@Buffer[0], DataRead + sDataLength - 1, 0, AEncoding.FindText, bCase, False) <> Pointer(-1) then
|
||||
Exit(True);
|
||||
end;
|
||||
end;
|
||||
|
|
@ -469,6 +531,7 @@ begin
|
|||
end;
|
||||
except
|
||||
end;
|
||||
end;
|
||||
|
||||
finally
|
||||
FreeAndNil(fs);
|
||||
|
|
@ -480,10 +543,11 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure TFindThread.FileReplaceString(const FileName, SearchString, ReplaceString: string; bCase, bRegExp: Boolean);
|
||||
procedure TFindThread.FileReplaceString(const FileName: String; bCase, bRegExp: Boolean);
|
||||
var
|
||||
S: String;
|
||||
fs: TFileStreamEx;
|
||||
AEncoding: TEncoding;
|
||||
Flags : TReplaceFlags = [];
|
||||
begin
|
||||
fs := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyNone);
|
||||
|
|
@ -499,13 +563,15 @@ begin
|
|||
fs.Free;
|
||||
end;
|
||||
|
||||
AEncoding:= TEncoding(FEncodings[0]);
|
||||
|
||||
if bRegExp then
|
||||
S := FRegExpr.ReplaceAll(SearchString, S, replaceString)
|
||||
S := AEncoding.FRegExpr.ReplaceAll(AEncoding.FindText, S, AEncoding.ReplaceText)
|
||||
else
|
||||
begin
|
||||
Include(Flags, rfReplaceAll);
|
||||
if not bCase then Include(Flags, rfIgnoreCase);
|
||||
S := StringReplace(S, SearchString, replaceString, Flags);
|
||||
S := StringReplace(S, AEncoding.FindText, AEncoding.ReplaceText, Flags);
|
||||
end;
|
||||
|
||||
fs := TFileStreamEx.Create(FileName, fmCreate);
|
||||
|
|
@ -626,7 +692,7 @@ begin
|
|||
begin
|
||||
if Result and IsFindText then
|
||||
begin
|
||||
Result:= FindInFile(TargetFileName, FindText, CaseSensitive, TextRegExp);
|
||||
Result:= FindInFile(TargetFileName, CaseSensitive, TextRegExp);
|
||||
if NotContainingText then Result:= not Result;
|
||||
mbDeleteFile(TargetFileName);
|
||||
end;
|
||||
|
|
@ -862,10 +928,10 @@ begin
|
|||
Exit(False);
|
||||
|
||||
try
|
||||
Result := FindInFile(IncludeTrailingBackslash(Folder) + sr.Name, FindText, CaseSensitive, TextRegExp);
|
||||
Result := FindInFile(IncludeTrailingBackslash(Folder) + sr.Name, CaseSensitive, TextRegExp);
|
||||
|
||||
if (Result and IsReplaceText) then
|
||||
FileReplaceString(IncludeTrailingBackslash(Folder) + sr.Name, FindText, ReplaceText, CaseSensitive, TextRegExp);
|
||||
FileReplaceString(IncludeTrailingBackslash(Folder) + sr.Name, CaseSensitive, TextRegExp);
|
||||
|
||||
if NotContainingText then
|
||||
Result := not Result;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue