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

📄 arjhandler.cpp

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