## Summary * **What is the goal of this PR?** * This PR ports over Crossink's handling of large EPUBs that helps prevent crashes during open after the book metadata cache is built. * **What changes are included?** * Removes the post-indexing ZIP-wide CSS discovery pass that built an in-memory map of every ZIP entry. * Reuses `content.opf` parsing to collect declared CSS files without writing spine entries again. * Temporarily releases the loaded book metadata cache while rebuilding CSS for cached books. * Parses CSS before reloading `book.bin` after a fresh cache build, leaving more heap available during CSS rule parsing. ## Additional Context * User reported their EPUB opening fine on Crossink but would crash on Crosspoint. Verified this claim on my own devices. * The crash this addresses happened after `book.bin` was successfully built, when CSS discovery allocated a large `unordered_map` for ~3k EPUB ZIP entries. * Tradeoff: CSS files not declared in `content.opf` are no longer discovered by scanning the full ZIP. This avoids the high-risk memory allocation but improperly formatted EPUBs (ones that don't declare their CSS styles in `content.opf` will render without styling and fallback to inline styles. * User provided epub that was crashing prior to this change: https://www.mediafire.com/file/g57ea4mj13iunvh/Quang+%C3%82m+Chi+Ngo%E1%BA%A1i+-+Nh%C4%A9+C%C4%83n.epub/file --- ### 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 >**_
78 lines
2.8 KiB
C++
78 lines
2.8 KiB
C++
#pragma once
|
|
|
|
#include <Print.h>
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "Epub/BookMetadataCache.h"
|
|
#include "Epub/css/CssParser.h"
|
|
|
|
class ZipFile;
|
|
|
|
class Epub {
|
|
// the ncx file (EPUB 2)
|
|
std::string tocNcxItem;
|
|
// the nav file (EPUB 3)
|
|
std::string tocNavItem;
|
|
// where is the EPUBfile?
|
|
std::string filepath;
|
|
// the base path for items in the EPUB file
|
|
std::string contentBasePath;
|
|
// Uniq cache key based on filepath
|
|
std::string cachePath;
|
|
// Spine and TOC cache
|
|
std::unique_ptr<BookMetadataCache> bookMetadataCache;
|
|
// CSS parser for styling
|
|
std::unique_ptr<CssParser> cssParser;
|
|
// CSS files
|
|
std::vector<std::string> cssFiles;
|
|
|
|
bool findContentOpfFile(std::string* contentOpfFile) const;
|
|
bool parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata, bool writeSpineEntries = true);
|
|
bool parseTocNcxFile() const;
|
|
bool parseTocNavFile() const;
|
|
void discoverCssFilesFromZip();
|
|
void parseCssFiles() const;
|
|
|
|
public:
|
|
explicit Epub(std::string filepath, const std::string& cacheDir) : filepath(std::move(filepath)) {
|
|
// create a cache key based on the filepath
|
|
cachePath = cacheDir + "/epub_" + std::to_string(std::hash<std::string>{}(this->filepath));
|
|
}
|
|
~Epub() = default;
|
|
std::string& getBasePath() { return contentBasePath; }
|
|
bool load(bool buildIfMissing = true, bool skipLoadingCss = false);
|
|
bool clearCache() const;
|
|
void setupCacheDir() const;
|
|
const std::string& getCachePath() const;
|
|
const std::string& getPath() const;
|
|
const std::string& getTitle() const;
|
|
const std::string& getAuthor() const;
|
|
const std::string& getLanguage() const;
|
|
std::string getCoverBmpPath(bool cropped = false) const;
|
|
bool generateCoverBmp(bool cropped = false) const;
|
|
std::string getThumbBmpPath() const;
|
|
std::string getThumbBmpPath(int height) const;
|
|
bool generateThumbBmp(int height) const;
|
|
uint8_t* readItemContentsToBytes(const std::string& itemHref, size_t* size = nullptr,
|
|
bool trailingNullByte = false) const;
|
|
bool readItemContentsToStream(const std::string& itemHref, Print& out, size_t chunkSize) const;
|
|
bool getItemSize(const std::string& itemHref, size_t* size) const;
|
|
BookMetadataCache::SpineEntry getSpineItem(int spineIndex) const;
|
|
BookMetadataCache::TocEntry getTocItem(int tocIndex) const;
|
|
int getSpineItemsCount() const;
|
|
int getTocItemsCount() const;
|
|
int getSpineIndexForTocIndex(int tocIndex) const;
|
|
int getTocIndexForSpineIndex(int spineIndex) const;
|
|
size_t getCumulativeSpineItemSize(int spineIndex) const;
|
|
int getSpineIndexForTextReference() const;
|
|
|
|
size_t getBookSize() const;
|
|
float calculateProgress(int currentSpineIndex, float currentSpineRead) const;
|
|
CssParser* getCssParser() const { return cssParser.get(); }
|
|
int resolveHrefToSpineIndex(const std::string& href) const;
|
|
};
|