⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fsfolder.cpp

📁 7-Zip 是一款号称有着现今最高压缩比的压缩软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// FSFolder.cpp

#include "StdAfx.h"

#include "FSFolder.h"

#include "Common/StringConvert.h"
#include "Common/UTFConvert.h"
#include "Common/ComTry.h"

#include "Windows/Defs.h"
#include "Windows/PropVariant.h"
#include "Windows/FileDir.h"
#include "Windows/FileIO.h"

#include "../../PropID.h"

#include "SysIconUtils.h"
#include "FSDrives.h"
#include "NetFolder.h"

namespace NWindows {
namespace NFile {

bool GetLongPath(LPCWSTR path, UString &longPath);

}}

using namespace NWindows;
using namespace NFile;
using namespace NFind;

namespace NFsFolder {

static STATPROPSTG kProperties[] =
{
  { NULL, kpidName, VT_BSTR},
  // { NULL, kpidIsDir, VT_BOOL},
  { NULL, kpidSize, VT_UI8},
  { NULL, kpidMTime, VT_FILETIME},
  { NULL, kpidCTime, VT_FILETIME},
  { NULL, kpidATime, VT_FILETIME},
  { NULL, kpidAttrib, VT_UI4},
  { NULL, kpidPackSize, VT_UI8},
  { NULL, kpidComment, VT_BSTR},
  { NULL, kpidPrefix, VT_BSTR}
};

HRESULT CFSFolder::Init(const UString &path, IFolderFolder *parentFolder)
{
  _parentFolder = parentFolder;
  _path = path;

  _findChangeNotification.FindFirst(_path, false,
      FILE_NOTIFY_CHANGE_FILE_NAME |
      FILE_NOTIFY_CHANGE_DIR_NAME |
      FILE_NOTIFY_CHANGE_ATTRIBUTES |
      FILE_NOTIFY_CHANGE_SIZE |
      FILE_NOTIFY_CHANGE_LAST_WRITE /*|
      FILE_NOTIFY_CHANGE_LAST_ACCESS |
      FILE_NOTIFY_CHANGE_CREATION |
      FILE_NOTIFY_CHANGE_SECURITY */);
  if (!_findChangeNotification.IsHandleAllocated())
  {
    DWORD lastError = GetLastError();
    CFindFile findFile;
    CFileInfoW fileInfo;
    if (!findFile.FindFirst(_path + UString(L"*"), fileInfo))
      return lastError;
  }
  return S_OK;
}

HRESULT GetFolderSize(const UString &path, UInt64 &numFolders, UInt64 &numFiles, UInt64 &size, IProgress *progress)
{
  RINOK(progress->SetCompleted(NULL));
  numFiles = numFolders = size = 0;
  CEnumeratorW enumerator(path + UString(WSTRING_PATH_SEPARATOR L"*"));
  CFileInfoW fileInfo;
  while (enumerator.Next(fileInfo))
  {
    if (fileInfo.IsDir())
    {
      UInt64 subFolders, subFiles, subSize;
      RINOK(GetFolderSize(path + UString(WCHAR_PATH_SEPARATOR) + fileInfo.Name, subFolders, subFiles, subSize, progress));
      numFolders += subFolders;
      numFolders++;
      numFiles += subFiles;
      size += subSize;
    }
    else
    {
      numFiles++;
      size += fileInfo.Size;
    }
  }
  return S_OK;
}

HRESULT CFSFolder::LoadSubItems(CDirItem &dirItem, const UString &path)
{
  {
    CEnumeratorW enumerator(path + L"*");
    CDirItem fileInfo;
    while (enumerator.Next(fileInfo))
    {
      fileInfo.CompressedSizeIsDefined = false;
      /*
      if (!GetCompressedFileSize(_path + fileInfo.Name,
      fileInfo.CompressedSize))
      fileInfo.CompressedSize = fileInfo.Size;
      */
      if (fileInfo.IsDir())
      {
        // fileInfo.Size = GetFolderSize(_path + fileInfo.Name);
        fileInfo.Size = 0;
      }
      dirItem.Files.Add(fileInfo);
    }
  }
  if (!_flatMode)
    return S_OK;

  for (int i = 0; i < dirItem.Files.Size(); i++)
  {
    CDirItem &item = dirItem.Files[i];
    if (item.IsDir())
      LoadSubItems(item, path + item.Name + WCHAR_PATH_SEPARATOR);
  }
  return S_OK;
}

void CFSFolder::AddRefs(CDirItem &dirItem)
{
  int i;
  for (i = 0; i < dirItem.Files.Size(); i++)
  {
    CDirItem &item = dirItem.Files[i];
    item.Parent = &dirItem;
    _refs.Add(&item);
  }
  if (!_flatMode)
    return;
  for (i = 0; i < dirItem.Files.Size(); i++)
  {
    CDirItem &item = dirItem.Files[i];
    if (item.IsDir())
      AddRefs(item);
  }
}

STDMETHODIMP CFSFolder::LoadItems()
{
  // OutputDebugString(TEXT("Start\n"));
  INT32 dummy;
  WasChanged(&dummy);
  Clear();
  RINOK(LoadSubItems(_root, _path));
  AddRefs(_root);

  // OutputDebugString(TEXT("Finish\n"));
  _commentsAreLoaded = false;
  return S_OK;
}

static const wchar_t *kDescriptionFileName = L"descript.ion";

bool CFSFolder::LoadComments()
{
  if (_commentsAreLoaded)
    return true;
  _comments.Clear();
  _commentsAreLoaded = true;
  NIO::CInFile file;
  if (!file.Open(_path + kDescriptionFileName))
    return false;
  UInt64 length;
  if (!file.GetLength(length))
    return false;
  if (length >= (1 << 28))
    return false;
  AString s;
  char *p = s.GetBuffer((int)((size_t)length + 1));
  UInt32 processedSize;
  file.Read(p, (UInt32)length, processedSize);
  p[length] = 0;
  s.ReleaseBuffer();
  if (processedSize != length)
    return false;
  file.Close();
  UString unicodeString;
  if (!ConvertUTF8ToUnicode(s, unicodeString))
    return false;
  return _comments.ReadFromString(unicodeString);
}

static bool IsAscii(const UString &testString)
{
  for (int i = 0; i < testString.Length(); i++)
    if (testString[i] >= 0x80)
      return false;
  return true;
}

bool CFSFolder::SaveComments()
{
  NIO::COutFile file;
  if (!file.Create(_path + kDescriptionFileName, true))
    return false;
  UString unicodeString;
  _comments.SaveToString(unicodeString);
  AString utfString;
  ConvertUnicodeToUTF8(unicodeString, utfString);
  UInt32 processedSize;
  if (!IsAscii(unicodeString))
  {
    Byte bom [] = { 0xEF, 0xBB, 0xBF, 0x0D, 0x0A };
    file.Write(bom , sizeof(bom), processedSize);
  }
  file.Write(utfString, utfString.Length(), processedSize);
  _commentsAreLoaded = false;
  return true;
}

STDMETHODIMP CFSFolder::GetNumberOfItems(UInt32 *numItems)
{
  *numItems = _refs.Size();
  return S_OK;
}

/*
STDMETHODIMP CFSFolder::GetNumberOfSubFolders(UInt32 *numSubFolders)
{
  UInt32 numSubFoldersLoc = 0;
  for (int i = 0; i < _files.Size(); i++)
    if (_files[i].IsDir())
      numSubFoldersLoc++;
  *numSubFolders = numSubFoldersLoc;
  return S_OK;
}
*/

bool MyGetCompressedFileSizeW(LPCWSTR fileName, UInt64 &size)
{
  DWORD highPart;
  DWORD lowPart = ::GetCompressedFileSizeW(fileName, &highPart);
  if (lowPart == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR)
  {
    #ifdef WIN_LONG_PATH
    {
      UString longPath;
      if (GetLongPath(fileName, longPath))
        lowPart = ::GetCompressedFileSizeW(longPath, &highPart);
    }
    #endif
    if (lowPart == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR)
      return false;
  }
  size = (UInt64(highPart) << 32) | lowPart;
  return true;
}

STDMETHODIMP CFSFolder::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)
{
  NCOM::CPropVariant prop;
  if (itemIndex >= (UInt32)_refs.Size())
    return E_INVALIDARG;
  CDirItem &fileInfo = *_refs[itemIndex];
  switch(propID)
  {
    case kpidIsDir:  prop = fileInfo.IsDir(); break;
    case kpidName:  prop = fileInfo.Name; break;
    case kpidSize:  if (!fileInfo.IsDir()) prop = fileInfo.Size; break;
    case kpidPackSize:
      if (!fileInfo.CompressedSizeIsDefined)
      {
        fileInfo.CompressedSizeIsDefined = true;
        if (fileInfo.IsDir () ||
            !MyGetCompressedFileSizeW(_path + GetRelPath(fileInfo), fileInfo.CompressedSize))
          fileInfo.CompressedSize = fileInfo.Size;
      }
      prop = fileInfo.CompressedSize;
      break;
    case kpidAttrib: prop = (UInt32)fileInfo.Attrib; break;
    case kpidCTime: prop = fileInfo.CTime; break;
    case kpidATime: prop = fileInfo.ATime; break;
    case kpidMTime: prop = fileInfo.MTime; break;
    case kpidComment:
    {
      LoadComments();
      UString comment;
      if (_comments.GetValue(GetRelPath(fileInfo), comment))
        prop = comment;
      break;
    }
    case kpidPrefix:
    {
      if (_flatMode)
      {
        prop = GetPrefix(fileInfo);
      }
      break;
    }
  }
  prop.Detach(value);
  return S_OK;
}

HRESULT CFSFolder::BindToFolderSpec(const wchar_t *name, IFolderFolder **resultFolder)
{
  *resultFolder = 0;
  CFSFolder *folderSpec = new CFSFolder;
  CMyComPtr<IFolderFolder> subFolder = folderSpec;
  RINOK(folderSpec->Init(_path + name + UString(WCHAR_PATH_SEPARATOR), 0));
  *resultFolder = subFolder.Detach();
  return S_OK;
}

UString CFSFolder::GetPrefix(const CDirItem &item) const
{
  UString path;
  CDirItem *cur = item.Parent;
  while (cur->Parent != 0)
  {
    path = cur->Name + UString(WCHAR_PATH_SEPARATOR) + path;
    cur = cur->Parent;
  }
  return path;
}

UString CFSFolder::GetRelPath(const CDirItem &item) const
{
  return GetPrefix(item) + item.Name;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -