must not reach the layout
+ // engine — they would accumulate path data and exhaust heap on large inline SVG.
+ if (self->svgDepth > 0 && !matches(name, IMAGE_TAGS, NUM_IMAGE_TAGS)) {
+ self->depth += 1;
+ return;
+ }
+
// Extract class, style, and id attributes
std::string classAttr;
std::string styleAttr;
@@ -1319,6 +1335,12 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char
return;
}
+ // Skip SVG text content (path data, coordinates, etc.) — it would be treated as words
+ // and exhaust heap on EPUBs with large inline SVG elements.
+ if (self->svgDepth > 0) {
+ return;
+ }
+
// Collect footnote link display text (for the number label)
// Remove leading/trailing whitespace and square brackets from the
// footnote link text to normalize noterefs like "[1]" → "1"
@@ -1559,6 +1581,10 @@ void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* n
self->depth -= 1;
+ if (strcmp(name, "svg") == 0 && self->svgDepth > 0) {
+ self->svgDepth -= 1;
+ }
+
// Pop list entries whose ul/ol is now out of scope
while (!self->listStack.empty() && self->listStack.back().depth >= self->depth) {
self->listStack.pop_back();
diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h
index 6c1f9eb9..c632b254 100644
--- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h
+++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h
@@ -36,6 +36,7 @@ class ChapterHtmlSlimParser final : public Print {
int underlineUntilDepth = INT_MAX;
int strikethroughUntilDepth = INT_MAX;
int preUntilDepth = INT_MAX; // set when inside a element; enables \n → line-break handling
+ int svgDepth = 0; // nesting counter for