src/lib/MSPUBParser.cpp | 12 ++++++++++-- src/lib/MSPUBParser.h | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-)
New commits: commit 3b9ab5b25d0a072009482eac8bc0ba68da952bc4 Author: Caolán McNamara <[email protected]> AuthorDate: Fri May 22 14:32:02 2026 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Fri May 22 18:02:53 2026 +0200 cap parseShapeGroup recursion depth Cap parseShapeGroup at 100 levels of nesting. Real Publisher documents nest groups at most a handful deep - LibreOffice core's PowerPoint Escher exporter caps emit at 12 with a note that PowerPoint itself complains past 16 Change-Id: I58c2fbb4a0c4610943147b7abe6c948413953911 Reviewed-on: https://gerrit.libreoffice.org/c/libmspub/+/205559 Tested-by: Caolán McNamara <[email protected]> Reviewed-by: Caolán McNamara <[email protected]> diff --git a/src/lib/MSPUBParser.cpp b/src/lib/MSPUBParser.cpp index 214d54c..5c2d173 100644 --- a/src/lib/MSPUBParser.cpp +++ b/src/lib/MSPUBParser.cpp @@ -51,6 +51,12 @@ namespace libmspub namespace { +// Well above the ~12 ceiling LibreOffice's PowerPoint Escher exporter +// applies (sd/source/filter/eppt/escherex.cxx +// PptEscherEx::CloseContainer notes PPT itself struggles past 16), well +// below any stack-overflow risk. +constexpr unsigned MAX_SHAPE_GROUP_DEPTH = 100; + Underline readUnderline(const unsigned value) { switch (value & 0xff) @@ -1579,8 +1585,10 @@ bool MSPUBParser::parseEscher(librevenge::RVNGInputStream *input) return true; } -void MSPUBParser::parseShapeGroup(librevenge::RVNGInputStream *input, const EscherContainerInfo &spgr, Coordinate parentCoordinateSystem, Coordinate parentGroupAbsoluteCoord) +void MSPUBParser::parseShapeGroup(librevenge::RVNGInputStream *input, const EscherContainerInfo &spgr, Coordinate parentCoordinateSystem, Coordinate parentGroupAbsoluteCoord, unsigned depth) { + if (depth > MAX_SHAPE_GROUP_DEPTH) + return; EscherContainerInfo shapeOrGroup; std::set<unsigned short> types; types.insert(OFFICE_ART_SPGR_CONTAINER); @@ -1591,7 +1599,7 @@ void MSPUBParser::parseShapeGroup(librevenge::RVNGInputStream *input, const Esch { case OFFICE_ART_SPGR_CONTAINER: m_collector->beginGroup(); - parseShapeGroup(input, shapeOrGroup, parentCoordinateSystem, parentGroupAbsoluteCoord); + parseShapeGroup(input, shapeOrGroup, parentCoordinateSystem, parentGroupAbsoluteCoord, depth + 1); m_collector->endGroup(); break; case OFFICE_ART_SP_CONTAINER: diff --git a/src/lib/MSPUBParser.h b/src/lib/MSPUBParser.h index 9d00a8f..15eb253 100644 --- a/src/lib/MSPUBParser.h +++ b/src/lib/MSPUBParser.h @@ -116,7 +116,7 @@ protected: void parseColors(librevenge::RVNGInputStream *input, const QuillChunkReference &chunk); void parseFonts(librevenge::RVNGInputStream *input, const QuillChunkReference &chunk); void parseDefaultStyle(librevenge::RVNGInputStream *input, const QuillChunkReference &chunk); - void parseShapeGroup(librevenge::RVNGInputStream *input, const EscherContainerInfo &spgr, Coordinate parentCoordinateSystem, Coordinate parentGroupAbsoluteCoord); + void parseShapeGroup(librevenge::RVNGInputStream *input, const EscherContainerInfo &spgr, Coordinate parentCoordinateSystem, Coordinate parentGroupAbsoluteCoord, unsigned depth = 0); void skipBlock(librevenge::RVNGInputStream *input, MSPUBBlockInfo block); void parseEscherShape(librevenge::RVNGInputStream *input, const EscherContainerInfo &sp, Coordinate &parentCoordinateSystem, Coordinate &parentGroupAbsoluteCoord); bool findEscherContainer(librevenge::RVNGInputStream *input, const EscherContainerInfo &parent, EscherContainerInfo &out, unsigned short type);
