chmhandler.cpp

来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 731 行 · 第 1/2 页

CPP
731
字号
// Chm/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 "../../Common/LimitedStreams.h"#include "../../Common/StreamUtils.h"#include "../../Common/ProgressUtils.h"#include "../../Compress/Copy/CopyCoder.h"#include "../../Compress/Lzx/LzxDecoder.h"#include "../Common/ItemNameUtils.h"#include "ChmHandler.h"using namespace NWindows;using namespace NTime;namespace NArchive {namespace NChm {// #define _CHM_DETAILS#ifdef _CHM_DETAILSenum {  kpidSection = kpidUserDefined,  kpidOffset};#endifSTATPROPSTG kProperties[] = {  { NULL, kpidPath, VT_BSTR},  // { NULL, kpidIsFolder, VT_BOOL},  { NULL, kpidSize, VT_UI8},  { NULL, kpidMethod, VT_BSTR},  { NULL, kpidBlock, VT_UI4}    #ifdef _CHM_DETAILS  ,  { L"Section", kpidSection, VT_UI4},  { L"Offset", kpidOffset, VT_UI4}  #endif};static const int kNumProperties = sizeof(kProperties) / sizeof(kProperties[0]);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;  if (srcItem.lpwstrName == 0)    *name = 0;  else    *name = ::SysAllocString(srcItem.lpwstrName);  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;  if (m_Database.NewFormat)  {    switch(propID)    {      case kpidSize:        propVariant = (UInt64)m_Database.NewFormatString.Length();      break;    }    propVariant.Detach(value);    return S_OK;  }  int entryIndex;  if (m_Database.LowLevel)    entryIndex = index;  else    entryIndex = m_Database.Indices[index];  const CItem &item = m_Database.Items[entryIndex];  switch(propID)  {    case kpidPath:    {      UString us;      if (ConvertUTF8ToUnicode(item.Name, us))      {        if (!m_Database.LowLevel)        {          if (us.Length() > 1)            if (us[0] == L'/')              us.Delete(0);        }        propVariant = NItemName::GetOSName2(us);      }      break;    }    case kpidIsFolder:      propVariant = item.IsDirectory();      break;    case kpidSize:      propVariant = item.Size;      break;    case kpidMethod:    {      if (!item.IsDirectory())        if (item.Section == 0)          propVariant = L"Copy";        else if (item.Section < m_Database.Sections.Size())          propVariant = m_Database.Sections[(size_t)item.Section].GetMethodName();      break;    }    case kpidBlock:      if (m_Database.LowLevel)        propVariant = item.Section;      else if (item.Section != 0)        propVariant = m_Database.GetFolder(index);      break;        #ifdef _CHM_DETAILS        case kpidSection:      propVariant = (UInt32)item.Section;      break;    case kpidOffset:      propVariant = (UInt32)item.Offset;      break;    #endif  }  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;    CPropgressImp progressImp;    progressImp.Init(openArchiveCallback);    RINOK(archive.Open(inStream, maxCheckStartPosition, m_Database));    /*    if (m_Database.LowLevel)      return S_FALSE;    */    m_Stream = inStream;  }  catch(...)  {    return S_FALSE;  }  return S_OK;  COM_TRY_END}STDMETHODIMP CHandler::Close(){  m_Database.Clear();  m_Stream.Release();  return S_OK;}class CChmFolderOutStream:   public ISequentialOutStream,  public CMyUnknownImp{public:  MY_UNKNOWN_IMP  HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);  UInt64 m_FolderSize;  UInt64 m_PosInFolder;  UInt64 m_PosInSection;  const CRecordVector<bool> *m_ExtractStatuses;  int m_StartIndex;  int m_CurrentIndex;  int m_NumFiles;private:  const CFilesDatabase *m_Database;  CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;  bool m_TestMode;  bool m_IsOk;  bool m_FileIsOpen;  UInt64 m_RemainFileSize;  CMyComPtr<ISequentialOutStream> m_RealOutStream;  HRESULT OpenFile();  HRESULT WriteEmptyFiles();public:  void Init(    const CFilesDatabase *database,    IArchiveExtractCallback *extractCallback,    bool testMode);    HRESULT FlushCorrupted();};void CChmFolderOutStream::Init(    const CFilesDatabase *database,    IArchiveExtractCallback *extractCallback,    bool testMode){  m_Database = database;  m_ExtractCallback = extractCallback;  m_TestMode = testMode;  m_CurrentIndex = 0;  m_FileIsOpen = false;}HRESULT CChmFolderOutStream::OpenFile(){  Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ?       NExtract::NAskMode::kTest :      NExtract::NAskMode::kExtract) :      NExtract::NAskMode::kSkip;  m_RealOutStream.Release();  RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode));  if (!m_RealOutStream && !m_TestMode)    askMode = NArchive::NExtract::NAskMode::kSkip;  return m_ExtractCallback->PrepareOperation(askMode);}HRESULT CChmFolderOutStream::WriteEmptyFiles(){  if (m_FileIsOpen)    return S_OK;  for(;m_CurrentIndex < m_NumFiles; m_CurrentIndex++)  {    UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex);    if (fileSize != 0)      return S_OK;    HRESULT result = OpenFile();    m_RealOutStream.Release();    RINOK(result);    RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));  }  return S_OK;}// This is WritePart functionHRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK){  UInt32 realProcessed = 0;  if (processedSize != NULL)   *processedSize = 0;  while(size != 0)  {    if (m_FileIsOpen)    {      UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size));      HRESULT res = S_OK;      if (numBytesToWrite > 0)      {        if (!isOK)          m_IsOk = false;        if (m_RealOutStream)        {          UInt32 processedSizeLocal = 0;          res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);          numBytesToWrite = processedSizeLocal;        }      }      realProcessed += numBytesToWrite;      if (processedSize != NULL)        *processedSize = realProcessed;      data = (const void *)((const Byte *)data + numBytesToWrite);      size -= numBytesToWrite;      m_RemainFileSize -= numBytesToWrite;      m_PosInSection += numBytesToWrite;      m_PosInFolder += numBytesToWrite;      if (res != S_OK)        return res;      if (m_RemainFileSize == 0)      {        m_RealOutStream.Release();        RINOK(m_ExtractCallback->SetOperationResult(          m_IsOk ?             NArchive::NExtract::NOperationResult::kOK:            NArchive::NExtract::NOperationResult::kDataError));        m_FileIsOpen = false;      }      if (realProcessed > 0)        break; // with this break this function works as write part    }    else    {      if (m_CurrentIndex >= m_NumFiles)        return E_FAIL;      int fullIndex = m_StartIndex + m_CurrentIndex;      m_RemainFileSize = m_Database->GetFileSize(fullIndex);      UInt64 fileOffset = m_Database->GetFileOffset(fullIndex);      if (fileOffset < m_PosInSection)        return E_FAIL;

⌨️ 快捷键说明

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