misc/libphysfs/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp
changeset 12213 bb5522e88ab2
--- /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;
+}