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

📄 cabhandler.cpp

📁 7-Zip 3.11的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// Cab/Handler.cpp

#include "stdafx.h"

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

#include "Windows/PropVariant.h"
#include "Windows/Time.h"

#include "CabCopyDecoder.h"
#include "LZXDecoder.h"
#include "MSZIPDecoder.h"

#include "CabHandler.h"

#include "../../Common/ProgressUtils.h"

using namespace NWindows;
using namespace NTime;

namespace NArchive {
namespace NCab {

STATPROPSTG kProperties[] = 
{
  { NULL, kpidPath, VT_BSTR},
  { NULL, kpidIsFolder, VT_BOOL},
  { NULL, kpidSize, VT_UI8},
  { NULL, kpidLastWriteTime, VT_FILETIME},
  { NULL, kpidAttributes, VT_UI4},

  { NULL, kpidMethod, VT_BSTR},
  // { NULL, kpidDictionarySize, VT_UI4},

  { NULL, kpidBlock, VT_UI4}
};

static const int kNumProperties = sizeof(kProperties) / sizeof(kProperties[0]);

static const wchar_t *kMethods[] = 
{
  L"None",
  L"MSZip",
  L"Quantum",
  L"LZX"
};

static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
static const wchar_t *kUnknownMethod = L"Unknown";

STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
  value->vt = VT_EMPTY;
  return S_OK;
}

STDMETHODIMP CHandler::GetNumberOfProperties(UINT32 *numProperties)
{
  *numProperties = sizeof(kProperties) / sizeof(kProperties[0]);
  return S_OK;
}

STDMETHODIMP CHandler::GetPropertyInfo(UINT32 index,     
      BSTR *name, PROPID *propID, VARTYPE *varType)
{
  if(index >= sizeof(kProperties) / sizeof(kProperties[0]))
    return E_INVALIDARG;
  const STATPROPSTG &srcItem = kProperties[index];
  *propID = srcItem.propid;
  *varType = srcItem.vt;
  *name = 0;
  return S_OK;
}

STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UINT32 *numProperties)
{
  *numProperties = 0;
  return S_OK;
}

STDMETHODIMP CHandler::GetArchivePropertyInfo(UINT32 index,     
      BSTR *name, PROPID *propID, VARTYPE *varType)
{
  return E_INVALIDARG;
}

STDMETHODIMP CHandler::GetProperty(UINT32 index, PROPID propID,  PROPVARIANT *value)
{
  COM_TRY_BEGIN
  NWindows::NCOM::CPropVariant propVariant;
  const CItem &fileInfo = m_Files[index];
  switch(propID)
  {
    case kpidPath:
      if (fileInfo.IsNameUTF())
      {
        UString unicodeName;
        if (!ConvertUTF8ToUnicode(fileInfo.Name, unicodeName))
          propVariant = L"";
        else
          propVariant = unicodeName;
      }
      else
        propVariant = MultiByteToUnicodeString(fileInfo.Name, CP_ACP);
      break;
    case kpidIsFolder:
      propVariant = false;
      break;
    case kpidSize:
      propVariant = fileInfo.UnPackSize;
      break;
    case kpidLastWriteTime:
    {
      FILETIME localFileTime, utcFileTime;
      if (DosTimeToFileTime(fileInfo.Time, localFileTime))
      {
        if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
          utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
      }
      else
        utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
      propVariant = utcFileTime;
      break;
    }
    case kpidAttributes:
      propVariant = fileInfo.GetWinAttributes();
      break;

    case kpidMethod:
    {
      UINT16 realFolderIndex = NHeader::NFolderIndex::GetRealFolderIndex(
          m_Folders.Size(), fileInfo.FolderIndex);
      const NHeader::CFolder &folder = m_Folders[realFolderIndex];
      UString method;
      int methodIndex = folder.GetCompressionMethod();
      if (methodIndex < kNumMethods)
        method = kMethods[methodIndex];
      else
        method = kUnknownMethod;
      if (methodIndex == NHeader::NCompressionMethodMajor::kLZX)
      {
        method += L":";
        wchar_t temp[32];
        _itow (folder.CompressionTypeMinor, temp, 10);
        method += temp;
      }
      propVariant = method;
      break;
    }
    case kpidBlock:
      propVariant = UINT32(fileInfo.FolderIndex);
      break;
  }
  propVariant.Detach(value);
  return S_OK;
  COM_TRY_END
}

class CPropgressImp: public CProgressVirt
{
  CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback;
public:
  STDMETHOD(SetTotal)(const UINT64 *numFiles);
  STDMETHOD(SetCompleted)(const UINT64 *numFiles);
  void Init(IArchiveOpenCallback *openArchiveCallback)
    { m_OpenArchiveCallback = openArchiveCallback; }
};

STDMETHODIMP CPropgressImp::SetTotal(const UINT64 *numFiles)
{
  if (m_OpenArchiveCallback)
    return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
  return S_OK;
}

