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

📄 cabin.cpp

📁 7-Zip 3.11的源码
💻 CPP
字号:
// Archive/CabIn.cpp

#include "StdAfx.h"

#include "Common/StringConvert.h"
#include "Common/MyCom.h"
#include "CabIn.h"
#include "Windows/Defs.h"
#include "../../Common/InBuffer.h"

namespace NArchive{
namespace NCab{

static HRESULT ReadBytes(IInStream *inStream, void *data, UINT32 size)
{
  UINT32 realProcessedSize;
  RINOK(inStream->Read(data, size, &realProcessedSize));
  if(realProcessedSize != size)
    return S_FALSE;
  return S_OK;
}

static HRESULT SafeRead(IInStream *inStream, void *data, UINT32 size)
{
  UINT32 realProcessedSize;
  RINOK(inStream->Read(data, size, &realProcessedSize));
  if(realProcessedSize != size)
    throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
  return S_OK;
}

static void SafeInByteRead(CInBuffer &inBuffer, void *data, UINT32 size)
{
  UINT32 realProcessedSize;
  inBuffer.ReadBytes(data, size, realProcessedSize);
  if(realProcessedSize != size)
    throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
}

static void SafeReadName(CInBuffer &inBuffer, AString &name)
{
  name.Empty();
  while(true)
  {
    BYTE b;
    if (!inBuffer.ReadByte(b))
      throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
    if (b == 0)
      return;
    name += char(b);
  }
}

HRESULT CInArchive::Open(IInStream *inStream, 
    const UINT64 *searchHeaderSizeLimit,
    CInArchiveInfo &inArchiveInfo, 
    CObjectVector<NHeader::CFolder> &folders,
    CObjectVector<CItem> &files,
    CProgressVirt *progressVirt)
{
  UINT64 startPosition;
  RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &startPosition));

  NHeader::NArchive::CBlock archiveHeader;

  {
    CInBuffer inBuffer;
    inBuffer.Init(inStream);
    UINT64 value = 0;
    const int kSignatureSize = sizeof(value);
    UINT64 kSignature64 = NHeader::NArchive::kSignature;
    while(true)
    {
      BYTE b;
      if (!inBuffer.ReadByte(b))
        return S_FALSE;
      value >>= 8;
      value |= ((UINT64)b) << ((kSignatureSize - 1) * 8);
      if (inBuffer.GetProcessedSize() >= kSignatureSize)
      {
        if (value == kSignature64)
          break;
        if (searchHeaderSizeLimit != NULL)
          if (inBuffer.GetProcessedSize() > (*searchHeaderSizeLimit))
            return S_FALSE;
      }
    }
    startPosition += inBuffer.GetProcessedSize() - kSignatureSize;
  }
  RINOK(inStream->Seek(startPosition, STREAM_SEEK_SET, NULL));
  RINOK(ReadBytes(inStream, &archiveHeader, sizeof(archiveHeader)));
  // if (archiveHeader.Signature != NHeader::NArchive::kSignature)
  //   return S_FALSE;
  
  if (archiveHeader.Reserved1 != 0 ||
      archiveHeader.Reserved2 != 0 ||
      archiveHeader.Reserved3 != 0)
    throw CInArchiveException(CInArchiveException::kUnsupported);

  inArchiveInfo.VersionMinor = archiveHeader.VersionMinor;
  inArchiveInfo.VersionMajor = archiveHeader.VersionMajor;
  inArchiveInfo.NumFolders = archiveHeader.NumFolders;
  inArchiveInfo.NumFiles = archiveHeader.NumFiles;
  inArchiveInfo.Flags = archiveHeader.Flags;

  if (inArchiveInfo.ReserveBlockPresent())
  {
    RINOK(SafeRead(inStream, &inArchiveInfo.PerDataSizes, 
        sizeof(inArchiveInfo.PerDataSizes)));
    RINOK(inStream->Seek(inArchiveInfo.PerDataSizes.PerCabinetAreaSize, 
        STREAM_SEEK_CUR, NULL));
  }

  {
    UINT64 foldersStartPosition;
    RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &foldersStartPosition));
    CInBuffer inBuffer;
    inBuffer.Init(inStream);
    if ((archiveHeader.Flags & NHeader::NArchive::NFlags::kPrevCabinet) != 0)
    {
      SafeReadName(inBuffer, inArchiveInfo.PreviousCabinetName);
      SafeReadName(inBuffer, inArchiveInfo.PreviousDiskName);
    }
    if ((archiveHeader.Flags & NHeader::NArchive::NFlags::kNextCabinet) != 0)
    {
      SafeReadName(inBuffer, inArchiveInfo.NextCabinetName);
      SafeReadName(inBuffer, inArchiveInfo.NextDiskName);
    }
    foldersStartPosition += inBuffer.GetProcessedSize();
    RINOK(inStream->Seek(foldersStartPosition, STREAM_SEEK_SET, NULL));
  }
  
  if (progressVirt != NULL)
  {
    UINT64 numFiles = archiveHeader.NumFiles;
    RINOK(progressVirt->SetTotal(&numFiles));
  }
  folders.Clear();
  for(int i = 0; i < archiveHeader.NumFolders; i++)
  {
    if (progressVirt != NULL)
    {
      UINT64 numFiles = 0;
      RINOK(progressVirt->SetCompleted(&numFiles));
    }
    NHeader::CFolder folder;
    RINOK(SafeRead(inStream, &folder, sizeof(folder)));
    if (inArchiveInfo.ReserveBlockPresent())
    {
      RINOK(inStream->Seek(
          inArchiveInfo.PerDataSizes.PerFolderAreaSize, STREAM_SEEK_CUR, NULL));
    }
    folder.DataStart += (UINT32)startPosition;
    folders.Add(folder);
  }
  
  RINOK(inStream->Seek(startPosition + archiveHeader.FileOffset, 
      STREAM_SEEK_SET, NULL));

  CInBuffer inBuffer;
  inBuffer.Init(inStream);
  files.Clear();
  if (progressVirt != NULL)
  {
    UINT64 numFiles = files.Size();
    RINOK(progressVirt->SetCompleted(&numFiles));
  }
  for(i = 0; i < archiveHeader.NumFiles; i++)
  {
    NHeader::CFile fileHeader;
    SafeInByteRead(inBuffer, &fileHeader, sizeof(fileHeader));
    CItem item;
    item.UnPackSize = fileHeader.UnPackSize;
    item.UnPackOffset = fileHeader.UnPackOffset;
    item.FolderIndex = fileHeader.FolderIndex;
    item.Time = ((UINT32(fileHeader.PureDate) << 16)) | fileHeader.PureTime;
    item.Attributes = fileHeader.Attributes;
    SafeReadName(inBuffer, item.Name);
    files.Add(item);
    if (progressVirt != NULL)
    {
      UINT64 numFiles = files.Size();
      RINOK(progressVirt->SetCompleted(&numFiles));
    }
  }
  return S_OK;
}

}}

⌨️ 快捷键说明

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