Fix br.0 indexing issue
This commit is contained in:
@@ -45,7 +45,8 @@ size_t countVisibleBytes(const XML_Char* text, const int len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Canonicalize a KOReader XPath for comparison:
|
// Canonicalize a KOReader XPath for comparison:
|
||||||
// - remove whitespace, lowercase, strip /text() with optional char offset.
|
// - remove whitespace, lowercase, strip /text() with optional char offset,
|
||||||
|
// strip trailing .N text-child-index suffix on the last segment (e.g. br.0 → br).
|
||||||
std::string normalizeXPath(const std::string& input) {
|
std::string normalizeXPath(const std::string& input) {
|
||||||
if (input.empty()) {
|
if (input.empty()) {
|
||||||
return "";
|
return "";
|
||||||
@@ -71,6 +72,25 @@ std::string normalizeXPath(const std::string& input) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Strip trailing .N text-child-index suffix on the last path segment
|
||||||
|
// (KOReader notation, e.g. /div/br.0 → /div/br).
|
||||||
|
const size_t lastSlash = out.rfind('/');
|
||||||
|
if (lastSlash != std::string::npos) {
|
||||||
|
const size_t dotPos = out.find('.', lastSlash + 1);
|
||||||
|
if (dotPos != std::string::npos && dotPos + 1 < out.size()) {
|
||||||
|
bool allDigits = true;
|
||||||
|
for (size_t i = dotPos + 1; i < out.size(); i++) {
|
||||||
|
if (!std::isdigit(static_cast<unsigned char>(out[i]))) {
|
||||||
|
allDigits = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allDigits) {
|
||||||
|
out.erase(dotPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (!out.empty() && out.back() == '/') {
|
while (!out.empty() && out.back() == '/') {
|
||||||
out.pop_back();
|
out.pop_back();
|
||||||
}
|
}
|
||||||
@@ -450,7 +470,16 @@ void XMLCALL revStart(void* ud, const XML_Char* name, const XML_Char**) {
|
|||||||
static_cast<ReverseState*>(ud)->pushElement(name);
|
static_cast<ReverseState*>(ud)->pushElement(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XMLCALL revEnd(void* ud, const XML_Char*) { static_cast<ReverseState*>(ud)->popElement(); }
|
void XMLCALL revEnd(void* ud, const XML_Char*) {
|
||||||
|
auto* state = static_cast<ReverseState*>(ud);
|
||||||
|
// Textless elements (e.g. <br/>) never trigger onChar, so check for a match
|
||||||
|
// before popping. The byte offset recorded is the text seen so far, which
|
||||||
|
// is the correct position ("just before this element").
|
||||||
|
if (!state->stack.empty() && !state->stack.back().hasText) {
|
||||||
|
state->checkMatch();
|
||||||
|
}
|
||||||
|
state->popElement();
|
||||||
|
}
|
||||||
|
|
||||||
void XMLCALL revChar(void* ud, const XML_Char* text, const int len) {
|
void XMLCALL revChar(void* ud, const XML_Char* text, const int len) {
|
||||||
static_cast<ReverseState*>(ud)->onChar(text, len);
|
static_cast<ReverseState*>(ud)->onChar(text, len);
|
||||||
|
|||||||
Reference in New Issue
Block a user