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

📄 chmhandler.cpp

📁 7-Zip 是一款号称有着现今最高压缩比的压缩软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 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_DETAILS

enum
{
  kpidSection = kpidUserDefined
};

#endif

STATPROPSTG kProps[] =
{
  { NULL, kpidPath, VT_BSTR},
  { NULL, kpidSize, VT_UI8},
  { NULL, kpidMethod, VT_BSTR},
  { NULL, kpidBlock, VT_UI4}
  
  #ifdef _CHM_DETAILS
  ,
  { L"Section", kpidSection, VT_UI4},
  { NULL, kpidOffset, VT_UI4}
  #endif
};

STATPROPSTG kArcProps[] =
{
  { NULL, kpidNumBlocks, VT_UI8}
};

IMP_IInArchive_Props

IMP_IInArchive_ArcProps_NO
/*
IMP_IInArchive_ArcProps

STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
  COM_TRY_BEGIN
  NWindows::NCOM::CPropVariant prop;
  switch(propID)
  {
    case kpidNumBlocks:
    {
      UInt64 numBlocks = 0;
      for (int i = 0; i < m_Database.Sections.Size(); i++)
      {
        const CSectionInfo &s = m_Database.Sections[i];
        for (int j = 0; j < s.Methods.Size(); j++)
        {
          const CMethodInfo &m = s.Methods[j];
          if (m.IsLzx())
            numBlocks += m.LzxInfo.ResetTable.GetNumBlocks();
        }
      }
      prop = numBlocks;
      break;
    }
  }
  prop.Detach(value);
  return S_OK;
  COM_TRY_END
}
*/

STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID,  PROPVARIANT *value)
{
  COM_TRY_BEGIN
  NWindows::NCOM::CPropVariant prop;
  if (m_Database.NewFormat)
  {
    switch(propID)
    {
      case kpidSize:
        prop = (UInt64)m_Database.NewFormatString.Length();
      break;
    }
    prop.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);
        }
        prop = NItemName::GetOSName2(us);
      }
      break;
    }
    case kpidIsDir:  prop = item.IsDir(); break;
    case kpidSize:  prop = item.Size; break;
    case kpidMethod:
    {
      if (!item.IsDir())
        if (item.Section == 0)
          prop = L"Copy";
        else if (item.Section < m_Database.Sections.Size())
          prop = m_Database.Sections[(int)item.Section].GetMethodName();
      break;
    }
    case kpidBlock:
      if (m_Database.LowLevel)
        prop = item.Section;
      else if (item.Section != 0)
        prop = m_Database.GetFolder(index);
      break;
    
    #ifdef _CHM_DETAILS
    
    case kpidSection:  prop = (UInt32)item.Section; break;
    case kpidOffset:  prop = (UInt32)item.Offset; break;

    #endif
  }
  prop.Detach(value);
  return S_OK;
  COM_TRY_END
}

class CProgressImp: public CProgressVirt
{
  CMyComPtr<IArchiveOpenCallback> _callback;
public:
  STDMETHOD(SetTotal)(const UInt64 *numFiles);
  STDMETHOD(SetCompleted)(const UInt64 *numFiles);
  CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {};
};

STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles)
{
  if (_callback)
    return _callback->SetCompleted(numFiles, NULL);
  return S_OK;
}

STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)
{
  if (_callback)
    return _callback->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;
    // CProgressImp progressImp(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(UInt64 maxSize);
};

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 function
HRESULT 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;
      if (fileOffset > m_PosInSection)
      {
        UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size));
        realProcessed += numBytesToWrite;
        if (processedSize != NULL)
          *processedSize = realProcessed;
        data = (const void *)((const Byte *)data + numBytesToWrite);
        size -= numBytesToWrite;
        m_PosInSection += numBytesToWrite;

⌨️ 快捷键说明

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