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

📄 cabin.cpp

📁 7-Zip 是一款号称有着现今最高压缩比的压缩软件
💻 CPP
字号:
// Archive/CabIn.cpp

#include "StdAfx.h"

#include "CabIn.h"

#include "../Common/FindSignature.h"

namespace NArchive {
namespace NCab {

/*
static HRESULT ReadBytes(IInStream *inStream, void *data, UInt32 size)
{
  UInt32 realProcessedSize;
  RINOK(ReadStream(inStream, data, size, &realProcessedSize));
  if(realProcessedSize != size)
    return S_FALSE;
  return S_OK;
}

static HRESULT SafeRead(IInStream *inStream, void *data, UInt32 size)
{
  UInt32 realProcessedSize;
  RINOK(ReadStream(inStream, 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);
}
*/

Byte CInArchive::ReadByte()
{
  Byte b;
  if (!inBuffer.ReadByte(b))
    throw CInArchiveException(CInArchiveException::kUnsupported);
  return b;
}

UInt16 CInArchive::ReadUInt16()
{
  UInt16 value = 0;
  for (int i = 0; i < 2; i++)
  {
    Byte b = ReadByte();
    value |= (UInt16(b) << (8 * i));
  }
  return value;
}

UInt32 CInArchive::ReadUInt32()
{
  UInt32 value = 0;
  for (int i = 0; i < 4; i++)
  {
    Byte b = ReadByte();
    value |= (UInt32(b) << (8 * i));
  }
  return value;
}

AString CInArchive::SafeReadName()
{
  AString name;
  for (;;)
  {
    Byte b = ReadByte();
    if (b == 0)
      return name;
    name += (char)b;
  }
}

void CInArchive::ReadOtherArchive(COtherArchive &oa)
{
  oa.FileName = SafeReadName();
  oa.DiskName = SafeReadName();
}

void CInArchive::Skeep(size_t size)
{
  while (size-- != 0)
    ReadByte();
}

HRESULT CInArchive::Open2(IInStream *stream,
    const UInt64 *searchHeaderSizeLimit,
    CDatabase &database)
{
  database.Clear();
  RINOK(stream->Seek(0, STREAM_SEEK_SET, &database.StartPosition));

  RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize,
      searchHeaderSizeLimit, database.StartPosition));

  RINOK(stream->Seek(database.StartPosition + NHeader::kMarkerSize, STREAM_SEEK_SET, NULL));
  if (!inBuffer.Create(1 << 17))
    return E_OUTOFMEMORY;
  inBuffer.SetStream(stream);
  inBuffer.Init();

  CInArchiveInfo &archiveInfo = database.ArchiveInfo;

  archiveInfo.Size = ReadUInt32(); // size of this cabinet file in bytes
  if (ReadUInt32() != 0)
    return S_FALSE;
  archiveInfo.FileHeadersOffset = ReadUInt32(); // offset of the first CFFILE entry
  if (ReadUInt32() != 0)
    return S_FALSE;

  archiveInfo.VersionMinor = ReadByte(); // cabinet file format version, minor
  archiveInfo.VersionMajor = ReadByte(); // cabinet file format version, major
  archiveInfo.NumFolders = ReadUInt16(); // number of CFFOLDER entries in this cabinet
  archiveInfo.NumFiles  = ReadUInt16(); // number of CFFILE entries in this cabinet
  archiveInfo.Flags = ReadUInt16();
  if (archiveInfo.Flags > 7)
    return S_FALSE;
  archiveInfo.SetID = ReadUInt16(); // must be the same for all cabinets in a set
  archiveInfo.CabinetNumber = ReadUInt16(); // number of this cabinet file in a set

  if (archiveInfo.ReserveBlockPresent())
  {
    archiveInfo.PerCabinetAreaSize = ReadUInt16(); // (optional) size of per-cabinet reserved area
    archiveInfo.PerFolderAreaSize = ReadByte(); // (optional) size of per-folder reserved area
    archiveInfo.PerDataBlockAreaSize = ReadByte(); // (optional) size of per-datablock reserved area

    Skeep(archiveInfo.PerCabinetAreaSize);
  }

  {
    if (archiveInfo.IsTherePrev())
      ReadOtherArchive(archiveInfo.PreviousArchive);
    if (archiveInfo.IsThereNext())
      ReadOtherArchive(archiveInfo.NextArchive);
  }
  
  int i;
  for(i = 0; i < archiveInfo.NumFolders; i++)
  {
    CFolder folder;

    folder.DataStart = ReadUInt32();
    folder.NumDataBlocks = ReadUInt16();
    folder.CompressionTypeMajor = ReadByte();
    folder.CompressionTypeMinor = ReadByte();

    Skeep(archiveInfo.PerFolderAreaSize);
    database.Folders.Add(folder);
  }
  
  RINOK(stream->Seek(database.StartPosition + archiveInfo.FileHeadersOffset, STREAM_SEEK_SET, NULL));

