ChmTocBuilder(ChmDoc *doc, WStrList *pages, Vec<ChmTocTraceItem> *tocTrace, Allocator *allocator) : doc(doc), pages(pages), tocTrace(tocTrace), allocator(allocator) { for (int i = 0; i < (int)pages->Count(); i++) { const WCHAR *url = pages->At(i); bool inserted = urlsSet.Insert(url, i + 1, NULL); CrashIf(!inserted); } }
ChmTocBuilder(ChmDoc *doc, WStrList *pages, ChmTocItem **root) : doc(doc), pages(pages), root(root), idCounter(0) { #ifdef USE_STR_INT_MAP for (size_t i = 0; i < pages->Count(); i++) { const WCHAR *url = pages->At(i); bool inserted = urlsSet.Insert(url, i + 1, NULL); CrashIf(!inserted); } #endif }
// We fake page numbers by doing a depth-first traversal of // toc tree and considering each unique html page in toc tree // as a page int CreatePageNoForURL(const WCHAR *url) { if (!url || IsExternalUrl(url)) return 0; ScopedMem<WCHAR> plainUrl(str::ToPlainUrl(url)); int pageNo = pages->Find(plainUrl) + 1; if (pageNo > 0) return pageNo; pages->Append(plainUrl.StealData()); return pages->Count(); }
// Detect TeX editors installed on the system and construct the // corresponding inverse search commands. // // Parameters: // hwndCombo -- (optional) handle to a combo list that will be filled with the list of possible inverse search commands. // Returns: // the inverse search command of the first detected editor (the caller needs to free() the result). WCHAR *AutoDetectInverseSearchCommands(HWND hwndCombo) { WCHAR *firstEditor = NULL; WStrList foundExes; for (int i = 0; i < dimof(editor_rules); i++) { ScopedMem<WCHAR> path(ReadRegStr(editor_rules[i].RegRoot, editor_rules[i].RegKey, editor_rules[i].RegValue)); if (!path) continue; ScopedMem<WCHAR> exePath; if (editor_rules[i].Type == SiblingPath) { // remove file part ScopedMem<WCHAR> dir(path::GetDir(path)); exePath.Set(path::Join(dir, editor_rules[i].BinaryFilename)); } else if (editor_rules[i].Type == BinaryDir) exePath.Set(path::Join(path, editor_rules[i].BinaryFilename)); else // if (editor_rules[i].Type == BinaryPath) exePath.Set(path.StealData()); // don't show duplicate entries if (foundExes.FindI(exePath) != -1) continue; // don't show inexistent paths (and don't try again for them) if (!file::Exists(exePath)) { foundExes.Append(exePath.StealData()); continue; } ScopedMem<WCHAR> editorCmd(str::Format(L"\"%s\" %s", exePath, editor_rules[i].InverseSearchArgs)); if (!hwndCombo) { // no need to fill a combo box: return immeditately after finding an editor. return editorCmd.StealData(); } ComboBox_AddString(hwndCombo, editorCmd); if (!firstEditor) firstEditor = editorCmd.StealData(); foundExes.Append(exePath.StealData()); } // Fall back to notepad as a default handler if (!firstEditor) { firstEditor = str::Dup(L"notepad %f"); if (hwndCombo) ComboBox_AddString(hwndCombo, firstEditor); } return firstEditor; }
static void StrListTest() { WStrList l; utassert(l.Count() == 0); l.Append(str::Dup(L"one")); l.Append(str::Dup(L"two")); l.Append(str::Dup(L"One")); utassert(l.Count() == 3); utassert(str::Eq(l.At(0), L"one")); utassert(str::EqI(l.At(2), L"one")); utassert(l.Find(L"One") == 2); utassert(l.FindI(L"One") == 0); utassert(l.Find(L"Two") == -1); }
int CreatePageNoForURL(const WCHAR *url) { if (!url || IsExternalUrl(url)) return 0; ScopedMem<WCHAR> plainUrl(str::ToPlainUrl(url)); int pageNo = pages->Count() + 1; bool inserted = urlsSet.Insert(plainUrl, pageNo, &pageNo); if (inserted) { pages->Append(plainUrl.StealData()); CrashIf(pageNo != pages->Count()); } else { CrashIf(pageNo == pages->Count() + 1); } return pageNo; }
virtual void Visit(const WCHAR *name, const WCHAR *url, int level) { if (!url || IsExternalUrl(url)) return; ScopedMem<WCHAR> plainUrl(str::ToPlainUrl(url)); if (added.FindI(plainUrl) != -1) return; ScopedMem<char> urlUtf8(str::conv::ToUtf8(plainUrl)); size_t pageHtmlLen; ScopedMem<unsigned char> pageHtml(doc->GetData(urlUtf8, &pageHtmlLen)); if (!pageHtml) return; html.AppendFmt("<pagebreak page_path=\"%s\" page_marker />", urlUtf8); html.AppendAndFree(doc->ToUtf8(pageHtml, ExtractHttpCharset((const char *)pageHtml.Get(), pageHtmlLen))); added.Append(plainUrl.StealData()); }
void ChmEngineImpl::DisplayPage(const WCHAR *pageUrl) { if (IsExternalUrl(pageUrl)) { // open external links in an external browser // (same as for PDF, XPS, etc. documents) if (navCb) navCb->LaunchBrowser(pageUrl); return; } int pageNo = pages.Find(ScopedMem<WCHAR>(str::ToPlainUrl(pageUrl))) + 1; if (pageNo) currentPageNo = pageNo; // This is a hack that seems to be needed for some chm files where // url starts with "..\" even though it's not accepted by ie as // a correct its: url. There's a possibility it breaks some other // chm files (I don't know such cases, though). // A more robust solution would try to match with the actual // names of files inside chm package. if (str::StartsWith(pageUrl, L"..\\")) pageUrl += 3; if (str::StartsWith(pageUrl, L"/")) pageUrl++; assert(htmlWindow); if (htmlWindow) htmlWindow->NavigateToDataUrl(pageUrl); }
PageDestination *ChmEngineImpl::GetNamedDest(const WCHAR *name) { ScopedMem<WCHAR> plainUrl(str::ToPlainUrl(name)); int pageNo = pages.Find(plainUrl) + 1; if (pageNo > 0) return new ChmTocItem(NULL, pageNo, str::Dup(name)); return NULL; }
bool ChmEngineImpl::Load(const WCHAR *fileName) { this->fileName = str::Dup(fileName); Timer t(true); doc = ChmDoc::CreateFromFile(fileName); dbglog::LogF("ChmDoc::CreateFromFile(): %.2f ms", t.GetTimeInMs()); if (!doc) return false; // always make the document's homepage page 1 pages.Append(str::conv::FromAnsi(doc->GetHomePath())); // parse the ToC here, since page numbering depends on it t.Start(); doc->ParseToc(&ChmTocBuilder(doc, &pages, &tocRoot)); dbglog::LogF("doc->ParseToc(): %.2f ms", t.GetTimeInMs()); CrashIf(pages.Count() == 0); return pages.Count() > 0; }
// Called after html document has been loaded. // Sync the state of the ui with the page (show // the right page number, select the right item in toc tree) void ChmEngineImpl::OnDocumentComplete(const WCHAR *url) { if (!url) return; if (*url == '/') ++url; int pageNo = pages.Find(ScopedMem<WCHAR>(str::ToPlainUrl(url))) + 1; if (pageNo) { currentPageNo = pageNo; if (navCb) navCb->PageNoChanged(pageNo); } }