A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: Handle EPUB 3 TOC to spine mapping when nav file in subdirectory (#332)

## Summary

- Nav file in EPUB 3 file is a HTML file with relative hrefs
- If this file exists anywhere but in the same location as the
content.opf file, navigating in the book will fail
- Bump the book cache version to rebuild potentially broken books

## Additional Context

- Fixes https://github.com/daveallie/crosspoint-reader/issues/264

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code?

- [ ] Yes
- [ ] Partially
- [x] No

authored by

Dave Allie and committed by
GitHub
8f3df7e1 0165fab5

+11 -6
+4 -1
lib/Epub/Epub.cpp
··· 167 167 } 168 168 const auto navSize = tempNavFile.size(); 169 169 170 - TocNavParser navParser(contentBasePath, navSize, bookMetadataCache.get()); 170 + // Note: We can't use `contentBasePath` here as the nav file may be in a different folder to the content.opf 171 + // and the HTMLX nav file will have hrefs relative to itself 172 + const std::string navContentBasePath = tocNavItem.substr(0, tocNavItem.find_last_of('/') + 1); 173 + TocNavParser navParser(navContentBasePath, navSize, bookMetadataCache.get()); 171 174 172 175 if (!navParser.setup()) { 173 176 Serial.printf("[%lu] [EBP] Could not setup toc nav parser\n", millis());
+1 -1
lib/Epub/Epub/BookMetadataCache.cpp
··· 9 9 #include "FsHelpers.h" 10 10 11 11 namespace { 12 - constexpr uint8_t BOOK_CACHE_VERSION = 3; 12 + constexpr uint8_t BOOK_CACHE_VERSION = 4; 13 13 constexpr char bookBinFile[] = "/book.bin"; 14 14 constexpr char tmpSpineBinFile[] = "/spine.bin.tmp"; 15 15 constexpr char tmpTocBinFile[] = "/toc.bin.tmp";
+2 -2
lib/Epub/Epub/parsers/ContentOpfParser.cpp
··· 167 167 if (strcmp(atts[i], "id") == 0) { 168 168 itemId = atts[i + 1]; 169 169 } else if (strcmp(atts[i], "href") == 0) { 170 - href = self->baseContentPath + atts[i + 1]; 170 + href = FsHelpers::normalisePath(self->baseContentPath + atts[i + 1]); 171 171 } else if (strcmp(atts[i], "media-type") == 0) { 172 172 mediaType = atts[i + 1]; 173 173 } else if (strcmp(atts[i], "properties") == 0) { ··· 243 243 break; 244 244 } 245 245 } else if (strcmp(atts[i], "href") == 0) { 246 - textHref = self->baseContentPath + atts[i + 1]; 246 + textHref = FsHelpers::normalisePath(self->baseContentPath + atts[i + 1]); 247 247 } 248 248 } 249 249 if ((type == "text" || (type == "start" && !self->textReferenceHref.empty())) && (textHref.length() > 0)) {
+2 -1
lib/Epub/Epub/parsers/TocNavParser.cpp
··· 1 1 #include "TocNavParser.h" 2 2 3 + #include <FsHelpers.h> 3 4 #include <HardwareSerial.h> 4 5 5 6 #include "../BookMetadataCache.h" ··· 140 141 if (strcmp(name, "a") == 0 && self->state == IN_ANCHOR) { 141 142 // Create TOC entry when closing anchor tag (we have all data now) 142 143 if (!self->currentLabel.empty() && !self->currentHref.empty()) { 143 - std::string href = self->baseContentPath + self->currentHref; 144 + std::string href = FsHelpers::normalisePath(self->baseContentPath + self->currentHref); 144 145 std::string anchor; 145 146 146 147 const size_t pos = href.find('#');
+2 -1
lib/Epub/Epub/parsers/TocNcxParser.cpp
··· 1 1 #include "TocNcxParser.h" 2 2 3 + #include <FsHelpers.h> 3 4 #include <HardwareSerial.h> 4 5 5 6 #include "../BookMetadataCache.h" ··· 159 160 // This is the safest place to push the data, assuming <navLabel> always comes before <content>. 160 161 // NCX spec says navLabel comes before content. 161 162 if (!self->currentLabel.empty() && !self->currentSrc.empty()) { 162 - std::string href = self->baseContentPath + self->currentSrc; 163 + std::string href = FsHelpers::normalisePath(self->baseContentPath + self->currentSrc); 163 164 std::string anchor; 164 165 165 166 const size_t pos = href.find('#');