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