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 §ion = 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 + -
显示快捷键?