// http://www.nongnu.org/chmspec/latest/Internal.html#SYSTEM bool ChmDoc::ParseSystemData() { size_t dataLen; ScopedMem<unsigned char> data(GetData("/#SYSTEM", &dataLen)); if (!data) return false; ByteReader r(data, dataLen); DWORD len = 0; // Note: skipping DWORD version at offset 0. It's supposed to be 2 or 3. for (size_t off = 4; off + 4 < dataLen; off += len + 4) { // Note: at some point we seem to get off-sync i.e. I'm seeing // many entries with type == 0 and len == 0. Seems harmless. len = r.WordLE(off + 2); if (len == 0) continue; WORD type = r.WordLE(off); switch (type) { case 0: if (!tocPath) tocPath.Set(GetCharZ(data, dataLen, off + 4)); break; case 1: if (!indexPath) indexPath.Set(GetCharZ(data, dataLen, off + 4)); break; case 2: if (!homePath) homePath.Set(GetCharZ(data, dataLen, off + 4)); break; case 3: if (!title) title.Set(GetCharZ(data, dataLen, off + 4)); break; case 4: if (!codepage && len >= 4) codepage = LcidToCodepage(r.DWordLE(off + 4)); break; case 6: // compiled file - ignore break; case 9: if (!creator) creator.Set(GetCharZ(data, dataLen, off + 4)); break; case 16: // default font - ignore break; } } return true; }
bool ChmDoc::Load(const WCHAR *fileName) { chmHandle = chm_open((WCHAR *)fileName); if (!chmHandle) return false; ParseWindowsData(); if (!ParseSystemData()) return false; UINT fileCodepage = codepage; char header[24] = { 0 }; if (file::ReadN(fileName, header, sizeof(header))) { DWORD lcid = ByteReader(header, sizeof(header)).DWordLE(20); fileCodepage = LcidToCodepage(lcid); } if (!codepage) codepage = fileCodepage; // if file and #SYSTEM codepage disagree, prefer #SYSTEM's (unless it leads to wrong paths) FixPathCodepage(homePath, fileCodepage); FixPathCodepage(tocPath, fileCodepage); FixPathCodepage(indexPath, fileCodepage); if (GetACP() == codepage) codepage = CP_ACP; if (!HasData(homePath)) { const char *pathsToTest[] = { "/index.htm", "/index.html", "/default.htm", "/default.html" }; for (int i = 0; i < dimof(pathsToTest); i++) { if (HasData(pathsToTest[i])) { homePath.SetCopy(pathsToTest[i]); } } if (!HasData(homePath)) return false; } return true; }
bool ChmDoc::Load(const WCHAR *fileName) { chmHandle = chm_open((WCHAR *)fileName); if (!chmHandle) return false; ParseWindowsData(); if (!ParseSystemData()) return false; if (!HasData(homePath)) { const char *pathsToTest[] = { "/index.htm", "/index.html", "/default.htm", "/default.html" }; for (int i = 0; i < dimof(pathsToTest); i++) { if (HasData(pathsToTest[i])) homePath.Set(str::Dup(pathsToTest[i])); } } if (!HasData(homePath)) return false; if (!codepage) { char header[24]; if (file::ReadAll(fileName, header, sizeof(header))) { DWORD lcid = ByteReader(header, sizeof(header)).DWordLE(20); codepage = LcidToCodepage(lcid); } else codepage = CP_CHM_DEFAULT; } if (GetACP() == codepage) codepage = CP_ACP; return true; }