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

📄 chmin.cpp

📁 7-Zip 是一款号称有着现今最高压缩比的压缩软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
      if (ReadUInt32() != NHeader::kItsfSignature)
        return S_FALSE;
      if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3)
        return S_FALSE;
      if (ReadUInt32() != 0x20) // $20 (length of ITSF)
        return S_FALSE;
      UInt32 unknown = ReadUInt32();
      if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases;
        return S_FALSE;
      database.ContentOffset = _startPosition + ReadUInt64();
      /* UInt32 timeStamp = */ ReadUInt32();
          // A timestamp of some sort.
          // Considered as a big-endian DWORD, it appears to contain
          // seconds (MSB) and fractional seconds (second byte).
          // The third and fourth bytes may contain even more fractional
          // bits.  The 4 least significant bits in the last byte are constant.
      /* UInt32 lang = */ ReadUInt32(); // BE?
    }
    else
      return S_FALSE;
  }

  /*
  // Section 0
  ReadChunk(inStream, _startPosition + sectionOffsets[0], sectionSizes[0]);
  if (sectionSizes[0] != 0x18)
    return S_FALSE;
  ReadUInt32(); // unknown:  01FE
  ReadUInt32(); // unknown:  0
  UInt64 fileSize = ReadUInt64();
  ReadUInt32(); // unknown:  0
  ReadUInt32(); // unknown:  0
  */

  // Section 1: The Directory Listing
  ReadChunk(inStream, _startPosition + sectionOffsets[1], sectionSizes[1]);
  if (ReadUInt32() != NHeader::kIfcmSignature)
    return S_FALSE;
  if (ReadUInt32() != 1) // (probably a version number)
    return S_FALSE;
  UInt32 dirChunkSize = ReadUInt32(); // $2000
  if (dirChunkSize < 64)
    return S_FALSE;
  ReadUInt32(); // $100000  (unknown)
  ReadUInt32(); // -1 (unknown)
  ReadUInt32(); // -1 (unknown)
  UInt32 numDirChunks = ReadUInt32();
  ReadUInt32(); // 0 (unknown, probably high word of above)

  for (UInt32 ci = 0; ci < numDirChunks; ci++)
  {
    UInt64 chunkPos = _inBuffer.GetProcessedSize();
    if (ReadUInt32() == NHeader::kAollSignature)
    {
      UInt32 quickrefLength = ReadUInt32(); // Length of quickref area at end of directory chunk
      if (quickrefLength > dirChunkSize || quickrefLength < 2)
        return S_FALSE;
      ReadUInt64(); // Directory chunk number
            // This must match physical position in file, that is
            // the chunk size times the chunk number must be the
            // offset from the end of the directory header.
      ReadUInt64(); // Chunk number of previous listing chunk when reading
                    // directory in sequence (-1 if first listing chunk)
      ReadUInt64(); // Chunk number of next listing chunk when reading
                    // directory in sequence (-1 if last listing chunk)
      ReadUInt64(); // Number of first listing entry in this chunk
      ReadUInt32(); // 1 (unknown -- other values have also been seen here)
      ReadUInt32(); // 0 (unknown)
      
      int numItems = 0;
      for (;;)
      {
        UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
        UInt32 offsetLimit = dirChunkSize - quickrefLength;
        if (offset > offsetLimit)
          return S_FALSE;
        if (offset == offsetLimit)
          break;
        if (database.NewFormat)
        {
          UInt16 nameLength = ReadUInt16();
          if (nameLength == 0)
            return S_FALSE;
          UString name;
          ReadUString((int)nameLength, name);
          AString s;
          ConvertUnicodeToUTF8(name, s);
          Byte b = ReadByte();
          s += ' ';
          PrintByte(b, s);
          s += ' ';
          UInt64 len = ReadEncInt();
          // then number of items ?
          // then length ?
          // then some data (binary encoding?)
          while (len-- != 0)
          {
            b = ReadByte();
            PrintByte(b, s);
          }
          database.NewFormatString += s;
          database.NewFormatString += "\r\n";
        }
        else
        {
          RINOK(ReadDirEntry(database));
        }
        numItems++;
      }
      Skeep(quickrefLength - 2);
      if (ReadUInt16() != numItems)
        return S_FALSE;
      if (numItems > numDirEntries)
        return S_FALSE;
      numDirEntries -= numItems;
    }
    else
      Skeep(dirChunkSize - 4);
  }
  return numDirEntries == 0 ? S_OK : S_FALSE;
}

HRESULT CInArchive::DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name)
{
  int index = database.FindItem(name);
  if (index < 0)
    return S_FALSE;
  const CItem &item = database.Items[index];
  _chunkSize = item.Size;
  return ReadChunk(inStream, database.ContentOffset + item.Offset, item.Size);
}


#define DATA_SPACE "::DataSpace/"
static const char *kNameList = DATA_SPACE "NameList";
static const char *kStorage = DATA_SPACE "Storage/";
static const char *kContent = "Content";
static const char *kControlData = "ControlData";
static const char *kSpanInfo = "SpanInfo";
static const char *kTransform = "Transform/";
static const char *kResetTable = "/InstanceData/ResetTable";
static const char *kTransformList = "List";

static AString GetSectionPrefix(const AString &name)
{
  return AString(kStorage) + name + AString("/");
}

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

static int CompareFiles(const int *p1, const int *p2, void *param)
{
  const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param;
  const CItem &item1 = items[*p1];
  const CItem &item2 = items[*p2];
  bool isDir1 = item1.IsDir();
  bool isDir2 = item2.IsDir();
  if (isDir1 && !isDir2)
    return -1;
  if (isDir2)
  {
    if (isDir1)
      return MyCompare(*p1, *p2);
    return 1;
  }
  RINOZ(MyCompare(item1.Section, item2.Section));
  RINOZ(MyCompare(item1.Offset, item2.Offset));
  RINOZ(MyCompare(item1.Size, item2.Size));
  return MyCompare(*p1, *p2);
}

void CFilesDatabase::SetIndices()
{
  for (int i = 0; i < Items.Size(); i++)
  {
    const CItem &item = Items[i];
    if (item.IsUserItem() && item.Name.Length() != 1)
      Indices.Add(i);
  }
}

void CFilesDatabase::Sort()
{
  Indices.Sort(CompareFiles, (void *)&Items);
}

bool CFilesDatabase::Check()
{
  UInt64 maxPos = 0;
  UInt64 prevSection = 0;
  for(int i = 0; i < Indices.Size(); i++)
  {
    const CItem &item = Items[Indices[i]];
    if (item.Section == 0 || item.IsDir())
      continue;
    if (item.Section != prevSection)
    {
      prevSection = item.Section;
      maxPos = 0;
      continue;
    }
    if (item.Offset < maxPos)
      return false;
    maxPos = item.Offset + item.Size;
    if (maxPos < item.Offset)
      return false;
  }
  return true;
}

HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
{
  {
    // The NameList file
    RINOK(DecompressStream(inStream, database, kNameList));
    /* UInt16 length = */ ReadUInt16();
    UInt16 numSections = ReadUInt16();
    for (int i = 0; i < numSections; i++)
    {
      CSectionInfo section;
      UInt16 nameLength  = ReadUInt16();
      UString name;
      ReadUString(nameLength, name);
      if (ReadUInt16() != 0)
        return S_FALSE;
      if (!ConvertUnicodeToUTF8(name, section.Name))
        return S_FALSE;
      database.Sections.Add(section);
    }
  }

  int i;
  for (i = 1; i < database.Sections.Size(); i++)
  {
    CSectionInfo &section = database.Sections[i];
    AString sectionPrefix = GetSectionPrefix(section.Name);
    {
      // Content
      int index = database.FindItem(sectionPrefix + kContent);
      if (index < 0)
        return S_FALSE;
      const CItem &item = database.Items[index];
      section.Offset = item.Offset;
      section.CompressedSize = item.Size;
    }
    AString transformPrefix = sectionPrefix + kTransform;
    if (database.Help2Format)
    {
      // Transform List
      RINOK(DecompressStream(inStream, database, transformPrefix + kTransformList));
      if ((_chunkSize & 0xF) != 0)
        return S_FALSE;
      int numGuids = (int)(_chunkSize / 0x10);
      if (numGuids < 1)
        return S_FALSE;
      for (int i = 0; i < numGuids; i++)
      {
        CMethodInfo method;
        ReadGUID(method.Guid);
        section.Methods.Add(method);
      }
    }
    else
    {
      CMethodInfo method;
      method.Guid = kChmLzxGuid;
      section.Methods.Add(method);
    }

    {
      // Control Data
      RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData));
      for (int mi = 0; mi < section.Methods.Size(); mi++)
      {
        CMethodInfo &method = section.Methods[mi];
        UInt32 numDWORDS = ReadUInt32();
        if (method.IsLzx())
        {
          if (numDWORDS < 5)
            return S_FALSE;
          if (ReadUInt32() != NHeader::kLzxcSignature)
            return S_FALSE;
          CLzxInfo &li = method.LzxInfo;
          li.Version = ReadUInt32();
          if (li.Version != 2 && li.Version != 3)
            return S_FALSE;
          li.ResetInterval = ReadUInt32();
          li.WindowSize = ReadUInt32();
          li.CacheSize = ReadUInt32();
          if (
              li.ResetInterval != 1 &&
              li.ResetInterval != 2 &&
              li.ResetInterval != 4 &&
              li.ResetInterval != 8 &&
              li.ResetInterval != 16 &&
              li.ResetInterval != 32 &&
              li.ResetInterval != 64)
            return S_FALSE;
          if (
              li.WindowSize != 1 &&
              li.WindowSize != 2 &&
              li.WindowSize != 4 &&
              li.WindowSize != 8 &&
              li.WindowSize != 16 &&
              li.WindowSize != 32 &&
              li.WindowSize != 64)
            return S_FALSE;
          numDWORDS -= 5;
          while (numDWORDS-- != 0)
            ReadUInt32();
        }
        else
        {
          UInt32 numBytes = numDWORDS * 4;
          method.ControlData.SetCapacity(numBytes);
          ReadBytes(method.ControlData, numBytes);
        }
      }
    }

    {
      // SpanInfo
      RINOK(DecompressStream(inStream, database, sectionPrefix + kSpanInfo));
      section.UncompressedSize = ReadUInt64();
    }

    // read ResetTable for LZX
    for (int mi = 0; mi < section.Methods.Size(); mi++)
    {
      CMethodInfo &method = section.Methods[mi];
      if (method.IsLzx())
      {
        // ResetTable;
        RINOK(DecompressStream(inStream, database, transformPrefix +
            method.GetGuidString() + kResetTable));
        CResetTable &rt = method.LzxInfo.ResetTable;
        if (_chunkSize < 4)
        {
          if (_chunkSize != 0)
            return S_FALSE;
          // ResetTable is empty in .chw files
          if (section.UncompressedSize != 0)
            return S_FALSE;
          rt.UncompressedSize = 0;
          rt.CompressedSize = 0;
          rt.BlockSize = 0;
        }
        else
        {
          UInt32 ver = ReadUInt32(); // 2  unknown (possibly a version number)
          if (ver != 2 && ver != 3)
            return S_FALSE;
          UInt32 numEntries = ReadUInt32();
          if (ReadUInt32() != 8) // Size of table entry (bytes)
            return S_FALSE;
          if (ReadUInt32() != 0x28) // Length of table header
            return S_FALSE;
          rt.UncompressedSize = ReadUInt64();
          rt.CompressedSize = ReadUInt64();
          rt.BlockSize = ReadUInt64(); //  0x8000 block size for locations below
          if (rt.BlockSize != 0x8000)
            return S_FALSE;
          rt.ResetOffsets.Reserve(numEntries);
          for (UInt32 i = 0; i < numEntries; i++)
            rt.ResetOffsets.Add(ReadUInt64());
        }
      }
    }
  }

  database.SetIndices();
  database.Sort();
  return database.Check() ? S_OK : S_FALSE;
}

HRESULT CInArchive::Open2(IInStream *inStream,
    const UInt64 *searchHeaderSizeLimit,
    CFilesDatabase &database)
{
  database.Clear();

  RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition));

  database.Help2Format = false;
  const UInt32 chmVersion = 3;
  {
    if (!_inBuffer.Create(1 << 14))
      return E_OUTOFMEMORY;
    _inBuffer.SetStream(inStream);
    _inBuffer.Init();
    UInt64 value = 0;
    const int kSignatureSize = 8;
    UInt64 hxsSignature = NHeader::GetHxsSignature();
    UInt64 chmSignature = ((UInt64)chmVersion << 32)| NHeader::kItsfSignature;
    UInt64 limit = 1 << 18;
    if (searchHeaderSizeLimit)
      if (limit > *searchHeaderSizeLimit)
        limit = *searchHeaderSizeLimit;

    for (;;)
    {
      Byte b;
      if (!_inBuffer.ReadByte(b))
        return S_FALSE;
      value >>= 8;
      value |= ((UInt64)b) << ((kSignatureSize - 1) * 8);
      if (_inBuffer.GetProcessedSize() >= kSignatureSize)
      {
        if (value == chmSignature)
          break;
        if (value == hxsSignature)
        {
          database.Help2Format = true;
          break;
        }
        if (_inBuffer.GetProcessedSize() > limit)
          return S_FALSE;
      }
    }
    _startPosition += _inBuffer.GetProcessedSize() - kSignatureSize;
  }

  if (database.Help2Format)
  {
    RINOK(OpenHelp2(inStream, database));
    if (database.NewFormat)
      return S_OK;
  }
  else
  {
    RINOK(OpenChm(inStream, database));
  }

  #ifndef CHM_LOW
  try
  {
    HRESULT res = OpenHighLevel(inStream, database);
    if (res == S_FALSE)
    {
      database.HighLevelClear();
      return S_OK;
    }
    RINOK(res);
    database.LowLevel = false;
  }
  catch(...)
  {
    return S_OK;
  }
  #endif
  return S_OK;
}

HRESULT CInArchive::Open(IInStream *inStream,
    const UInt64 *searchHeaderSizeLimit,
    CFilesDatabase &database)
{
  try
  {
    HRESULT res = Open2(inStream, searchHeaderSizeLimit, database);
    _inBuffer.ReleaseStream();
    return res;
  }
  catch(...)
  {
    _inBuffer.ReleaseStream();
    throw;
  }
}

}}

⌨️ 快捷键说明

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