## Summary * **What is the goal of this PR?** Slightly increase the OOM limit when loading epubs * **What changes are included?** Switched vectors for parsing epubs to deques, allowing use of more memory ## Additional Context * Increases loadable epub size from 2000+ chapter/ToC entries loadable to 5000+ chapter/ToC entries * #1574, but without the complicated stuff --- ### 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? _**NO**_ ### Testing | Commit | Book | Time | |----------|------|-------| |83cd96bc2f| 1000.epub | ~30 sec | |83cd96bc2f| 5000.epub | crash | | PR | 1000.epub | ~29 sec | | PR | 5000.epub | ~2 min 20 sec | => No actual loading time regressions [tested_epubs.zip](https://github.com/user-attachments/files/26645243/tested_epubs.zip)
81 lines
2.2 KiB
C++
81 lines
2.2 KiB
C++
#pragma once
|
|
#include <Print.h>
|
|
|
|
#include <algorithm>
|
|
#include <deque>
|
|
#include <vector>
|
|
|
|
#include "Epub.h"
|
|
#include "expat.h"
|
|
|
|
class BookMetadataCache;
|
|
|
|
class ContentOpfParser final : public Print {
|
|
enum ParserState {
|
|
START,
|
|
IN_PACKAGE,
|
|
IN_METADATA,
|
|
IN_BOOK_TITLE,
|
|
IN_BOOK_AUTHOR,
|
|
IN_BOOK_LANGUAGE,
|
|
IN_MANIFEST,
|
|
IN_SPINE,
|
|
IN_GUIDE,
|
|
};
|
|
|
|
const std::string& cachePath;
|
|
const std::string& baseContentPath;
|
|
size_t remainingSize;
|
|
XML_Parser parser = nullptr;
|
|
ParserState state = START;
|
|
BookMetadataCache* cache;
|
|
FsFile tempItemStore;
|
|
std::string coverItemId;
|
|
|
|
// Index for fast idref→href lookup (used only for large EPUBs)
|
|
struct ItemIndexEntry {
|
|
uint32_t idHash; // FNV-1a hash of itemId
|
|
uint16_t idLen; // length for collision reduction
|
|
uint32_t fileOffset; // offset in .items.bin
|
|
};
|
|
std::deque<ItemIndexEntry> itemIndex;
|
|
bool useItemIndex = false;
|
|
|
|
static constexpr uint16_t LARGE_SPINE_THRESHOLD = 400;
|
|
|
|
// FNV-1a hash function
|
|
static uint32_t fnvHash(const std::string& s) {
|
|
uint32_t hash = 2166136261u;
|
|
for (char c : s) {
|
|
hash ^= static_cast<uint8_t>(c);
|
|
hash *= 16777619u;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
static void startElement(void* userData, const XML_Char* name, const XML_Char** atts);
|
|
static void characterData(void* userData, const XML_Char* s, int len);
|
|
static void endElement(void* userData, const XML_Char* name);
|
|
|
|
public:
|
|
std::string title;
|
|
std::string author;
|
|
std::string language;
|
|
std::string tocNcxPath;
|
|
std::string tocNavPath; // EPUB 3 nav document path
|
|
std::string coverItemHref;
|
|
std::string guideCoverPageHref; // Guide reference with type="cover" or "cover-page" (points to XHTML wrapper)
|
|
std::string textReferenceHref;
|
|
std::vector<std::string> cssFiles; // CSS stylesheet paths
|
|
|
|
explicit ContentOpfParser(const std::string& cachePath, const std::string& baseContentPath, const size_t xmlSize,
|
|
BookMetadataCache* cache)
|
|
: cachePath(cachePath), baseContentPath(baseContentPath), remainingSize(xmlSize), cache(cache) {}
|
|
~ContentOpfParser() override;
|
|
|
|
bool setup();
|
|
|
|
size_t write(uint8_t) override;
|
|
size_t write(const uint8_t* buffer, size_t size) override;
|
|
};
|