DocTocItem *MobiEngineImpl::GetTocTree() { if (!tocReparsePoint) return NULL; EbookTocItem *root = NULL; ScopedMem<WCHAR> itemText; ScopedMem<WCHAR> itemLink; int itemLevel = 0; int idCounter = 0; // there doesn't seem to be a standard for Mobi ToCs, so we try to // determine the author's intentions by looking at commonly used tags HtmlPullParser parser(tocReparsePoint, str::Len(tocReparsePoint)); HtmlToken *tok; while ((tok = parser.Next()) && !tok->IsError()) { if (itemLink && tok->IsText()) { ScopedMem<WCHAR> linkText(str::conv::FromHtmlUtf8(tok->s, tok->sLen)); if (itemText) itemText.Set(str::Join(itemText, L" ", linkText)); else itemText.Set(linkText.StealData()); } else if (!tok->IsTag()) continue; else if (Tag_Mbp_Pagebreak == tok->tag) break; else if (!itemLink && tok->IsStartTag() && Tag_A == tok->tag) { AttrInfo *attr = tok->GetAttrByName("filepos"); if (!attr) attr = tok->GetAttrByName("href"); if (attr) itemLink.Set(str::conv::FromHtmlUtf8(attr->val, attr->valLen)); } else if (itemLink && tok->IsEndTag() && Tag_A == tok->tag) { PageDestination *dest = NULL; if (!itemText) { itemLink.Set(NULL); continue; } if (IsExternalUrl(itemLink)) dest = new SimpleDest2(0, RectD(), itemLink.StealData()); else dest = GetNamedDest(itemLink); EbookTocItem *item = new EbookTocItem(itemText.StealData(), dest); item->id = ++idCounter; item->open = itemLevel <= 2; AppendTocItem(root, item, itemLevel); itemLink.Set(NULL); } else if (Tag_Blockquote == tok->tag || Tag_Ul == tok->tag || Tag_Ol == tok->tag) { if (tok->IsStartTag()) itemLevel++; else if (tok->IsEndTag() && itemLevel > 0) itemLevel--; } } return root; }
// 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; }
// extract ComicBookInfo metadata // cf. http://code.google.com/p/comicbookinfo/ bool CbxEngineImpl::Visit(const char *path, const char *value, json::DataType type) { if (json::Type_String == type && str::Eq(path, "/ComicBookInfo/1.0/title")) propTitle.Set(str::conv::FromUtf8(value)); else if (json::Type_Number == type && str::Eq(path, "/ComicBookInfo/1.0/publicationYear")) propDate.Set(str::Format(L"%s/%d", propDate ? propDate : L"", atoi(value))); else if (json::Type_Number == type && str::Eq(path, "/ComicBookInfo/1.0/publicationMonth")) propDate.Set(str::Format(L"%d%s", atoi(value), propDate ? propDate : L"")); else if (json::Type_String == type && str::Eq(path, "/appID")) propCreator.Set(str::conv::FromUtf8(value)); else if (json::Type_String == type && str::Eq(path, "/lastModified")) propModDate.Set(str::conv::FromUtf8(value)); else if (json::Type_String == type && str::Eq(path, "/X-summary")) propSummary.Set(str::conv::FromUtf8(value)); else if (str::StartsWith(path, "/ComicBookInfo/1.0/credits[")) { int idx = -1; const char *prop = str::Parse(path, "/ComicBookInfo/1.0/credits[%d]/", &idx); if (prop) { if (json::Type_String == type && str::Eq(prop, "person")) propAuthorTmp.Set(str::conv::FromUtf8(value)); else if (json::Type_Bool == type && str::Eq(prop, "primary") && propAuthorTmp && propAuthors.Find(propAuthorTmp) == -1) { propAuthors.Append(propAuthorTmp.StealData()); } } return true; } // stop parsing once we have all desired information return !propTitle || propAuthors.Count() == 0 || !propCreator || !propDate || str::FindChar(propDate, '/') <= propDate; }
WCHAR *ChmDoc::GetProperty(DocumentProperty prop) { ScopedMem<WCHAR> result; if (Prop_Title == prop && title) result.Set(ToStr(title)); else if (Prop_CreatorApp == prop && creator) result.Set(ToStr(creator)); // TODO: shouldn't it be up to the front-end to normalize whitespace? if (result) { // TODO: original code called str::RemoveChars(result, "\n\r\t") str::NormalizeWS(result); } return result.StealData(); }
DocTocItem *Fb2EngineImpl::GetTocTree() { EbookTocItem *root = NULL; ScopedMem<WCHAR> itemText; int titleCount = 0; bool inTitle = false; int level = 0; size_t xmlLen; const char *xmlData = doc->GetTextData(&xmlLen); HtmlPullParser parser(xmlData, xmlLen); HtmlToken *tok; while ((tok = parser.Next()) && !tok->IsError()) { if (tok->IsStartTag() && Tag_Section == tok->tag) level++; else if (tok->IsEndTag() && Tag_Section == tok->tag && level > 0) level--; else if (tok->IsStartTag() && Tag_Title == tok->tag) { inTitle = true; titleCount++; } else if (tok->IsEndTag() && Tag_Title == tok->tag) { if (itemText) str::NormalizeWS(itemText); if (!str::IsEmpty(itemText.Get())) { ScopedMem<WCHAR> name(str::Format(TEXT(FB2_TOC_ENTRY_MARK) L"%d", titleCount)); PageDestination *dest = GetNamedDest(name); EbookTocItem *item = new EbookTocItem(itemText.StealData(), dest); item->id = titleCount; item->open = level <= 2; AppendTocItem(root, item, level); } inTitle = false; } else if (inTitle && tok->IsText()) { ScopedMem<WCHAR> text(str::conv::FromHtmlUtf8(tok->s, tok->sLen)); if (str::IsEmpty(itemText.Get())) itemText.Set(text.StealData()); else itemText.Set(str::Join(itemText, L" ", text)); } } return root; }
static void DeserializeAdvancedSettings(const WCHAR *filepath, SettingInfo *info, size_t count, void *structBase) { char *base = (char *)structBase; const WCHAR *section = NULL; INT intValue, intValueDef; ScopedMem<WCHAR> strValue; for (size_t i = 0; i < count; i++) { SettingInfo& meta = info[i]; CrashIf(meta.type != SType_Section && !section); switch (meta.type) { case SType_Section: section = meta.name; break; case SType_Bool: intValueDef = *(bool *)(base + meta.offset) ? 1 : 0; intValue = GetPrivateProfileInt(section, meta.name, intValueDef, filepath); *(bool *)(base + meta.offset) = intValue != 0; break; case SType_Color: strValue.Set(ReadIniString(filepath, section, meta.name)); if (str::Parse(strValue, L"#%6x", &intValue)) *(COLORREF *)(base + meta.offset) = (COLORREF)intValue; break; case SType_Int: intValueDef = *(int *)(base + meta.offset); intValue = GetPrivateProfileInt(section, meta.name, intValueDef, filepath); *(int *)(base + meta.offset) = intValue; break; case SType_String: strValue.Set(ReadIniString(filepath, section, meta.name, L"\n")); if (!str::Eq(strValue, L"\n")) ((ScopedMem<WCHAR> *)(base + meta.offset))->Set(strValue.StealData()); break; case SType_BoolVec: case SType_ColorVec: case SType_IntVec: case SType_StringVec: ScopedMem<WCHAR> sections(ReadIniString(filepath, section, NULL)); for (const WCHAR *name = sections; *name; name += str::Len(name) + 1) { UINT idx; if (str::Eq(str::Parse(name, L"%u.", &idx), meta.name)) { if (SType_BoolVec == meta.type) { bool value = GetPrivateProfileInt(section, name, 0, filepath) != 0; ((Vec<bool> *)(base + meta.offset))->InsertAt(idx, value); } else if (SType_ColorVec == meta.type) { strValue.Set(ReadIniString(filepath, section, name)); if (str::Parse(strValue, L"#%6x", &intValue)) { COLORREF value = (COLORREF)intValue; ((Vec<COLORREF> *)(base + meta.offset))->InsertAt(idx, value); } } else if (SType_IntVec == meta.type) { intValue = GetPrivateProfileInt(section, name, 0, filepath); ((Vec<int> *)(base + meta.offset))->InsertAt(idx, intValue); } else { strValue.Set(ReadIniString(filepath, section, name)); WStrVec *strVec = (WStrVec *)(base + meta.offset); // TODO: shouldn't InsertAt free the previous string? if (idx < strVec->Count()) free(strVec->At(idx)); strVec->InsertAt(idx, strValue.StealData()); } } } break; } } }