Xteink-X4-crosspoint-reader/lib/Epub/Epub/BookMetadataCache.h
Jake Kenneally f0ac68d26c Address review comments
- Renamed `getIndentWidth` to `getTextAdvanceX`
- Collapsed `Style` and `BlockStyle` into a single struct, and switched to using bitflag setup for determining font style in `EpdFontFamily::Style`, including underlined text
- Added caching for parsed CSS rules
- Reverted changes for fixing spurious spaces
- Skipped loading CSS on Sleep and HomeScreen activities, since we only need BookMetadata and the cover image
- Reverted changes to BookMetadataCache, since we don't need to cache the individual CSS files and can instead use the parsed CSS rules (and the new cache file for those)
- Switched intermediary values to direct assignment in `CssParser.cpp`
- Added function in `BlockStyle.h` to directly convert from a `CssStyle` to a `BlockStyle`, as well as combined multiple `BlockStyle`s together for nested elements that should inherit the parent's style when the child's is unspecified
- Updated names of variables in `CssStyle` to match those of the CSS they represent (e.g. alignment -> textAlign, indent -> textIndent)
- General cleaning up and simplifying the code
2026-02-02 22:18:06 -05:00

113 lines
3.1 KiB
C++

#pragma once
#include <SDCardManager.h>
#include <algorithm>
#include <string>
#include <vector>
class BookMetadataCache {
public:
struct BookMetadata {
std::string title;
std::string author;
std::string language;
std::string coverItemHref;
std::string textReferenceHref;
};
struct SpineEntry {
std::string href;
size_t cumulativeSize;
int16_t tocIndex;
SpineEntry() : cumulativeSize(0), tocIndex(-1) {}
SpineEntry(std::string href, const size_t cumulativeSize, const int16_t tocIndex)
: href(std::move(href)), cumulativeSize(cumulativeSize), tocIndex(tocIndex) {}
};
struct TocEntry {
std::string title;
std::string href;
std::string anchor;
uint8_t level;
int16_t spineIndex;
TocEntry() : level(0), spineIndex(-1) {}
TocEntry(std::string title, std::string href, std::string anchor, const uint8_t level, const int16_t spineIndex)
: title(std::move(title)),
href(std::move(href)),
anchor(std::move(anchor)),
level(level),
spineIndex(spineIndex) {}
};
private:
std::string cachePath;
size_t lutOffset;
uint16_t spineCount;
uint16_t tocCount;
bool loaded;
bool buildMode;
FsFile bookFile;
// Temp file handles during build
FsFile spineFile;
FsFile tocFile;
// Index for fast href→spineIndex lookup (used only for large EPUBs)
struct SpineHrefIndexEntry {
uint64_t hrefHash; // FNV-1a 64-bit hash
uint16_t hrefLen; // length for collision reduction
int16_t spineIndex;
};
std::vector<SpineHrefIndexEntry> spineHrefIndex;
bool useSpineHrefIndex = false;
static constexpr uint16_t LARGE_SPINE_THRESHOLD = 400;
// FNV-1a 64-bit hash function
static uint64_t fnvHash64(const std::string& s) {
uint64_t hash = 14695981039346656037ull;
for (char c : s) {
hash ^= static_cast<uint8_t>(c);
hash *= 1099511628211ull;
}
return hash;
}
uint32_t writeSpineEntry(FsFile& file, const SpineEntry& entry) const;
uint32_t writeTocEntry(FsFile& file, const TocEntry& entry) const;
SpineEntry readSpineEntry(FsFile& file) const;
TocEntry readTocEntry(FsFile& file) const;
public:
BookMetadata coreMetadata;
explicit BookMetadataCache(std::string cachePath)
: cachePath(std::move(cachePath)), lutOffset(0), spineCount(0), tocCount(0), loaded(false), buildMode(false) {}
~BookMetadataCache() = default;
// Building phase (stream to disk immediately)
bool beginWrite();
bool beginContentOpfPass();
void createSpineEntry(const std::string& href);
bool endContentOpfPass();
bool beginTocPass();
void createTocEntry(const std::string& title, const std::string& href, const std::string& anchor, uint8_t level);
bool endTocPass();
bool endWrite();
bool cleanupTmpFiles() const;
// Post-processing to update mappings and sizes
bool buildBookBin(const std::string& epubPath, const BookMetadata& metadata);
// Reading phase (read mode)
bool load();
SpineEntry getSpineEntry(int index);
TocEntry getTocEntry(int index);
int getSpineCount() const { return spineCount; }
int getTocCount() const { return tocCount; }
bool isLoaded() const { return loaded; }
};