STDMETHODIMP CPropgressImp::SetCompleted(const UINT64 *numFiles)
{
  if (m_OpenArchiveCallback)
    return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
  return S_OK;
}

STDMETHODIMP CHandler::Open(IInStream *inStream, 
    const UINT64 *maxCheckStartPosition,
    IArchiveOpenCallback *openArchiveCallback)
{
  COM_TRY_BEGIN
  m_Stream.Release();
  // try
  {
    CInArchive archive;
    m_Files.Clear();
    CPropgressImp progressImp;
    progressImp.Init(openArchiveCallback);
    RINOK(archive.Open(inStream, maxCheckStartPosition, 
        m_ArchiveInfo, m_Folders, m_Files, &progressImp));
    m_Stream = inStream;
  }
  /*
  catch(...)
  {
    return S_FALSE;
  }
  */
  COM_TRY_END
  return S_OK;
}

STDMETHODIMP CHandler::Close()
{
  m_Stream.Release();
  return S_OK;
}

class CCabFolderOutStream: 
  public ISequentialOutStream,
  public CMyUnknownImp
{
public:
  MY_UNKNOWN_IMP

  STDMETHOD(Write)(const void *data, UINT32 size, UINT32 *processedSize);
  STDMETHOD(WritePart)(const void *data, UINT32 size, UINT32 *processedSize);
private:
  const CObjectVector<NHeader::CFolder> *m_Folders;
  const CObjectVector<CItem> *m_Files;
  const CRecordVector<int> *m_FileIndexes;
  const CRecordVector<bool> *m_ExtractStatuses;
  int m_StartIndex;
  int m_CurrentIndex;
  int m_NumFiles;
  UINT64 m_CurrentDataPos;
  CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
  bool m_TestMode;

  bool m_FileIsOpen;
  CMyComPtr<ISequentialOutStream> realOutStream;
  UINT64 m_FilePos;

  HRESULT OpenFile(int indexIndex, ISequentialOutStream **realOutStream);
  HRESULT WriteEmptyFiles();
  UINT64 m_StartImportantTotalUnPacked;
public:
  void Init(
      const CObjectVector<NHeader::CFolder> *folders,
      const CObjectVector<CItem> *files, 
      const CRecordVector<int> *fileIndices, 
      const CRecordVector<bool> *extractStatuses, 
      int startIndex, 
      int numFiles, 
      IArchiveExtractCallback *extractCallback,
      UINT64 startImportantTotalUnPacked,
      bool testMode);
  HRESULT FlushCorrupted();
  HRESULT Unsupported();
};

void CCabFolderOutStream::Init(
    const CObjectVector<NHeader::CFolder> *folders,
    const CObjectVector<CItem> *files, 
    const CRecordVector<int> *fileIndices,
    const CRecordVector<bool> *extractStatuses, 
    int startIndex, 
    int numFiles,
    IArchiveExtractCallback *extractCallback,
    UINT64 startImportantTotalUnPacked,
    bool testMode)
{
  m_Folders = folders;
  m_Files = files;
  m_FileIndexes = fileIndices;
  m_ExtractStatuses = extractStatuses;
  m_StartIndex = startIndex;
  m_NumFiles = numFiles;
  m_ExtractCallback = extractCallback;
  m_StartImportantTotalUnPacked = startImportantTotalUnPacked;
  m_TestMode = testMode;

  m_CurrentIndex = 0;
  m_FileIsOpen = false;
}

HRESULT CCabFolderOutStream::OpenFile(int indexIndex, ISequentialOutStream **realOutStream)
{
  // RINOK(m_ExtractCallback->SetCompleted(&m_StartImportantTotalUnPacked));
  
  int fullIndex = m_StartIndex + indexIndex;

  INT32 askMode;
  if((*m_ExtractStatuses)[fullIndex])
    askMode = m_TestMode ? 
        NArchive::NExtract::NAskMode::kTest :
        NArchive::NExtract::NAskMode::kExtract;
  else
    askMode = NArchive::NExtract::NAskMode::kSkip;
  
  int index = (*m_FileIndexes)[fullIndex];
  const CItem &fileInfo = (*m_Files)[index];
  UINT16 realFolderIndex = NHeader::NFolderIndex::GetRealFolderIndex(
      m_Folders->Size(), fileInfo.FolderIndex);

  RINOK(m_ExtractCallback->GetStream(index, realOutStream, askMode));
  
  UINT64 currentUnPackSize = fileInfo.UnPackSize;
  
  bool mustBeProcessedAnywhere = (indexIndex < m_NumFiles - 1);
    
  if (realOutStream || mustBeProcessedAnywhere)
  {
    if (!realOutStream && !m_TestMode)
      askMode = NArchive::NExtract::NAskMode::kSkip;
    RINOK(m_ExtractCallback->PrepareOperation(askMode));
    return S_OK;
  }
  else

⌨️ 快捷键说明

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