  inBuffer.SetStream(stream);
  inBuffer.Init();
  for(i = 0; i < archiveInfo.NumFiles; i++)
  {
    CItem item;
    item.Size = ReadUInt32();
    item.Offset = ReadUInt32();
    item.FolderIndex = ReadUInt16();
    UInt16 pureDate = ReadUInt16();
    UInt16 pureTime = ReadUInt16();
    item.Time = ((UInt32(pureDate) << 16)) | pureTime;
    item.Attributes = ReadUInt16();
    item.Name = SafeReadName();
    int folderIndex = item.GetFolderIndex(database.Folders.Size());
    if (folderIndex >= database.Folders.Size())
      return S_FALSE;
    database.Items.Add(item);
  }
  return S_OK;
}

#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }

HRESULT CInArchive::Open(
    const UInt64 *searchHeaderSizeLimit,
    CDatabaseEx &database)
{
  return Open2(database.Stream, searchHeaderSizeLimit, database);
}


static int CompareMvItems2(const CMvItem *p1, const CMvItem *p2)
{
  RINOZ(MyCompare(p1->VolumeIndex, p2->VolumeIndex));
  return MyCompare(p1->ItemIndex, p2->ItemIndex);
}

static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param)
{
  const CMvDatabaseEx &mvDb = *(const CMvDatabaseEx *)param;
  const CDatabaseEx &db1 = mvDb.Volumes[p1->VolumeIndex];
  const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex];
  const CItem &item1 = db1.Items[p1->ItemIndex];
  const CItem &item2 = db2.Items[p2->ItemIndex];;
  bool isDir1 = item1.IsDir();
  bool isDir2 = item2.IsDir();
  if (isDir1 && !isDir2)
    return -1;
  if (isDir2 && !isDir1)
    return 1;
  int f1 = mvDb.GetFolderIndex(p1);
  int f2 = mvDb.GetFolderIndex(p2);
  RINOZ(MyCompare(f1, f2));
  RINOZ(MyCompare(item1.Offset, item2.Offset));
  RINOZ(MyCompare(item1.Size, item2.Size));
  return CompareMvItems2(p1, p2);
}

bool CMvDatabaseEx::AreItemsEqual(int i1, int i2)
{
  const CMvItem *p1 = &Items[i1];
  const CMvItem *p2 = &Items[i2];
  const CDatabaseEx &db1 = Volumes[p1->VolumeIndex];
  const CDatabaseEx &db2 = Volumes[p2->VolumeIndex];
  const CItem &item1 = db1.Items[p1->ItemIndex];
  const CItem &item2 = db2.Items[p2->ItemIndex];;
  int f1 = GetFolderIndex(p1);
  int f2 = GetFolderIndex(p2);
  if (f1 != f2)
    return false;
  if (item1.Offset != item2.Offset)
    return false;
  if (item1.Size != item2.Size)
    return false;

  return true;
}

void CMvDatabaseEx::FillSortAndShrink()
{
  Items.Clear();
  StartFolderOfVol.Clear();
  FolderStartFileIndex.Clear();
  int offset = 0;
  for (int v = 0; v < Volumes.Size(); v++)
  {
    const CDatabaseEx &db = Volumes[v];
    int curOffset = offset;
    if (db.IsTherePrevFolder())
      curOffset--;
    StartFolderOfVol.Add(curOffset);
    offset += db.GetNumberOfNewFolders();

    CMvItem mvItem;
    mvItem.VolumeIndex = v;
    for (int i = 0 ; i < db.Items.Size(); i++)
    {
      mvItem.ItemIndex = i;
      Items.Add(mvItem);
    }
  }

  Items.Sort(CompareMvItems, (void *)this);
  int j = 1;
  int i;
  for (i = 1; i < Items.Size(); i++)
    if (!AreItemsEqual(i, i -1))
      Items[j++] = Items[i];
  Items.DeleteFrom(j);

  for (i = 0; i < Items.Size(); i++)
  {
    const CMvItem &mvItem = Items[i];
    int folderIndex = GetFolderIndex(&mvItem);
    if (folderIndex >= FolderStartFileIndex.Size())
      FolderStartFileIndex.Add(i);
  }
}

bool CMvDatabaseEx::Check()
{
  for (int v = 1; v < Volumes.Size(); v++)
  {
    const CDatabaseEx &db1 = Volumes[v];
    if (db1.IsTherePrevFolder())
    {
      const CDatabaseEx &db0 = Volumes[v - 1];
      if (db0.Folders.IsEmpty() || db1.Folders.IsEmpty())
        return false;
      const CFolder &f0 = db0.Folders.Back();
      const CFolder &f1 = db1.Folders.Front();
      if (f0.CompressionTypeMajor != f1.CompressionTypeMajor ||
          f0.CompressionTypeMinor != f1.CompressionTypeMinor)
        return false;
    }
  }
  UInt64 maxPos = 0;
  int prevFolder = -2;
  for(int i = 0; i < Items.Size(); i++)
  {
    const CMvItem &mvItem = Items[i];
    int fIndex = GetFolderIndex(&mvItem);
    if (fIndex >= FolderStartFileIndex.Size())
      return false;
    const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
    if (item.IsDir())
      continue;
    int folderIndex = GetFolderIndex(&mvItem);
    if (folderIndex != prevFolder)
    {
      prevFolder = folderIndex;
      maxPos = 0;
      continue;
    }
    if (item.Offset < maxPos)
      return false;
    maxPos = item.GetEndOffset();
    if (maxPos < item.Offset)
      return false;
  }
  return true;
}

}}

⌨️ 快捷键说明

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