Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mpc-hc/mpc-hc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/thirdparty/unrar/scantree.cpp')
-rw-r--r--src/thirdparty/unrar/scantree.cpp165
1 files changed, 157 insertions, 8 deletions
diff --git a/src/thirdparty/unrar/scantree.cpp b/src/thirdparty/unrar/scantree.cpp
index 40e4e47c9..ed48efe4b 100644
--- a/src/thirdparty/unrar/scantree.cpp
+++ b/src/thirdparty/unrar/scantree.cpp
@@ -8,6 +8,7 @@ ScanTree::ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN
ScanTree::GetDirs=GetDirs;
ScanEntireDisk=false;
+ FolderWildcards=false;
SetAllMaskDepth=0;
*CurMask=0;
@@ -16,6 +17,8 @@ ScanTree::ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN
Errors=0;
*ErrArcName=0;
Cmd=NULL;
+ ErrDirList=NULL;
+ ErrDirSpecPathLength=NULL;
}
@@ -27,11 +30,14 @@ ScanTree::~ScanTree()
}
-SCAN_CODE ScanTree::GetNext(FindData *FindData)
+SCAN_CODE ScanTree::GetNext(FindData *FD)
{
if (Depth<0)
return SCAN_DONE;
+#ifndef SILENT
+ uint LoopCount=0;
+#endif
SCAN_CODE FindCode;
while (1)
@@ -39,8 +45,15 @@ SCAN_CODE ScanTree::GetNext(FindData *FindData)
if (*CurMask==0 && !GetNextMask())
return SCAN_DONE;
+#ifndef SILENT
+ // Let's return some ticks to system or WinRAR can become irresponsible
+ // while scanning files in command like "winrar a -r arc c:\file.ext".
+ // Also we reset system sleep timer here.
+ if ((++LoopCount & 0x3ff)==0)
+ Wait();
+#endif
- FindCode=FindProc(FindData);
+ FindCode=FindProc(FD);
if (FindCode==SCAN_ERROR)
{
Errors++;
@@ -48,21 +61,151 @@ SCAN_CODE ScanTree::GetNext(FindData *FindData)
}
if (FindCode==SCAN_NEXT)
continue;
- if (FindCode==SCAN_SUCCESS && FindData->IsDir && GetDirs==SCAN_SKIPDIRS)
+ if (FindCode==SCAN_SUCCESS && FD->IsDir && GetDirs==SCAN_SKIPDIRS)
continue;
if (FindCode==SCAN_DONE && GetNextMask())
continue;
+ if (FilterList.ItemsCount()>0 && FindCode==SCAN_SUCCESS)
+ if (!CommandData::CheckArgs(&FilterList,FD->IsDir,FD->Name,false,MATCH_WILDSUBPATH))
+ continue;
break;
}
- return(FindCode);
+ return FindCode;
}
-bool ScanTree::GetNextMask()
+// For masks like dir1\dir2*\*.ext in non-recursive mode.
+bool ScanTree::ExpandFolderMask()
{
+ bool WildcardFound=false;
+ uint SlashPos=0;
+ for (int I=0;CurMask[I]!=0;I++)
+ {
+ if (CurMask[I]=='?' || CurMask[I]=='*')
+ WildcardFound=true;
+ if (WildcardFound && IsPathDiv(CurMask[I]))
+ {
+ // First path separator position after folder wildcard mask.
+ // In case of dir1\dir2*\dir3\name.ext mask it may point not to file
+ // name, so we cannot use PointToName() here.
+ SlashPos=I;
+ break;
+ }
+ }
+
+ wchar Mask[NM];
+ wcsncpyz(Mask,CurMask,ASIZE(Mask));
+ Mask[SlashPos]=0;
+
+ // Prepare the list of all folders matching the wildcard mask.
+ ExpandedFolderList.Reset();
+ FindFile Find;
+ Find.SetMask(Mask);
+ FindData FD;
+ while (Find.Next(&FD))
+ if (FD.IsDir)
+ {
+ wcsncatz(FD.Name,CurMask+SlashPos,ASIZE(FD.Name));
+
+ // Treat dir*\* or dir*\*.* as dir, so empty 'dir' is also matched
+ // by such mask. Skipping empty dir with dir*\*.* confused some users.
+ wchar *LastMask=PointToName(FD.Name);
+ if (wcscmp(LastMask,L"*")==0 || wcscmp(LastMask,L"*.*")==0)
+ RemoveNameFromPath(FD.Name);
+
+ ExpandedFolderList.AddString(FD.Name);
+ }
+ if (ExpandedFolderList.ItemsCount()==0)
+ return false;
+ // Return the first matching folder name now.
+ ExpandedFolderList.GetString(CurMask,ASIZE(CurMask));
+ return true;
+}
+
+
+// For masks like dir1\dir2*\file.ext this function sets 'dir1' recursive mask
+// and '*\dir2*\file.ext' filter. Masks without folder wildcards are
+// returned as is.
+bool ScanTree::GetFilteredMask()
+{
+ // If we have some matching folders left for non-recursive folder wildcard
+ // mask, we return it here.
+ if (ExpandedFolderList.ItemsCount()>0 && ExpandedFolderList.GetString(CurMask,ASIZE(CurMask)))
+ return true;
+
+ FolderWildcards=false;
+ FilterList.Reset();
if (!FileMasks->GetString(CurMask,ASIZE(CurMask)))
return false;
- CurMask[ASIZE(CurMask)-1]=0;
+
+ // Check if folder wildcards present.
+ bool WildcardFound=false;
+ uint FolderWildcardCount=0;
+ uint SlashPos=0;
+ for (int I=0;CurMask[I]!=0;I++)
+ {
+ if (CurMask[I]=='?' || CurMask[I]=='*')
+ WildcardFound=true;
+ if (IsPathDiv(CurMask[I]) || IsDriveDiv(CurMask[I]))
+ {
+ if (WildcardFound)
+ {
+ // Calculate a number of folder wildcards in current mask.
+ FolderWildcardCount++;
+ WildcardFound=false;
+ }
+ if (FolderWildcardCount==0)
+ SlashPos=I; // Slash position before first folder wildcard mask.
+ }
+ }
+ if (FolderWildcardCount==0)
+ return true;
+ FolderWildcards=true; // Global folder wildcards flag.
+
+ // If we have only one folder wildcard component and -r is missing or -r-
+ // is specified, prepare matching folders in non-recursive mode.
+ // We assume -r for masks like dir1*\dir2*\file*, because it is complicated
+ // to fast find them using OS file find API call.
+ if ((Recurse==RECURSE_NONE || Recurse==RECURSE_DISABLE) && FolderWildcardCount==1)
+ return ExpandFolderMask();
+
+ wchar Filter[NM];
+ // Convert path\dir*\ to *\dir filter to search for 'dir' in all 'path' subfolders.
+ wcscpy(Filter,L"*");
+ AddEndSlash(Filter,ASIZE(Filter));
+ // SlashPos might point or not point to path separator for masks like 'dir*', '\dir*' or 'd:dir*'
+ wchar *WildName=IsPathDiv(CurMask[SlashPos]) || IsDriveDiv(CurMask[SlashPos]) ? CurMask+SlashPos+1 : CurMask+SlashPos;
+ wcsncatz(Filter,WildName,ASIZE(Filter));
+
+ // Treat dir*\* or dir*\*.* as dir\, so empty 'dir' is also matched
+ // by such mask. Skipping empty dir with dir*\*.* confused some users.
+ wchar *LastMask=PointToName(Filter);
+ if (wcscmp(LastMask,L"*")==0 || wcscmp(LastMask,L"*.*")==0)
+ *LastMask=0;
+
+ FilterList.AddString(Filter);
+
+ bool RelativeDrive=IsDriveDiv(CurMask[SlashPos]);
+ if (RelativeDrive)
+ SlashPos++; // Use "d:" instead of "d" for d:* mask.
+
+ CurMask[SlashPos]=0;
+
+ if (!RelativeDrive) // Keep d: mask as is, not convert to d:\*
+ {
+ // We need to append "\*" both for -ep1 to work correctly and to
+ // convert d:\* masks previously truncated to d: back to original form.
+ AddEndSlash(CurMask,ASIZE(CurMask));
+ wcsncatz(CurMask,MASKALL,ASIZE(CurMask));
+ }
+ return true;
+}
+
+
+bool ScanTree::GetNextMask()
+{
+ if (!GetFilteredMask())
+ return false;
#ifdef _WIN_ALL
UnixSlashToDos(CurMask,CurMask,ASIZE(CurMask));
#endif
@@ -70,7 +213,7 @@ bool ScanTree::GetNextMask()
// We wish to scan entire disk if mask like c:\ is specified
// regardless of recursion mode. Use c:\*.* mask when need to scan only
// the root directory.
- ScanEntireDisk=IsDiskLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0;
+ ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0;
wchar *Name=PointToName(CurMask);
if (*Name==0)
@@ -111,8 +254,10 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
// SearchAll means that we'll use "*" mask for search, so we'll find
// subdirectories and will be able to recurse into them.
// We do not use "*" for directories at any level or for files
- // at top level in recursion mode.
+ // at top level in recursion mode. We always comrpess the entire directory
+ // if folder wildcard is specified.
bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS ||
+ FolderWildcards && Recurse!=RECURSE_DISABLE ||
Wildcards && Recurse==RECURSE_WILDCARDS ||
ScanEntireDisk && Recurse!=RECURSE_DISABLE);
if (Depth==0)
@@ -324,6 +469,10 @@ void ScanTree::ScanError(bool &Error)
if (Error)
{
+ if (ErrDirList!=NULL)
+ ErrDirList->AddString(CurMask);
+ if (ErrDirSpecPathLength!=NULL)
+ ErrDirSpecPathLength->Push((uint)SpecPathLength);
wchar FullName[NM];
// This conversion works for wildcard masks too.
ConvertNameToFull(CurMask,FullName,ASIZE(FullName));