fix: Handle EPUB 3 TOC to spine mapping when nav file in subdirectory

Fixes https://github.com/daveallie/crosspoint-reader/issues/264
This commit is contained in:
Dave Allie 2026-01-13 00:52:00 +11:00
parent 0165fab581
commit 93a68b9ffa
No known key found for this signature in database
GPG Key ID: F2FDDB3AD8D0276F
4 changed files with 10 additions and 5 deletions

View File

@ -167,7 +167,10 @@ bool Epub::parseTocNavFile() const {
} }
const auto navSize = tempNavFile.size(); const auto navSize = tempNavFile.size();
TocNavParser navParser(contentBasePath, navSize, bookMetadataCache.get()); // Note: We can't use `contentBasePath` here as the nav file may be in a different folder to the content.opf
// and the HTMLX nav file will have hrefs relative to itself
const std::string navContentBasePath = tocNavItem.substr(0, tocNavItem.find_last_of('/') + 1);
TocNavParser navParser(navContentBasePath, navSize, bookMetadataCache.get());
if (!navParser.setup()) { if (!navParser.setup()) {
Serial.printf("[%lu] [EBP] Could not setup toc nav parser\n", millis()); Serial.printf("[%lu] [EBP] Could not setup toc nav parser\n", millis());

View File

@ -167,7 +167,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
if (strcmp(atts[i], "id") == 0) { if (strcmp(atts[i], "id") == 0) {
itemId = atts[i + 1]; itemId = atts[i + 1];
} else if (strcmp(atts[i], "href") == 0) { } else if (strcmp(atts[i], "href") == 0) {
href = self->baseContentPath + atts[i + 1]; href = FsHelpers::normalisePath(self->baseContentPath + atts[i + 1]);
} else if (strcmp(atts[i], "media-type") == 0) { } else if (strcmp(atts[i], "media-type") == 0) {
mediaType = atts[i + 1]; mediaType = atts[i + 1];
} else if (strcmp(atts[i], "properties") == 0) { } else if (strcmp(atts[i], "properties") == 0) {
@ -243,7 +243,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
break; break;
} }
} else if (strcmp(atts[i], "href") == 0) { } else if (strcmp(atts[i], "href") == 0) {
textHref = self->baseContentPath + atts[i + 1]; textHref = FsHelpers::normalisePath(self->baseContentPath + atts[i + 1]);
} }
} }
if ((type == "text" || (type == "start" && !self->textReferenceHref.empty())) && (textHref.length() > 0)) { if ((type == "text" || (type == "start" && !self->textReferenceHref.empty())) && (textHref.length() > 0)) {

View File

@ -1,5 +1,6 @@
#include "TocNavParser.h" #include "TocNavParser.h"
#include <FsHelpers.h>
#include <HardwareSerial.h> #include <HardwareSerial.h>
#include "../BookMetadataCache.h" #include "../BookMetadataCache.h"
@ -140,7 +141,7 @@ void XMLCALL TocNavParser::endElement(void* userData, const XML_Char* name) {
if (strcmp(name, "a") == 0 && self->state == IN_ANCHOR) { if (strcmp(name, "a") == 0 && self->state == IN_ANCHOR) {
// Create TOC entry when closing anchor tag (we have all data now) // Create TOC entry when closing anchor tag (we have all data now)
if (!self->currentLabel.empty() && !self->currentHref.empty()) { if (!self->currentLabel.empty() && !self->currentHref.empty()) {
std::string href = self->baseContentPath + self->currentHref; std::string href = FsHelpers::normalisePath(self->baseContentPath + self->currentHref);
std::string anchor; std::string anchor;
const size_t pos = href.find('#'); const size_t pos = href.find('#');

View File

@ -1,5 +1,6 @@
#include "TocNcxParser.h" #include "TocNcxParser.h"
#include <FsHelpers.h>
#include <HardwareSerial.h> #include <HardwareSerial.h>
#include "../BookMetadataCache.h" #include "../BookMetadataCache.h"
@ -159,7 +160,7 @@ void XMLCALL TocNcxParser::endElement(void* userData, const XML_Char* name) {
// This is the safest place to push the data, assuming <navLabel> always comes before <content>. // This is the safest place to push the data, assuming <navLabel> always comes before <content>.
// NCX spec says navLabel comes before content. // NCX spec says navLabel comes before content.
if (!self->currentLabel.empty() && !self->currentSrc.empty()) { if (!self->currentLabel.empty() && !self->currentSrc.empty()) {
std::string href = self->baseContentPath + self->currentSrc; std::string href = FsHelpers::normalisePath(self->baseContentPath + self->currentSrc);
std::string anchor; std::string anchor;
const size_t pos = href.find('#'); const size_t pos = href.find('#');