chmin.cpp

来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 925 行 · 第 1/2 页

CPP
925
字号
    if (caolLength == 0x2C)    {      database.ContentOffset = 0;      database.NewFormat = true;    }    else if (caolLength == 0x50)    {      ReadUInt32(); // 0 (Unknown)      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;      while (true)      {        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.IsDirectory();  bool isDir2 = item2.IsDirectory();  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.IsDirectory())      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 != 2 && li.ResetInterval != 4)            return S_FALSE;          if (li.WindowSize != 2 && li.WindowSize != 4)            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;    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 == chmSignature)          break;        if (value == hxsSignature)        {          database.Help2Format = true;          break;        }        if (searchHeaderSizeLimit != NULL)          if (_inBuffer.GetProcessedSize() > (*searchHeaderSizeLimit))            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 + =
减小字号Ctrl + -
显示快捷键?