chmin.cpp
来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 925 行 · 第 1/2 页
CPP
925 行
// Archive/ChmIn.cpp#include "StdAfx.h"#include "Common/StringConvert.h"#include "Common/MyCom.h"#include "Common/UTFConvert.h"#include "Common/IntToString.h"#include "Windows/Defs.h"#include "../../Common/LimitedStreams.h"#include "ChmIn.h"namespace NArchive{namespace NChm{// define CHM_LOW, if you want to see low level items// #define CHM_LOWstatic const GUID kChmLzxGuid = { 0x7FC28940, 0x9D31, 0x11D0, 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C };static const GUID kHelp2LzxGuid = { 0x0A9007C6, 0x4076, 0x11D3, 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 };static const GUID kDesGuid = { 0x67F6E4A2, 0x60BF, 0x11D3, 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF };static bool AreGuidsEqual(REFGUID g1, REFGUID g2){ if (g1.Data1 != g2.Data1 || g1.Data2 != g2.Data2 || g1.Data3 != g2.Data3) return false; for (int i = 0; i < 8; i++) if (g1.Data4[i] != g2.Data4[i]) return false; return true;}static char GetHex(Byte value){ return (value < 10) ? ('0' + value) : ('A' + (value - 10));}static void PrintByte(Byte b, AString &s){ s += GetHex(b >> 4); s += GetHex(b & 0xF);}static void PrintUInt16(UInt16 v, AString &s){ PrintByte((Byte)(v >> 8), s); PrintByte((Byte)v, s);}static void PrintUInt32(UInt32 v, AString &s){ PrintUInt16((UInt16)(v >> 16), s); PrintUInt16((UInt16)v, s);}AString CMethodInfo::GetGuidString() const{ AString s; s += '{'; PrintUInt32(Guid.Data1, s); s += '-'; PrintUInt16(Guid.Data2, s); s += '-'; PrintUInt16(Guid.Data3, s); s += '-'; PrintByte(Guid.Data4[0], s); PrintByte(Guid.Data4[1], s); s += '-'; for (int i = 2; i < 8; i++) PrintByte(Guid.Data4[i], s); s += '}'; return s;}bool CMethodInfo::IsLzx() const{ if (AreGuidsEqual(Guid, kChmLzxGuid)) return true; return AreGuidsEqual(Guid, kHelp2LzxGuid);}bool CMethodInfo::IsDes() const{ return AreGuidsEqual(Guid, kDesGuid);}UString CMethodInfo::GetName() const{ UString s; if (IsLzx()) { s = L"LZX:"; UInt32 numDictBits = LzxInfo.GetNumDictBits(); wchar_t temp[32]; ConvertUInt64ToString(numDictBits, temp); s += temp; } else { AString s2; if (IsDes()) s2 = "DES"; else { s2 = GetGuidString(); if (ControlData.GetCapacity() > 0) { s2 += ":"; for (size_t i = 0; i < ControlData.GetCapacity(); i++) PrintByte(ControlData[i], s2); } } ConvertUTF8ToUnicode(s2, s); } return s;}bool CSectionInfo::IsLzx() const{ if (Methods.Size() != 1) return false; return Methods[0].IsLzx();}UString CSectionInfo::GetMethodName() const{ UString s; if (!IsLzx()) { UString temp; if (ConvertUTF8ToUnicode(Name, temp)) s += temp; s += L": "; } for (int i = 0; i < Methods.Size(); i++) { if (i != 0) s += L" "; s += Methods[i].GetName(); } return s;}Byte CInArchive::ReadByte(){ Byte b; if (!_inBuffer.ReadByte(b)) throw 1; return b;}void CInArchive::Skeep(size_t size){ while (size-- != 0) ReadByte();}void CInArchive::ReadBytes(Byte *data, UInt32 size){ for (UInt32 i = 0; i < size; i++) data[i] = ReadByte();}UInt16 CInArchive::ReadUInt16(){ UInt16 value = 0; for (int i = 0; i < 2; i++) value |= ((UInt16)(ReadByte()) << (8 * i)); return value;}UInt32 CInArchive::ReadUInt32(){ UInt32 value = 0; for (int i = 0; i < 4; i++) value |= ((UInt32)(ReadByte()) << (8 * i)); return value;}UInt64 CInArchive::ReadUInt64(){ UInt64 value = 0; for (int i = 0; i < 8; i++) value |= ((UInt64)(ReadByte()) << (8 * i)); return value;}UInt64 CInArchive::ReadEncInt(){ UInt64 val = 0;; for (int i = 0; i < 10; i++) { Byte b = ReadByte(); val |= (b & 0x7F); if (b < 0x80) return val; val <<= 7; } throw 1;}void CInArchive::ReadGUID(GUID &g){ g.Data1 = ReadUInt32(); g.Data2 = ReadUInt16(); g.Data3 = ReadUInt16(); ReadBytes(g.Data4, 8);}void CInArchive::ReadString(int size, AString &s){ s.Empty(); while(size-- != 0) { char c = (char)ReadByte(); if (c == 0) { Skeep(size); return; } s += c; }}void CInArchive::ReadUString(int size, UString &s){ s.Empty(); while(size-- != 0) { wchar_t c = ReadUInt16(); if (c == 0) { Skeep(2 * size); return; } s += c; }}HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size){ RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL)); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<ISequentialInStream> limitedStream(streamSpec); streamSpec->Init(inStream, size); _inBuffer.SetStream(limitedStream); _inBuffer.Init(); return S_OK;}HRESULT CInArchive::ReadDirEntry(CDatabase &database){ CItem item; UInt64 nameLength = ReadEncInt(); if (nameLength == 0 || nameLength >= 0x10000000) return S_FALSE; ReadString((int)nameLength, item.Name); item.Section = ReadEncInt(); item.Offset = ReadEncInt(); item.Size = ReadEncInt(); database.Items.Add(item); return S_OK;}HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database){ UInt32 headerSize = ReadUInt32(); if (headerSize != 0x60) return S_FALSE; UInt32 unknown1 = ReadUInt32(); if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file return S_FALSE; UInt32 timeStamp = ReadUInt32(); // 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(); GUID g; ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC} ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC} const int kNumSections = 2; UInt64 sectionOffsets[kNumSections]; UInt64 sectionSizes[kNumSections]; int i; for (i = 0; i < kNumSections; i++) { sectionOffsets[i] = ReadUInt64(); sectionSizes[i] = ReadUInt64(); } // if (chmVersion == 3) database.ContentOffset = ReadUInt64(); /* else database.ContentOffset = _startPosition + 0x58 */ /* // Section 0 ReadChunk(inStream, 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, sectionOffsets[1], sectionSizes[1]); if (ReadUInt32() != NHeader::kItspSignature) return S_FALSE; if (ReadUInt32() != 1) // version return S_FALSE; UInt32 dirHeaderSize = ReadUInt32(); ReadUInt32(); // 0x0A (unknown) UInt32 dirChunkSize = ReadUInt32(); // $1000 if (dirChunkSize < 32) return S_FALSE; UInt32 density = ReadUInt32(); // "Density" of quickref section, usually 2. UInt32 depth = ReadUInt32(); // Depth of the index tree: 1 there is no index, // 2 if there is one level of PMGI chunks. UInt32 chunkNumber = ReadUInt32(); // Chunk number of root index chunk, -1 if there is none // (though at least one file has 0 despite there being no // index chunk, probably a bug.) UInt32 firstPmglChunkNumber = ReadUInt32(); // Chunk number of first PMGL (listing) chunk UInt32 lastPmglChunkNumber = ReadUInt32(); // Chunk number of last PMGL (listing) chunk ReadUInt32(); // -1 (unknown) UInt32 numDirChunks = ReadUInt32(); // Number of directory chunks (total) UInt32 windowsLangId = ReadUInt32(); ReadGUID(g); // {5D02926A-212E-11D0-9DF9-00A0C922E6EC} ReadUInt32(); // 0x54 (This is the length again) ReadUInt32(); // -1 (unknown) ReadUInt32(); // -1 (unknown) ReadUInt32(); // -1 (unknown) for (UInt32 ci = 0; ci < numDirChunks; ci++) { UInt64 chunkPos = _inBuffer.GetProcessedSize(); if (ReadUInt32() == NHeader::kPmglSignature) { // The quickref area is written backwards from the end of the chunk. // One quickref entry exists for every n entries in the file, where n // is calculated as 1 + (1 << quickref density). So for density = 2, n = 5. UInt32 quickrefLength = ReadUInt32(); // Length of free space and/or quickref area at end of directory chunk if (quickrefLength > dirChunkSize || quickrefLength < 2) return S_FALSE; ReadUInt32(); // Always 0 ReadUInt32(); // Chunk number of previous listing chunk when reading // directory in sequence (-1 if this is the first listing chunk) ReadUInt32(); // Chunk number of next listing chunk when reading // directory in sequence (-1 if this is the last listing chunk) int numItems = 0; while (true) { UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; UInt32 offsetLimit = dirChunkSize - quickrefLength; if (offset > offsetLimit) return S_FALSE; if (offset == offsetLimit) break; RINOK(ReadDirEntry(database)); numItems++; } Skeep(quickrefLength - 2); if (ReadUInt16() != numItems) return S_FALSE; } else Skeep(dirChunkSize - 4); } return S_OK;}HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database){ if (ReadUInt32() != 1) // version return S_FALSE; if (ReadUInt32() != 0x28) // Location of header section table return S_FALSE; UInt32 numHeaderSections = ReadUInt32(); const int kNumHeaderSectionsMax = 5; if (numHeaderSections != kNumHeaderSectionsMax) return S_FALSE; ReadUInt32(); // Length of post-header table GUID g; ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754} // header section table UInt64 sectionOffsets[kNumHeaderSectionsMax]; UInt64 sectionSizes[kNumHeaderSectionsMax]; UInt32 i; for (i = 0; i < numHeaderSections; i++) { sectionOffsets[i] = ReadUInt64(); sectionSizes[i] = ReadUInt64(); } // Post-Header ReadUInt32(); // 2 ReadUInt32(); // 0x98: offset to CAOL from beginning of post-header) // ----- Directory information ReadUInt64(); // Chunk number of top-level AOLI chunk in directory, or -1 ReadUInt64(); // Chunk number of first AOLL chunk in directory ReadUInt64(); // Chunk number of last AOLL chunk in directory ReadUInt64(); // 0 (unknown) ReadUInt32(); // $2000 (Directory chunk size of directory) ReadUInt32(); // Quickref density for main directory, usually 2 ReadUInt32(); // 0 (unknown) ReadUInt32(); // Depth of main directory index tree // 1 there is no index, 2 if there is one level of AOLI chunks. ReadUInt64(); // 0 (unknown) UInt64 numDirEntries = ReadUInt64(); // Number of directory entries // ----- Directory Index Information ReadUInt64(); // -1 (unknown, probably chunk number of top-level AOLI in directory index) ReadUInt64(); // Chunk number of first AOLL chunk in directory index ReadUInt64(); // Chunk number of last AOLL chunk in directory index ReadUInt64(); // 0 (unknown) ReadUInt32(); // $200 (Directory chunk size of directory index) ReadUInt32(); // Quickref density for directory index, usually 2 ReadUInt32(); // 0 (unknown) ReadUInt32(); // Depth of directory index index tree. ReadUInt64(); // Possibly flags -- sometimes 1, sometimes 0. ReadUInt64(); // Number of directory index entries (same as number of AOLL // chunks in main directory) // (The obvious guess for the following two fields, which recur in a number // of places, is they are maximum sizes for the directory and directory index. // However, I have seen no direct evidence that this is the case.) ReadUInt32(); // $100000 (Same as field following chunk size in directory) ReadUInt32(); // $20000 (Same as field following chunk size in directory index) ReadUInt64(); // 0 (unknown) if (ReadUInt32() != NHeader::kCaolSignature) return S_FALSE; if (ReadUInt32() != 2) // (Most likely a version number) return S_FALSE; UInt32 caolLength = ReadUInt32(); // $50 (Length of the CAOL section, which includes the ITSF section) if (caolLength >= 0x2C) { UInt32 c7 = ReadUInt16(); // Unknown. Remains the same when identical files are built. // Does not appear to be a checksum. Many files have // 'HH' (HTML Help?) here, indicating this may be a compiler ID // field. But at least one ITOL/ITLS compiler does not set this // field to a constant value. ReadUInt16(); // 0 (Unknown. Possibly part of 00A4 field) ReadUInt32(); // Unknown. Two values have been seen -- $43ED, and 0. ReadUInt32(); // $2000 (Directory chunk size of directory) ReadUInt32(); // $200 (Directory chunk size of directory index) ReadUInt32(); // $100000 (Same as field following chunk size in directory) ReadUInt32(); // $20000 (Same as field following chunk size in directory index) ReadUInt32(); // 0 (unknown) ReadUInt32(); // 0 (Unknown)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?