#pragma once
// KOReader xpath <-> FreeInkBook character offset, via one streaming SAX pass
// over the chapter's XHTML (no DOM, no pagination — chapter character offsets
// are layout-independent, so neither direction needs the page cache).
//
// The text accounting mirrors ChapterLayout exactly (suppressed head/style/
// script/title, body gating, whitespace collapse,
newlines, block
// flushes), so the offsets these functions produce address the same
// characters the engine's page records anchor on. Known approximation:
// display:none content is counted here but skipped by layout when the book's
// CSS hides it — a paragraph-level drift on such books, corrected by the
// percentage fallback.
#include
#include
#include
namespace BookXPath {
// Real-ancestry KOReader xpath for a chapter character offset:
// "/body/DocFragment[N]/body/div[2]/p[4]/text().17". Falls back to the
// chapter-level "/body/DocFragment[N]" when the offset lies past the text or
// the parse fails.
std::string xpathForCharStart(freeink::book::BookSource& source, const freeink::book::ZipCatalog& zip,
const freeink::book::ZipEntry& entry, int spineIndex, uint32_t charStart);
// Resolves a KOReader xpath's element ancestry to the chapter character
// offset where that element's text begins (plus the xpath's text offset).
// Returns false when the ancestry cannot be matched — caller falls back to
// the synced percentage.
bool charStartForXpath(freeink::book::BookSource& source, const freeink::book::ZipCatalog& zip,
const freeink::book::ZipEntry& entry, const std::string& xpath, uint32_t* charStartOut);
// The 0-based spine index from "/body/DocFragment[N]/...", or -1.
int spineIndexForXpath(const std::string& xpath);
} // namespace BookXPath