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

📄 dmghandler.cpp

📁 7z一个高压缩比的压缩程序源代码,重要的是里面的算法值得学习
💻 CPP
📖 第 1 页 / 共 2 页
字号:
          startPos = b.PackPos;
        }
        startPos += b.PackSize;
        */

        file.Blocks.Add(b);

        PRF(printf("\nType=%8x  m[1]=%8x  uPos=%8x  uSize=%7x  pPos=%8x  pSize=%7x",
            b.Type, Get32(p + 4), (UInt32)b.UnpPos, (UInt32)b.UnpSize, (UInt32)b.PackPos, (UInt32)b.PackSize));
      }
    }
    int itemIndex = _files.Add(file);
    if (file.Blocks.Size() > 0)
    {
      // if (file.Name.Find("HFS") >= 0)
        _fileIndices.Add(itemIndex);
    }
  }
  return S_OK;
}

STDMETHODIMP CHandler::Open(IInStream *stream,
    const UInt64 * /* maxCheckStartPosition */,
    IArchiveOpenCallback * /* openArchiveCallback */)
{
  COM_TRY_BEGIN
  {
    Close();
    if (Open2(stream) != S_OK)
      return S_FALSE;
    _inStream = stream;
  }
  return S_OK;
  COM_TRY_END
}

STDMETHODIMP CHandler::Close()
{
  _inStream.Release();
  _fileIndices.Clear();
  _files.Clear();
  _xml.Empty();
  return S_OK;
}

STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
  *numItems = _fileIndices.Size()
    #ifdef DMG_SHOW_RAW
    + _files.Size() + 1;
    #endif
  ;
  return S_OK;
}

#define RAW_PREFIX L"raw" WSTRING_PATH_SEPARATOR

STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
  COM_TRY_BEGIN
  NWindows::NCOM::CPropVariant prop;
  
  #ifdef DMG_SHOW_RAW
  if ((int)index == _fileIndices.Size())
  {
    switch(propID)
    {
      case kpidPath:
        prop = RAW_PREFIX L"a.xml";
        break;
      case kpidSize:
      case kpidPackedSize:
        prop = (UInt64)_xml.Length();
        break;
    }
  }
  else if ((int)index > _fileIndices.Size())
  {
    int rawIndex = (int)index - (_fileIndices.Size() + 1);
    switch(propID)
    {
      case kpidPath:
      {
        wchar_t s[32] = RAW_PREFIX;
        ConvertUInt64ToString(rawIndex, s + MyStringLen(s));
        prop = s;
        break;
      }
      case kpidSize:
      case kpidPackedSize:
        prop = (UInt64)_files[rawIndex].Raw.GetCapacity();
        break;
    }
  }
  else
  #endif
  {
    int itemIndex = _fileIndices[index];
    const CFile &item = _files[itemIndex];
    switch(propID)
    {
      case kpidMethod:
      {
        CMethods m;
        m.Update(item);
        UString resString = m.GetString();
        if (!resString.IsEmpty())
          prop = resString;
        break;
      }
      
      // case kpidExtension: prop = L"hfs"; break;

      case kpidPath:
      {
        // break;
        UString name;
        wchar_t s[32];
        ConvertUInt64ToString(index, s);
        name = s;
        int num = 10;
        int numDigits;
        for (numDigits = 1; num < _fileIndices.Size(); numDigits++)
          num *= 10;
        while (name.Length() < numDigits)
          name = L'0' + name;

        AString subName;
        int pos1 = item.Name.Find('(');
        if (pos1 >= 0)
        {
          pos1++;
          int pos2 = item.Name.Find(')', pos1);
          if (pos2 >= 0)
          {
            subName = item.Name.Mid(pos1, pos2 - pos1);
            pos1 = subName.Find(':');
            if (pos1 >= 0)
              subName = subName.Left(pos1);
          }
        }
        subName.Trim();
        if (!subName.IsEmpty())
        {
          if (subName == "Apple_HFS")
            subName = "hfs";
          else if (subName == "Apple_HFSX")
            subName = "hfsx";
          else if (subName == "Apple_Free")
            subName = "free";
          else if (subName == "DDM")
            subName = "ddm";
          UString name2;
          ConvertUTF8ToUnicode(subName, name2);
          name += L'.';
          name += name2;
        }
        else
        {
          UString name2;
          ConvertUTF8ToUnicode(item.Name, name2);
          if (!name2.IsEmpty())
            name += L" - ";
          name += name2;
        }
        prop = name;
        break;
      }
      case kpidComment:
      {
        UString name;
        ConvertUTF8ToUnicode(item.Name, name);
        prop = name;
        break;
      }

      case kpidSize:  prop = item.GetUnpackSize(); break;
      case kpidPackSize:  prop = item.GetPackSize(); break;
    }
  }
  prop.Detach(value);
  return S_OK;
  COM_TRY_END
}

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 = _files.Size();
  if (numItems == 0)
    return S_OK;
  UInt64 totalSize = 0;
  UInt32 i;
  for (i = 0; i < numItems; i++)
  {
    int index = (int)(allFilesMode ? i : indices[i]);
    #ifdef DMG_SHOW_RAW
    if (index == _fileIndices.Size())
      totalSize += _xml.Length();
    else if (index > _fileIndices.Size())
      totalSize += _files[index - (_fileIndices.Size() + 1)].Raw.GetCapacity();
    else
    #endif
      totalSize += _files[_fileIndices[index]].GetUnpackSize();
  }
  extractCallback->SetTotal(totalSize);

  UInt64 currentPackTotal = 0;
  UInt64 currentUnpTotal = 0;
  UInt64 currentPackSize = 0;
  UInt64 currentUnpSize = 0;

  const UInt32 kZeroBufSize = (1 << 14);
  CByteBuffer zeroBuf;
  zeroBuf.SetCapacity(kZeroBufSize);
  memset(zeroBuf, 0, kZeroBufSize);
  
  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

  NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
  CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;

  NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
  CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(extractCallback, false);

  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
  CMyComPtr<ISequentialInStream> inStream(streamSpec);
  streamSpec->SetStream(_inStream);

  for (i = 0; i < numItems; i++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize)
  {
    lps->InSize = currentPackTotal;
    lps->OutSize = currentUnpTotal;
    currentPackSize = 0;
    currentUnpSize = 0;
    RINOK(lps->SetCur());
    CMyComPtr<ISequentialOutStream> realOutStream;
    Int32 askMode = testMode ?
        NArchive::NExtract::NAskMode::kTest :
        NArchive::NExtract::NAskMode::kExtract;
    Int32 index = allFilesMode ? i : indices[i];
    // const CItemEx &item = _files[index];
    RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
    
    
    if (!testMode && (!realOutStream))
      continue;
    RINOK(extractCallback->PrepareOperation(askMode));

    CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
    CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
    outStreamSpec->SetStream(realOutStream);
    
    realOutStream.Release();

    Int32 opRes = NArchive::NExtract::NOperationResult::kOK;
    #ifdef DMG_SHOW_RAW
    if (index > _fileIndices.Size())
    {
      const CByteBuffer &buf = _files[index - (_fileIndices.Size() + 1)].Raw;
      outStreamSpec->Init(buf.GetCapacity());
      RINOK(WriteStream(outStream, buf, buf.GetCapacity()));
      currentPackSize = currentUnpSize = buf.GetCapacity();
    }
    else if (index == _fileIndices.Size())
    {
      outStreamSpec->Init(_xml.Length());
      RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length()));
      currentPackSize = currentUnpSize = _xml.Length();
    }
    else
    #endif
    {
      const CFile &item = _files[_fileIndices[index]];
      currentPackSize = item.GetPackSize();
      currentUnpSize = item.GetUnpackSize();

      UInt64 unpPos = 0;
      UInt64 packPos = 0;
      {
        for (int j = 0; j < item.Blocks.Size(); j++)
        {
          lps->InSize = currentPackTotal + packPos;
          lps->OutSize = currentUnpTotal + unpPos;
          RINOK(lps->SetCur());

          const CBlock &block = item.Blocks[j];

          packPos += block.PackSize;
          if (block.UnpPos != unpPos)
          {
            opRes = NArchive::NExtract::NOperationResult::kDataError;
            break;
          }

          RINOK(_inStream->Seek(block.PackPos, STREAM_SEEK_SET, NULL));
          streamSpec->Init(block.PackSize);
          // UInt64 startSize = outStreamSpec->GetSize();
          bool realMethod = true;
          outStreamSpec->Init(block.UnpSize);
          HRESULT res = S_OK;

          switch(block.Type)
          {
            case METHOD_ZERO_0:
            case METHOD_ZERO_2:
              realMethod = false;
              if (block.PackSize != 0)
                opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
              break;

            case METHOD_COPY:
              if (block.UnpSize != block.PackSize)
              {
                opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
                break;
              }
              res = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
              break;
            
            case METHOD_ZLIB:
            {
              res = zlibCoder->Code(inStream, outStream, NULL, NULL, progress);
              if (res != S_OK)
                break;
              break;
            }

            case METHOD_BZIP2:
            {
              res = bzip2Coder->Code(inStream, outStream, NULL, NULL, progress);
              if (res == S_OK)
                if (streamSpec->GetSize() != block.PackSize)
                  opRes = NArchive::NExtract::NOperationResult::kDataError;
              break;
            }
            
            default:
              opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
              break;
          }
          if (res != S_OK)
          {
            if (res != S_FALSE)
              return res;
            if (opRes == NArchive::NExtract::NOperationResult::kOK)
              opRes = NArchive::NExtract::NOperationResult::kDataError;
          }
          unpPos += block.UnpSize;
          if (!outStreamSpec->IsFinishedOK())
          {
            if (realMethod && opRes == NArchive::NExtract::NOperationResult::kOK)
              opRes = NArchive::NExtract::NOperationResult::kDataError;

            while (outStreamSpec->GetRem() != 0)
            {
              UInt64 rem = outStreamSpec->GetRem();
              UInt32 size = (UInt32)MyMin(rem, (UInt64)kZeroBufSize);
              RINOK(WriteStream(outStream, zeroBuf, size));
            }
          }
        }
      }
    }
    outStream.Release();
    RINOK(extractCallback->SetOperationResult(opRes));
  }
  return S_OK;
  COM_TRY_END
}

static IInArchive *CreateArc() { return new CHandler; }

static CArcInfo g_ArcInfo =
  { L"Dmg", L"dmg", 0, 0xE4, { 0 }, 0, false, CreateArc, 0 };

REGISTER_ARC(Dmg)

}}

⌨️ 快捷键说明

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