📄 arjhandler.cpp
字号:
bool filled;
RINOK(ReadBlock(filled));
if (!filled)
return S_OK;
if (Callback && (i & 0xFF) == 0)
RINOK(Callback->SetCompleted(&NumFiles, &NumBytes));
}
}
HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit)
{
UInt64 position = 0;
RINOK(FindAndReadMarker(Stream, searchHeaderSizeLimit, position));
RINOK(Stream->Seek(position, STREAM_SEEK_SET, NULL));
bool filled;
RINOK(ReadSignatureAndBlock(filled));
if (!filled)
return S_FALSE;
RINOK(Header.Parse(_block, _blockSize));
return SkeepExtendedHeaders();
}
HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
{
RINOK(ReadSignatureAndBlock(filled));
if (!filled)
return S_OK;
filled = false;
RINOK(item.Parse(_block, _blockSize));
/*
UInt32 extraData;
if ((header.Flags & NFileHeader::NFlags::kExtFile) != 0)
extraData = GetUInt32FromMemLE(_block + pos);
*/
RINOK(SkeepExtendedHeaders());
filled = true;
return S_OK;
}
class CHandler:
public IInArchive,
public CMyUnknownImp
{
public:
MY_UNKNOWN_IMP1(IInArchive)
INTERFACE_IInArchive(;)
HRESULT Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *callback);
private:
CInArchive _archive;
CObjectVector<CItem> _items;
CMyComPtr<IInStream> _stream;
};
const wchar_t *kHostOS[] =
{
L"MSDOS",
L"PRIMOS",
L"UNIX",
L"AMIGA",
L"MAC",
L"OS/2",
L"APPLE GS",
L"ATARI ST",
L"NEXT",
L"VAX VMS",
L"WIN95"
};
const wchar_t *kUnknownOS = L"Unknown";
const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
STATPROPSTG kArcProps[] =
{
{ NULL, kpidName, VT_BSTR},
{ NULL, kpidCTime, VT_BSTR},
{ NULL, kpidMTime, VT_BSTR},
{ NULL, kpidHostOS, VT_BSTR},
{ NULL, kpidComment, VT_BSTR}
};
STATPROPSTG kProps[] =
{
{ NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL},
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidPackSize, VT_UI8},
{ NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidAttrib, VT_UI4},
{ NULL, kpidEncrypted, VT_BOOL},
{ NULL, kpidCRC, VT_UI4},
{ NULL, kpidMethod, VT_UI1},
{ NULL, kpidHostOS, VT_BSTR},
{ NULL, kpidComment, VT_BSTR}
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
static void SetTime(UInt32 dosTime, NWindows::NCOM::CPropVariant &prop)
{
if (dosTime == 0)
return;
FILETIME localFileTime, utc;
if (NTime::DosTimeToFileTime(dosTime, localFileTime))
{
if (!LocalFileTimeToFileTime(&localFileTime, &utc))
utc.dwHighDateTime = utc.dwLowDateTime = 0;
}
else
utc.dwHighDateTime = utc.dwLowDateTime = 0;
prop = utc;
}
static void SetHostOS(Byte hostOS, NWindows::NCOM::CPropVariant &prop)
{
prop = hostOS < kNumHostOSes ? kHostOS[hostOS] : kUnknownOS;
}
static void SetUnicodeString(const AString &s, NWindows::NCOM::CPropVariant &prop)
{
if (!s.IsEmpty())
prop = MultiByteToUnicodeString(s, CP_OEMCP);
}
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
switch(propID)
{
case kpidName: SetUnicodeString(_archive.Header.Name, prop); break;
case kpidCTime: SetTime(_archive.Header.CTime, prop); break;
case kpidMTime: SetTime(_archive.Header.MTime, prop); break;
case kpidHostOS: SetHostOS(_archive.Header.HostOS, prop); break;
case kpidComment: SetUnicodeString(_archive.Header.Comment, prop); break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
*numItems = _items.Size();
return S_OK;
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
const CItem &item = _items[index];
switch(propID)
{
case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
case kpidIsDir: prop = item.IsDir(); break;
case kpidSize: prop = item.Size; break;
case kpidPackSize: prop = item.PackSize; break;
case kpidAttrib: prop = item.GetWinAttributes(); break;
case kpidEncrypted: prop = item.IsEncrypted(); break;
case kpidCRC: prop = item.FileCRC; break;
case kpidMethod: prop = item.Method; break;
case kpidHostOS: SetHostOS(item.HostOS, prop); break;
case kpidMTime: SetTime(item.MTime, prop); break;
case kpidComment: SetUnicodeString(item.Comment, prop); break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
HRESULT CHandler::Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *callback)
{
Close();
UInt64 endPos = 0;
if (callback != NULL)
{
RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
}
_archive.Stream = inStream;
_archive.Callback = callback;
_archive.NumFiles = _archive.NumBytes = 0;
RINOK(_archive.Open(maxCheckStartPosition));
if (callback != NULL)
RINOK(callback->SetTotal(NULL, &endPos));
for (;;)
{
CItem item;
bool filled;
RINOK(_archive.GetNextItem(filled, item));
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition));
if (!filled)
break;
_items.Add(item);
if (inStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL) != S_OK)
throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
_archive.NumFiles = _items.Size();
_archive.NumBytes = item.DataPosition;
if (callback != NULL && _items.Size() % 100 == 0)
{
RINOK(callback->SetCompleted(&_archive.NumFiles, &_archive.NumBytes));
}
}
return S_OK;
}
STDMETHODIMP CHandler::Open(IInStream *inStream,
const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
{
COM_TRY_BEGIN
HRESULT res;
try
{
res = Open2(inStream, maxCheckStartPosition, callback);
if (res == S_OK)
{
_stream = inStream;
return S_OK;
}
}
catch(const CInArchiveException &) { res = S_FALSE; }
Close();
return res;
COM_TRY_END
}
STDMETHODIMP CHandler::Close()
{
_items.Clear();
_stream.Release();
return S_OK;
}
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
bool testMode = (testModeSpec != 0);
UInt64 totalUnpacked = 0, totalPacked = 0;
bool allFilesMode = (numItems == UInt32(-1));
if (allFilesMode)
numItems = _items.Size();
if (numItems == 0)
return S_OK;
UInt32 i;
for (i = 0; i < numItems; i++)
{
const CItem &item = _items[allFilesMode ? i : indices[i]];
totalUnpacked += item.Size;
totalPacked += item.PackSize;
}
extractCallback->SetTotal(totalUnpacked);
totalUnpacked = totalPacked = 0;
UInt64 curUnpacked, curPacked;
CMyComPtr<ICompressCoder> arj1Decoder;
CMyComPtr<ICompressCoder> arj2Decoder;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream(inStreamSpec);
inStreamSpec->SetStream(_stream);
for (i = 0; i < numItems; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
{
lps->InSize = totalPacked;
lps->OutSize = totalUnpacked;
RINOK(lps->SetCur());
curUnpacked = curPacked = 0;
CMyComPtr<ISequentialOutStream> realOutStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
Int32 index = allFilesMode ? i : indices[i];
const CItem &item = _items[index];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
if (item.IsDir())
{
// if (!testMode)
{
RINOK(extractCallback->PrepareOperation(askMode));
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
}
continue;
}
if (!testMode && (!realOutStream))
continue;
RINOK(extractCallback->PrepareOperation(askMode));
curUnpacked = item.Size;
curPacked = item.PackSize;
{
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
outStreamSpec->SetStream(realOutStream);
realOutStream.Release();
outStreamSpec->Init();
inStreamSpec->Init(item.PackSize);
UInt64 pos;
_stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos);
HRESULT result = S_OK;
Int32 opRes = NExtract::NOperationResult::kOK;
if (item.IsEncrypted())
opRes = NExtract::NOperationResult::kUnSupportedMethod;
else
{
switch(item.Method)
{
case NFileHeader::NCompressionMethod::kStored:
{
result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
result = S_FALSE;
break;
}
case NFileHeader::NCompressionMethod::kCompressed1a:
case NFileHeader::NCompressionMethod::kCompressed1b:
case NFileHeader::NCompressionMethod::kCompressed1c:
{
if (!arj1Decoder)
arj1Decoder = new NCompress::NArj::NDecoder1::CCoder;
result = arj1Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
break;
}
case NFileHeader::NCompressionMethod::kCompressed2:
{
if (!arj2Decoder)
arj2Decoder = new NCompress::NArj::NDecoder2::CCoder;
result = arj2Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
break;
}
default:
opRes = NExtract::NOperationResult::kUnSupportedMethod;
}
}
if (opRes == NExtract::NOperationResult::kOK)
{
if (result == S_FALSE)
opRes = NExtract::NOperationResult::kDataError;
else
{
RINOK(result);
opRes = (outStreamSpec->GetCRC() == item.FileCRC) ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kCRCError;
}
}
outStream.Release();
RINOK(extractCallback->SetOperationResult(opRes));
}
}
return S_OK;
COM_TRY_END
}
static IInArchive *CreateArc() { return new CHandler; }
static CArcInfo g_ArcInfo =
{ L"Arj", L"arj", 0, 4, { 0x60, 0xEA }, 2, false, CreateArc, 0 };
REGISTER_ARC(Arj)
}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -