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 + -
显示快捷键?