From 3fb9ac9e297388062a1ca468ca76b22d2fbcc77b Mon Sep 17 00:00:00 2001 From: jpirnay Date: Mon, 20 Apr 2026 13:15:05 +0200 Subject: [PATCH] Finetuning 2 --- lib/Epub/Epub/Section.cpp | 18 +++---- .../ChapterXPathReverseMapper.cpp | 54 +++++++++++-------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/lib/Epub/Epub/Section.cpp b/lib/Epub/Epub/Section.cpp index 06ff3420..bdf6c0a5 100644 --- a/lib/Epub/Epub/Section.cpp +++ b/lib/Epub/Epub/Section.cpp @@ -584,23 +584,21 @@ std::optional Section::getPageForParagraphIndex(const uint16_t pIndex) return std::nullopt; } - // Find the page that contains the requested paragraph index. - // Each entry stores the first paragraph index for that page, so the page - // containing pIndex is the last page whose start paragraph is <= pIndex. - uint16_t resultPage = 0; + // Each LUT entry stores the paragraph index at page-break time — i.e. the last + //

whose start tag had been seen while page i was being laid out. Paragraph + // P therefore first appears on the smallest i where storedPIdx[i] >= P. for (uint16_t i = 0; i < count; i++) { - uint32_t byteOffset; + f.seek(paragraphLutOffset + sizeof(uint16_t) + i * ENTRY_SIZE + sizeof(uint32_t)); uint16_t pagePIdx; - serialization::readPod(f, byteOffset); serialization::readPod(f, pagePIdx); - if (pagePIdx > pIndex) { - break; + if (pagePIdx >= pIndex) { + f.close(); + return i; } - resultPage = i; } f.close(); - return resultPage; + return static_cast(count - 1); } std::optional Section::getParagraphIndexForPage(const uint16_t page) const { diff --git a/lib/KOReaderSync/ChapterXPathReverseMapper.cpp b/lib/KOReaderSync/ChapterXPathReverseMapper.cpp index b9cc9d81..ecf82b7a 100644 --- a/lib/KOReaderSync/ChapterXPathReverseMapper.cpp +++ b/lib/KOReaderSync/ChapterXPathReverseMapper.cpp @@ -47,33 +47,43 @@ struct ReverseState : StackState { const char* bestTierName = nullptr; ReverseState(const int spineIndex, const std::string& xpath) : spineIndex(spineIndex) { - // Parse optional /text()[N].M suffix before normalizing for element matching. + // Parse optional text-node suffix before normalizing for element matching. + // KOReader emits two shapes that both land here: + // /text()[N].M — explicit 1-based text-node index + codepoint offset + // /text().M — implicit first text-node (N=1) + codepoint offset std::string raw = xpath; for (char& c : raw) c = static_cast(std::tolower(static_cast(c))); - const std::string tnPat = "/text()["; + const std::string tnPat = "/text()"; const size_t tnPos = raw.rfind(tnPat); if (tnPos != std::string::npos) { - const size_t numStart = tnPos + tnPat.size(); - size_t numEnd = numStart; - while (numEnd < raw.size() && std::isdigit(static_cast(raw[numEnd]))) { - numEnd++; + size_t cursor = tnPos + tnPat.size(); + int nodeIdx = 1; + bool valid = true; + if (cursor < raw.size() && raw[cursor] == '[') { + cursor++; + size_t numEnd = cursor; + while (numEnd < raw.size() && std::isdigit(static_cast(raw[numEnd]))) { + numEnd++; + } + if (numEnd > cursor && numEnd < raw.size() && raw[numEnd] == ']') { + nodeIdx = static_cast(std::strtol(raw.substr(cursor, numEnd - cursor).c_str(), nullptr, 10)); + cursor = numEnd + 1; + } else { + valid = false; + } } - if (numEnd > numStart && numEnd < raw.size() && raw[numEnd] == ']') { - const long nodeIdx = std::strtol(raw.substr(numStart, numEnd - numStart).c_str(), nullptr, 10); - if (nodeIdx >= 1) { - targetTextNodeIndex = static_cast(nodeIdx); - size_t after = numEnd + 1; - if (after < raw.size() && raw[after] == '.') { - after++; - size_t charEnd = after; - while (charEnd < raw.size() && std::isdigit(static_cast(raw[charEnd]))) { - charEnd++; - } - if (charEnd > after) { - const long charOff = std::strtol(raw.substr(after, charEnd - after).c_str(), nullptr, 10); - if (charOff >= 0) { - targetCharOffset = static_cast(charOff); - } + if (valid && nodeIdx >= 1) { + targetTextNodeIndex = nodeIdx; + if (cursor < raw.size() && raw[cursor] == '.') { + cursor++; + size_t charEnd = cursor; + while (charEnd < raw.size() && std::isdigit(static_cast(raw[charEnd]))) { + charEnd++; + } + if (charEnd > cursor) { + const long charOff = std::strtol(raw.substr(cursor, charEnd - cursor).c_str(), nullptr, 10); + if (charOff >= 0) { + targetCharOffset = static_cast(charOff); } } }