From 8c08c19ca60f008181bfd503fdda74266090a23d Mon Sep 17 00:00:00 2001 From: jpirnay Date: Sat, 28 Feb 2026 05:31:12 +0100 Subject: [PATCH] Review comments --- lib/KOReaderSync/ChapterXPathIndexer.cpp | 20 ++++++++++++++++---- lib/KOReaderSync/ProgressMapper.cpp | 4 ++-- lib/KOReaderSync/ProgressMapper.h | 4 ++-- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/KOReaderSync/ChapterXPathIndexer.cpp b/lib/KOReaderSync/ChapterXPathIndexer.cpp index 28635486..667616b7 100644 --- a/lib/KOReaderSync/ChapterXPathIndexer.cpp +++ b/lib/KOReaderSync/ChapterXPathIndexer.cpp @@ -20,6 +20,7 @@ namespace { struct XPathAnchor { size_t textOffset = 0; std::string xpath; + std::string xpathNoIndex; // precomputed removeIndices(xpath) }; struct StackNode { @@ -129,8 +130,7 @@ struct ParserState { bool found = false; for (const auto& anchor : anchors) { - const std::string normalizedAnchor = normalizeXPath(anchor.xpath); - const std::string anchorPath = ignoreIndices ? removeIndices(normalizedAnchor) : normalizedAnchor; + const std::string& anchorPath = ignoreIndices ? anchor.xpathNoIndex : anchor.xpath; if (anchorPath == probe) { const int depth = pathDepth(anchorPath); if (!found || depth > bestDepth || (depth == bestDepth && anchor.textOffset < bestOffset)) { @@ -221,12 +221,13 @@ struct ParserState { } if (!stack.back().hasTextAnchor) { - anchors.push_back({totalTextBytes, currentXPath()}); + const std::string xpath = currentXPath(); + anchors.push_back({totalTextBytes, xpath, removeIndices(xpath)}); stack.back().hasTextAnchor = true; } else if (anchors.empty() || totalTextBytes - anchors.back().textOffset >= 192) { const std::string xpath = currentXPath(); if (anchors.empty() || anchors.back().xpath != xpath) { - anchors.push_back({totalTextBytes, xpath}); + anchors.push_back({totalTextBytes, xpath, removeIndices(xpath)}); } } } @@ -358,6 +359,17 @@ void XMLCALL onCharacterData(void* userData, const XML_Char* text, const int len } void XMLCALL onDefaultHandlerExpand(void* userData, const XML_Char* text, const int len) { + // The default handler fires for comments, PIs, DOCTYPE, and entity references. + // Only forward entity references (&..;) to avoid skewing text offsets with + // non-visible markup. + if (len < 3 || text[0] != '&' || text[len - 1] != ';') { + return; + } + for (int i = 1; i < len - 1; ++i) { + if (text[i] == '<' || text[i] == '>') { + return; + } + } auto* state = static_cast(userData); state->onCharacterData(text, len); } diff --git a/lib/KOReaderSync/ProgressMapper.cpp b/lib/KOReaderSync/ProgressMapper.cpp index d62e0608..f974da1b 100644 --- a/lib/KOReaderSync/ProgressMapper.cpp +++ b/lib/KOReaderSync/ProgressMapper.cpp @@ -24,7 +24,7 @@ KOReaderPosition ProgressMapper::toKOReader(const std::shared_ptr& epub, c // to a synthetic chapter-level path if parsing fails. result.xpath = ChapterXPathIndexer::findXPathForProgress(epub, pos.spineIndex, intraSpineProgress); if (result.xpath.empty()) { - result.xpath = generateXPath(pos.spineIndex, pos.pageNumber, pos.totalPages); + result.xpath = generateXPath(pos.spineIndex); } // Get chapter info for logging @@ -150,7 +150,7 @@ CrossPointPosition ProgressMapper::toCrossPoint(const std::shared_ptr& epu return result; } -std::string ProgressMapper::generateXPath(int spineIndex, int pageNumber, int totalPages) { +std::string ProgressMapper::generateXPath(int spineIndex) { // Fallback path when element-level XPath extraction is unavailable. // KOReader uses 1-based XPath predicates; spineIndex is 0-based internally. return "/body/DocFragment[" + std::to_string(spineIndex + 1) + "]/body"; diff --git a/lib/KOReaderSync/ProgressMapper.h b/lib/KOReaderSync/ProgressMapper.h index 6195fccc..6e375681 100644 --- a/lib/KOReaderSync/ProgressMapper.h +++ b/lib/KOReaderSync/ProgressMapper.h @@ -68,7 +68,7 @@ class ProgressMapper { private: /** * Generate XPath for KOReader compatibility. - * Fallback format: /body/DocFragment[spineIndex]/body + * Fallback format: /body/DocFragment[spineIndex + 1]/body */ - static std::string generateXPath(int spineIndex, int pageNumber, int totalPages); + static std::string generateXPath(int spineIndex); };