mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 09:14:58 -06:00
240 lines
6.1 KiB
C++
Executable File
240 lines
6.1 KiB
C++
Executable File
// ComHandler.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "Common/ComTry.h"
|
|
|
|
#include "Windows/PropVariant.h"
|
|
|
|
#include "../../Common/LimitedStreams.h"
|
|
#include "../../Common/ProgressUtils.h"
|
|
#include "../../Common/StreamUtils.h"
|
|
|
|
#include "../../Compress/CopyCoder.h"
|
|
|
|
#include "ComHandler.h"
|
|
|
|
namespace NArchive {
|
|
namespace NCom {
|
|
|
|
STATPROPSTG kProps[] =
|
|
{
|
|
{ NULL, kpidPath, VT_BSTR},
|
|
{ NULL, kpidIsDir, VT_BOOL},
|
|
{ NULL, kpidSize, VT_UI8},
|
|
{ NULL, kpidPackSize, VT_UI8},
|
|
{ NULL, kpidCTime, VT_FILETIME},
|
|
{ NULL, kpidMTime, VT_FILETIME}
|
|
};
|
|
|
|
STATPROPSTG kArcProps[] =
|
|
{
|
|
{ NULL, kpidClusterSize, VT_UI4},
|
|
{ NULL, kpidSectorSize, VT_UI4}
|
|
};
|
|
|
|
IMP_IInArchive_Props
|
|
IMP_IInArchive_ArcProps
|
|
|
|
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
|
{
|
|
COM_TRY_BEGIN
|
|
NWindows::NCOM::CPropVariant prop;
|
|
switch(propID)
|
|
{
|
|
case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break;
|
|
case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; 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;
|
|
const CRef &ref = _db.Refs[index];
|
|
const CItem &item = _db.Items[ref.Did];
|
|
|
|
switch(propID)
|
|
{
|
|
case kpidPath: prop = _db.GetItemPath(index); break;
|
|
case kpidIsDir: prop = item.IsDir(); break;
|
|
case kpidCTime: prop = item.CTime; break;
|
|
case kpidMTime: prop = item.MTime; break;
|
|
case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break;
|
|
case kpidSize: if (!item.IsDir()) prop = item.Size; break;
|
|
}
|
|
prop.Detach(value);
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
|
const UInt64 * /* maxCheckStartPosition */,
|
|
IArchiveOpenCallback * /* openArchiveCallback */)
|
|
{
|
|
COM_TRY_BEGIN
|
|
Close();
|
|
try
|
|
{
|
|
if (_db.Open(inStream) != S_OK)
|
|
return S_FALSE;
|
|
_stream = inStream;
|
|
}
|
|
catch(...) { return S_FALSE; }
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
STDMETHODIMP CHandler::Close()
|
|
{
|
|
_db.Clear();
|
|
_stream.Release();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
|
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
|
{
|
|
COM_TRY_BEGIN
|
|
bool testMode = (_aTestMode != 0);
|
|
bool allFilesMode = (numItems == UInt32(-1));
|
|
if (allFilesMode)
|
|
numItems = _db.Refs.Size();
|
|
if (numItems == 0)
|
|
return S_OK;
|
|
UInt32 i;
|
|
UInt64 totalSize = 0;
|
|
for(i = 0; i < numItems; i++)
|
|
{
|
|
const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did];
|
|
if (!item.IsDir())
|
|
totalSize += item.Size;
|
|
}
|
|
RINOK(extractCallback->SetTotal(totalSize));
|
|
|
|
UInt64 totalPackSize;
|
|
totalSize = totalPackSize = 0;
|
|
|
|
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
|
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
|
|
|
CLocalProgress *lps = new CLocalProgress;
|
|
CMyComPtr<ICompressProgressInfo> progress = lps;
|
|
lps->Init(extractCallback, false);
|
|
|
|
for (i = 0; i < numItems; i++)
|
|
{
|
|
lps->InSize = totalPackSize;
|
|
lps->OutSize = totalSize;
|
|
RINOK(lps->SetCur());
|
|
Int32 index = allFilesMode ? i : indices[i];
|
|
const CItem &item = _db.Items[_db.Refs[index].Did];
|
|
|
|
CMyComPtr<ISequentialOutStream> outStream;
|
|
Int32 askMode = testMode ?
|
|
NArchive::NExtract::NAskMode::kTest :
|
|
NArchive::NExtract::NAskMode::kExtract;
|
|
RINOK(extractCallback->GetStream(index, &outStream, askMode));
|
|
|
|
if (item.IsDir())
|
|
{
|
|
RINOK(extractCallback->PrepareOperation(askMode));
|
|
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
|
continue;
|
|
}
|
|
|
|
totalPackSize += _db.GetItemPackSize(item.Size);
|
|
totalSize += item.Size;
|
|
|
|
if (!testMode && (!outStream))
|
|
continue;
|
|
RINOK(extractCallback->PrepareOperation(askMode));
|
|
Int32 res = NArchive::NExtract::NOperationResult::kDataError;
|
|
CMyComPtr<ISequentialInStream> inStream;
|
|
HRESULT hres = GetStream(index, &inStream);
|
|
if (hres == S_FALSE)
|
|
res = NArchive::NExtract::NOperationResult::kDataError;
|
|
else if (hres == E_NOTIMPL)
|
|
res = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
|
|
else
|
|
{
|
|
RINOK(hres);
|
|
if (inStream)
|
|
{
|
|
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
|
if (copyCoderSpec->TotalSize == item.Size)
|
|
res = NArchive::NExtract::NOperationResult::kOK;
|
|
}
|
|
}
|
|
outStream.Release();
|
|
RINOK(extractCallback->SetOperationResult(res));
|
|
}
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
|
{
|
|
*numItems = _db.Refs.Size();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
|
{
|
|
COM_TRY_BEGIN
|
|
*stream = 0;
|
|
const CItem &item = _db.Items[_db.Refs[index].Did];
|
|
CClusterInStream *streamSpec = new CClusterInStream;
|
|
CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
|
|
streamSpec->Stream = _stream;
|
|
streamSpec->StartOffset = 0;
|
|
|
|
bool isLargeStream = _db.IsLargeStream(item.Size);
|
|
int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits;
|
|
streamSpec->BlockSizeLog = bsLog;
|
|
streamSpec->Size = item.Size;
|
|
|
|
UInt32 clusterSize = (UInt32)1 << bsLog;
|
|
UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
|
|
if (numClusters64 >= ((UInt32)1 << 31))
|
|
return E_NOTIMPL;
|
|
streamSpec->Vector.Reserve((int)numClusters64);
|
|
UInt32 sid = item.Sid;
|
|
UInt64 size = item.Size;
|
|
|
|
if (size != 0)
|
|
{
|
|
for (;; size -= clusterSize)
|
|
{
|
|
if (isLargeStream)
|
|
{
|
|
if (sid >= _db.FatSize)
|
|
return S_FALSE;
|
|
streamSpec->Vector.Add(sid + 1);
|
|
sid = _db.Fat[sid];
|
|
}
|
|
else
|
|
{
|
|
UInt64 val;
|
|
if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32)
|
|
return S_FALSE;
|
|
streamSpec->Vector.Add((UInt32)val);
|
|
sid = _db.Mat[sid];
|
|
}
|
|
if (size <= clusterSize)
|
|
break;
|
|
}
|
|
}
|
|
if (sid != NFatID::kEndOfChain)
|
|
return S_FALSE;
|
|
RINOK(streamSpec->InitAndSeek());
|
|
*stream = streamTemp.Detach();
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
}}
|