arjhandler.cpp

来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 484 行

CPP
484
字号
// ArjHandler.cpp#include "StdAfx.h"#include "Common/Defs.h"#include "Common/CRC.h"#include "Common/StringConvert.h"#include "Common/ComTry.h"#include "Windows/Time.h"#include "Windows/PropVariant.h"#include "ArjHandler.h"#include "../../ICoder.h"#include "../../Common/StreamObjects.h"#include "../../Common/ProgressUtils.h"#include "../../Common/LimitedStreams.h"#include "../../Compress/Copy/CopyCoder.h"#include "../../Compress/Arj/ArjDecoder1.h"#include "../../Compress/Arj/ArjDecoder2.h"#include "../Common/ItemNameUtils.h"#include "../Common/OutStreamWithCRC.h"using namespace NWindows;using namespace NTime;namespace NArchive {namespace NArj{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 int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);const wchar_t *kUnknownOS = L"Unknown";/*enum // PropID{  kpidHostOS = kpidUserDefined,  kpidUnPackVersion,   kpidMethod, };*/STATPROPSTG kProperties[] = {  { NULL, kpidPath, VT_BSTR},  { NULL, kpidIsFolder, VT_BOOL},  { NULL, kpidSize, VT_UI8},  { NULL, kpidPackedSize, VT_UI8},  { NULL, kpidLastWriteTime, VT_FILETIME},  { NULL, kpidAttributes, VT_UI4},  { NULL, kpidEncrypted, VT_BOOL},  // { NULL, kpidCommented, VT_BOOL},      { NULL, kpidCRC, VT_UI4},  { NULL, kpidMethod, VT_UI1},  { NULL, kpidHostOS, VT_BSTR}  // { L"UnPack Version", kpidUnPackVersion, VT_UI1},  // { L"Method", kpidMethod, VT_UI1},  // { L"Host OS", kpidHostOS, VT_BSTR}};CHandler::CHandler(){}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;  *name = 0;  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_NOTIMPL;}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 propVariant;  const CItemEx &item = _items[index];  switch(propID)  {    case kpidPath:      propVariant =       NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP));      /*                     NItemName::GetOSName2(          MultiByteToUnicodeString(item.Name, item.GetCodePage()));          */      break;    case kpidIsFolder:      propVariant = item.IsDirectory();      break;    case kpidSize:      propVariant = item.Size;      break;    case kpidPackedSize:      propVariant = item.PackSize;      break;    case kpidLastWriteTime:    {      FILETIME localFileTime, utcFileTime;      if (DosTimeToFileTime(item.ModifiedTime, localFileTime))      {        if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))          utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;      }      else        utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;      propVariant = utcFileTime;      break;    }    case kpidAttributes:      propVariant = item.GetWinAttributes();      break;    case kpidEncrypted:      propVariant = item.IsEncrypted();      break;    /*    case kpidCommented:      propVariant = item.IsCommented();      break;    */    case kpidCRC:      propVariant = item.FileCRC;      break;    case kpidMethod:      propVariant = item.Method;      break;    case kpidHostOS:      propVariant = (item.HostOS < kNumHostOSes) ?        (kHostOS[item.HostOS]) : kUnknownOS;      break;  }  propVariant.Detach(value);  return S_OK;  COM_TRY_END}/*class CPropgressImp: public CProgressVirt{public:  CMyComPtr<IArchiveOpenCallback> Callback;  STDMETHOD(SetCompleted)(const UInt64 *numFiles);};STDMETHODIMP CPropgressImp::SetCompleted(const UInt64 *numFiles){  if (Callback)    return Callback->SetCompleted(numFiles, NULL);  return S_OK;}*/STDMETHODIMP CHandler::Open(IInStream *inStream,     const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback){  COM_TRY_BEGIN  try  {    _items.Clear();    CInArchive archive;    if(!archive.Open(inStream, maxCheckStartPosition))      return S_FALSE;    if (callback != NULL)    {      RINOK(callback->SetTotal(NULL, NULL));      UInt64 numFiles = _items.Size();      RINOK(callback->SetCompleted(&numFiles, NULL));    }    while(true)    {      CItemEx itemInfo;      bool filled;      HRESULT result = archive.GetNextItem(filled, itemInfo);      if (result == S_FALSE)        return S_FALSE;      if (result != S_OK)        return S_FALSE;      if (!filled)        break;      _items.Add(itemInfo);      archive.IncreaseRealPosition(itemInfo.PackSize);      if (callback != NULL)      {        UInt64 numFiles = _items.Size();        RINOK(callback->SetCompleted(&numFiles, NULL));      }    }    _stream = inStream;  }  catch(...)  {    return S_FALSE;  }  COM_TRY_END  return S_OK;}STDMETHODIMP CHandler::Close(){  _items.Clear();  _stream.Release();  return S_OK;}//////////////////////////////////////// CHandler::DecompressItemsSTDMETHODIMP 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 CItemEx &itemInfo = _items[allFilesMode ? i : indices[i]];    totalUnPacked += itemInfo.Size;    totalPacked += itemInfo.PackSize;  }  extractCallback->SetTotal(totalUnPacked);  UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;  UInt64 currentItemUnPacked, currentItemPacked;    CMyComPtr<ICompressCoder> arj1Decoder;  CMyComPtr<ICompressCoder> arj2Decoder;  CMyComPtr<ICompressCoder> copyCoder;  for(i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,      currentTotalPacked += currentItemPacked)  {    currentItemUnPacked = 0;    currentItemPacked = 0;    RINOK(extractCallback->SetCompleted(&currentTotalUnPacked));    CMyComPtr<ISequentialOutStream> realOutStream;    Int32 askMode;    askMode = testMode ? NArchive::NExtract::NAskMode::kTest :        NArchive::NExtract::NAskMode::kExtract;    Int32 index = allFilesMode ? i : indices[i];    const CItemEx &itemInfo = _items[index];    RINOK(extractCallback->GetStream(index, &realOutStream, askMode));    if(itemInfo.IsDirectory())    {      // if (!testMode)      {        RINOK(extractCallback->PrepareOperation(askMode));        RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));      }      continue;    }    if (!testMode && (!realOutStream))       continue;    RINOK(extractCallback->PrepareOperation(askMode));    currentItemUnPacked = itemInfo.Size;    currentItemPacked = itemInfo.PackSize;    {      COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;      CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);      outStreamSpec->Init(realOutStream);      realOutStream.Release();            CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;      CMyComPtr<ISequentialInStream> inStream(streamSpec);            UInt64 pos;      _stream->Seek(itemInfo.DataPosition, STREAM_SEEK_SET, &pos);      streamSpec->Init(_stream, itemInfo.PackSize);      CLocalProgress *localProgressSpec = new CLocalProgress;      CMyComPtr<ICompressProgressInfo> progress = localProgressSpec;      localProgressSpec->Init(extractCallback, false);      CLocalCompressProgressInfo *localCompressProgressSpec =           new CLocalCompressProgressInfo;      CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;      localCompressProgressSpec->Init(progress,           &currentTotalPacked,          &currentTotalUnPacked);      if (itemInfo.IsEncrypted())      {        RINOK(extractCallback->SetOperationResult(          NArchive::NExtract::NOperationResult::kUnSupportedMethod));        continue;      }      HRESULT result;      switch(itemInfo.Method)      {        case NFileHeader::NCompressionMethod::kStored:          {            if(!copyCoder)              copyCoder = new NCompress::CCopyCoder;            try            {              if (itemInfo.IsEncrypted())              {                RINOK(extractCallback->SetOperationResult(                  NArchive::NExtract::NOperationResult::kUnSupportedMethod));                continue;              }              else              {                result = copyCoder->Code(inStream, outStream,                    NULL, NULL, compressProgress);              }              if (result == S_FALSE)                throw "data error";              if (result != S_OK)                return result;            }            catch(...)            {              outStream.Release();              RINOK(extractCallback->SetOperationResult(                  NArchive::NExtract::NOperationResult::kDataError));              continue;            }            break;          }        case NFileHeader::NCompressionMethod::kCompressed1a:        case NFileHeader::NCompressionMethod::kCompressed1b:        case NFileHeader::NCompressionMethod::kCompressed1c:          {            if(!arj1Decoder)            {              arj1Decoder = new NCompress::NArj::NDecoder1::CCoder;            }            try            {              if (itemInfo.IsEncrypted())              {                RINOK(extractCallback->SetOperationResult(                  NArchive::NExtract::NOperationResult::kUnSupportedMethod));                continue;              }              else              {                result = arj1Decoder->Code(inStream, outStream,                    NULL, &currentItemUnPacked, compressProgress);              }              if (result == S_FALSE)                throw "data error";              if (result != S_OK)                return result;            }            catch(...)            {              outStream.Release();              RINOK(extractCallback->SetOperationResult(                  NArchive::NExtract::NOperationResult::kDataError));              continue;            }            break;          }        case NFileHeader::NCompressionMethod::kCompressed2:          {            if(!arj2Decoder)            {              arj2Decoder = new NCompress::NArj::NDecoder2::CCoder;            }            try            {              if (itemInfo.IsEncrypted())              {                RINOK(extractCallback->SetOperationResult(                  NArchive::NExtract::NOperationResult::kUnSupportedMethod));                continue;              }              else              {                result = arj2Decoder->Code(inStream, outStream,                    NULL, &currentItemUnPacked, compressProgress);              }              if (result == S_FALSE)                throw "data error";              if (result != S_OK)                return result;            }            catch(...)            {              outStream.Release();              RINOK(extractCallback->SetOperationResult(                  NArchive::NExtract::NOperationResult::kDataError));              continue;            }            break;          }        default:            RINOK(extractCallback->SetOperationResult(                NArchive::NExtract::NOperationResult::kUnSupportedMethod));            continue;      }      bool crcOK = outStreamSpec->GetCRC() == itemInfo.FileCRC;      outStream.Release();      if(crcOK)        RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK))      else        RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kCRCError))    }  }  return S_OK;  COM_TRY_END}}}

⌨️ 快捷键说明

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