--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp Mon Apr 10 12:06:43 2017 -0400
@@ -0,0 +1,281 @@
+// EnumDirItems.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StringConvert.h"
+#include "Common/Wildcard.h"
+#include "Common/MyCom.h"
+
+#include "EnumDirItems.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+void AddDirFileInfo(
+ const UString &prefix, // prefix for logical path
+ const UString &fullPathName, // path on disk: can be relative to some basePrefix
+ const NFind::CFileInfoW &fileInfo,
+ CObjectVector<CDirItem> &dirItems)
+{
+ CDirItem item;
+ item.Attributes = fileInfo.Attributes;
+ item.Size = fileInfo.Size;
+ item.CreationTime = fileInfo.CreationTime;
+ item.LastAccessTime = fileInfo.LastAccessTime;
+ item.LastWriteTime = fileInfo.LastWriteTime;
+ item.Name = prefix + fileInfo.Name;
+ item.FullPath = fullPathName;
+ dirItems.Add(item);
+}
+
+static void EnumerateDirectory(
+ const UString &baseFolderPrefix, // base (disk) prefix for scanning
+ const UString &directory, // additional disk prefix starting from baseFolderPrefix
+ const UString &prefix, // logical prefix
+ CObjectVector<CDirItem> &dirItems,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ NFind::CEnumeratorW enumerator(baseFolderPrefix + directory + wchar_t(kAnyStringWildcard));
+ for (;;)
+ {
+ NFind::CFileInfoW fileInfo;
+ bool found;
+ if (!enumerator.Next(fileInfo, found))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(baseFolderPrefix + directory);
+ return;
+ }
+ if (!found)
+ break;
+ AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, dirItems);
+ if (fileInfo.IsDirectory())
+ {
+ EnumerateDirectory(baseFolderPrefix, directory + fileInfo.Name + wchar_t(kDirDelimiter),
+ prefix + fileInfo.Name + wchar_t(kDirDelimiter), dirItems, errorPaths, errorCodes);
+ }
+ }
+}
+
+void EnumerateDirItems(
+ const UString &baseFolderPrefix, // base (disk) prefix for scanning
+ const UStringVector &fileNames, // names relative to baseFolderPrefix
+ const UString &archiveNamePrefix,
+ CObjectVector<CDirItem> &dirItems,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ for(int i = 0; i < fileNames.Size(); i++)
+ {
+ const UString &fileName = fileNames[i];
+ NFind::CFileInfoW fileInfo;
+ if (!NFind::FindFile(baseFolderPrefix + fileName, fileInfo))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(baseFolderPrefix + fileName);
+ continue;
+ }
+ AddDirFileInfo(archiveNamePrefix, fileName, fileInfo, dirItems);
+ if (fileInfo.IsDirectory())
+ {
+ EnumerateDirectory(baseFolderPrefix, fileName + wchar_t(kDirDelimiter),
+ archiveNamePrefix + fileInfo.Name + wchar_t(kDirDelimiter),
+ dirItems, errorPaths, errorCodes);
+ }
+ }
+}
+
+static HRESULT EnumerateDirItems(
+ const NWildcard::CCensorNode &curNode,
+ const UString &diskPrefix, // full disk path prefix
+ const UString &archivePrefix, // prefix from root
+ const UStringVector &addArchivePrefix, // prefix from curNode
+ CObjectVector<CDirItem> &dirItems,
+ bool enterToSubFolders,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ if (!enterToSubFolders)
+ if (curNode.NeedCheckSubDirs())
+ enterToSubFolders = true;
+ if (callback)
+ RINOK(callback->CheckBreak());
+
+ // try direct_names case at first
+ if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
+ {
+ // check that all names are direct
+ int i;
+ for (i = 0; i < curNode.IncludeItems.Size(); i++)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ if (item.Recursive || item.PathParts.Size() != 1)
+ break;
+ const UString &name = item.PathParts.Front();
+ if (name.IsEmpty() || DoesNameContainWildCard(name))
+ break;
+ }
+ if (i == curNode.IncludeItems.Size())
+ {
+ // all names are direct (no wildcards)
+ // so we don't need file_system's dir enumerator
+ CRecordVector<bool> needEnterVector;
+ for (i = 0; i < curNode.IncludeItems.Size(); i++)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ const UString &name = item.PathParts.Front();
+ const UString fullPath = diskPrefix + name;
+ NFind::CFileInfoW fileInfo;
+ if (!NFind::FindFile(fullPath, fileInfo))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ bool isDir = fileInfo.IsDirectory();
+ if (isDir && !item.ForDir || !isDir && !item.ForFile)
+ {
+ errorCodes.Add((DWORD)E_FAIL);
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ const UString realName = fileInfo.Name;
+ const UString realDiskPath = diskPrefix + realName;
+ {
+ UStringVector pathParts;
+ pathParts.Add(fileInfo.Name);
+ if (curNode.CheckPathToRoot(false, pathParts, !isDir))
+ continue;
+ }
+ AddDirFileInfo(archivePrefix, realDiskPath, fileInfo, dirItems);
+ if (!isDir)
+ continue;
+
+ UStringVector addArchivePrefixNew;
+ const NWildcard::CCensorNode *nextNode = 0;
+ int index = curNode.FindSubNode(name);
+ if (index >= 0)
+ {
+ for (int t = needEnterVector.Size(); t <= index; t++)
+ needEnterVector.Add(true);
+ needEnterVector[index] = false;
+ nextNode = &curNode.SubNodes[index];
+ }
+ else
+ {
+ nextNode = &curNode;
+ addArchivePrefixNew.Add(name); // don't change it to realName. It's for shortnames support
+ }
+ RINOK(EnumerateDirItems(*nextNode,
+ realDiskPath + wchar_t(kDirDelimiter),
+ archivePrefix + realName + wchar_t(kDirDelimiter),
+ addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes));
+ }
+ for (i = 0; i < curNode.SubNodes.Size(); i++)
+ {
+ if (i < needEnterVector.Size())
+ if (!needEnterVector[i])
+ continue;
+ const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
+ const UString fullPath = diskPrefix + nextNode.Name;
+ NFind::CFileInfoW fileInfo;
+ if (!NFind::FindFile(fullPath, fileInfo))
+ {
+ if (!nextNode.AreThereIncludeItems())
+ continue;
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ if (!fileInfo.IsDirectory())
+ {
+ errorCodes.Add((DWORD)E_FAIL);
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ RINOK(EnumerateDirItems(nextNode,
+ diskPrefix + fileInfo.Name + wchar_t(kDirDelimiter),
+ archivePrefix + fileInfo.Name + wchar_t(kDirDelimiter),
+ UStringVector(), dirItems, false, callback, errorPaths, errorCodes));
+ }
+ return S_OK;
+ }
+ }
+
+
+ NFind::CEnumeratorW enumerator(diskPrefix + wchar_t(kAnyStringWildcard));
+ for (;;)
+ {
+ NFind::CFileInfoW fileInfo;
+ bool found;
+ if (!enumerator.Next(fileInfo, found))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(diskPrefix);
+ break;
+ }
+ if (!found)
+ break;
+
+ if (callback)
+ RINOK(callback->CheckBreak());
+ const UString &name = fileInfo.Name;
+ bool enterToSubFolders2 = enterToSubFolders;
+ UStringVector addArchivePrefixNew = addArchivePrefix;
+ addArchivePrefixNew.Add(name);
+ {
+ UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
+ if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fileInfo.IsDirectory()))
+ continue;
+ }
+ if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fileInfo.IsDirectory()))
+ {
+ AddDirFileInfo(archivePrefix, diskPrefix + name, fileInfo, dirItems);
+ if (fileInfo.IsDirectory())
+ enterToSubFolders2 = true;
+ }
+ if (!fileInfo.IsDirectory())
+ continue;
+
+ const NWildcard::CCensorNode *nextNode = 0;
+ if (addArchivePrefix.IsEmpty())
+ {
+ int index = curNode.FindSubNode(name);
+ if (index >= 0)
+ nextNode = &curNode.SubNodes[index];
+ }
+ if (!enterToSubFolders2 && nextNode == 0)
+ continue;
+
+ addArchivePrefixNew = addArchivePrefix;
+ if (nextNode == 0)
+ {
+ nextNode = &curNode;
+ addArchivePrefixNew.Add(name);
+ }
+ RINOK(EnumerateDirItems(*nextNode,
+ diskPrefix + name + wchar_t(kDirDelimiter),
+ archivePrefix + name + wchar_t(kDirDelimiter),
+ addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes));
+ }
+ return S_OK;
+}
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ CObjectVector<CDirItem> &dirItems,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ for (int i = 0; i < censor.Pairs.Size(); i++)
+ {
+ const NWildcard::CPair &pair = censor.Pairs[i];
+ RINOK(EnumerateDirItems(pair.Head, pair.Prefix, L"", UStringVector(), dirItems, false,
+ callback, errorPaths, errorCodes));
+ }
+ return S_OK;
+}