diff --git a/CHANGELOG.md b/CHANGELOG.md index d3a744bcb..9a2403786 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,11 @@ The release run heads these entries with the version and opens a fresh instead of in the running text. - A text document is laid out on the master page it names, so a letter template keeps the margins that leave room for its letterhead. +- A docx or odt that chains its styles deeply opens instead of taking the + process down with it: the `w:basedOn` / `style:parent-style-name` chain is + walked onto a stack rather than recursed, so its length costs no stack. +- A document's xml parts are read once instead of buffered twice on the way into + the parser, which lowers the memory opening a large one takes. ## v6.5.0 - 2026-08-10 diff --git a/src/odr/internal/odf/odf_style.cpp b/src/odr/internal/odf/odf_style.cpp index c5a0370b0..1e77108ec 100644 --- a/src/odr/internal/odf/odf_style.cpp +++ b/src/odr/internal/odf/odf_style.cpp @@ -5,8 +5,10 @@ #include #include +#include #include #include +#include namespace odr::internal::odf { @@ -603,34 +605,54 @@ Style *StyleRegistry::generate_default_style_(const std::string &name, return style.get(); } +/// Walks the `style:parent-style-name` chain onto a stack and builds it from +/// the root down; recursing it costs a stack frame per link. Style *StyleRegistry::generate_style_(const std::string &name, const pugi::xml_node node) { - // a null entry means the style is still resolving, i.e. the parent chain is - // cyclic; break it rather than recurse forever - const auto [style_it, inserted] = m_styles.try_emplace(name); - std::unique_ptr