From 86208ebbad72a6e4aa265f5a80fbdb0d5db285e3 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 29 Dec 2025 00:27:53 +0100 Subject: [PATCH 1/8] element capabilities and cleanup --- CMakeLists.txt | 1 + src/odr/document_element.cpp | 21 +++ src/odr/document_element.hpp | 7 +- src/odr/document_path.cpp | 125 +-------------- src/odr/document_path.hpp | 18 +-- src/odr/html.cpp | 22 +-- .../internal/abstract/document_element.hpp | 14 +- src/odr/internal/html/document_element.cpp | 3 +- src/odr/internal/odf/odf_document.cpp | 31 +++- .../ooxml_presentation_document.cpp | 31 ++-- .../ooxml_presentation_element_registry.hpp | 1 - .../ooxml_spreadsheet_document.cpp | 29 +++- .../ooxml_spreadsheet_element_registry.hpp | 1 - .../ooxml/text/ooxml_text_document.cpp | 34 ++-- .../text/ooxml_text_element_registry.hpp | 1 - src/odr/internal/pdf/pdf_cmap_parser.cpp | 4 +- src/odr/internal/util/byte_util.cpp | 12 +- src/odr/internal/util/byte_util.hpp | 4 +- test/src/document_test.cpp | 146 +++++++++--------- 19 files changed, 239 insertions(+), 266 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3487da85..5479fe40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,6 +178,7 @@ set(ODR_SOURCE_FILES "src/odr/internal/text/text_util.cpp" "src/odr/internal/util/byte_util.cpp" + "src/odr/internal/util/document_util.cpp" "src/odr/internal/util/file_util.cpp" "src/odr/internal/util/hash_util.cpp" "src/odr/internal/util/odr_meta_util.cpp" diff --git a/src/odr/document_element.cpp b/src/odr/document_element.cpp index 7bf3415d..92502d2d 100644 --- a/src/odr/document_element.cpp +++ b/src/odr/document_element.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -48,10 +49,30 @@ Element Element::next_sibling() const { : Element(); } +bool Element::is_unique() const { + return exists_() ? m_adapter->element_is_unique(m_identifier) : false; +} + +bool Element::is_self_locatable() const { + return exists_() ? m_adapter->element_is_self_locatable(m_identifier) : false; +} + bool Element::is_editable() const { return exists_() ? m_adapter->element_is_editable(m_identifier) : false; } +DocumentPath Element::document_path() const { + return exists_() ? m_adapter->element_document_path(m_identifier) + : DocumentPath(); +} + +Element Element::navigate_path(const DocumentPath &path) const { + return exists_() + ? Element(m_adapter, + m_adapter->element_navigate_path(m_identifier, path)) + : Element(); +} + TextRoot Element::as_text_root() const { return {m_adapter, m_identifier, m_adapter->text_root_adapter(m_identifier)}; } diff --git a/src/odr/document_element.hpp b/src/odr/document_element.hpp index e5a915eb..dcb44867 100644 --- a/src/odr/document_element.hpp +++ b/src/odr/document_element.hpp @@ -9,6 +9,7 @@ namespace odr { class TablePosition; struct TableDimensions; +class DocumentPath; class File; struct TextStyle; struct ParagraphStyle; @@ -153,7 +154,11 @@ class Element { [[nodiscard]] Element previous_sibling() const; [[nodiscard]] Element next_sibling() const; + [[nodiscard]] bool is_unique() const; + [[nodiscard]] bool is_self_locatable() const; [[nodiscard]] bool is_editable() const; + [[nodiscard]] DocumentPath document_path() const; + [[nodiscard]] Element navigate_path(const DocumentPath &path) const; [[nodiscard]] ElementRange children() const; @@ -183,7 +188,7 @@ class Element { protected: const internal::abstract::ElementAdapter *m_adapter{nullptr}; - ElementIdentifier m_identifier; + ElementIdentifier m_identifier{null_element_id}; friend bool operator==(const Element &lhs, const Element &rhs) { return lhs.m_identifier == rhs.m_identifier; diff --git a/src/odr/document_path.cpp b/src/odr/document_path.cpp index 7f109f4f..d779681c 100644 --- a/src/odr/document_path.cpp +++ b/src/odr/document_path.cpp @@ -1,8 +1,5 @@ #include -#include - -#include #include namespace odr { @@ -12,45 +9,10 @@ const std::string &DocumentPath::Child::prefix_string() { return result; } -std::pair -DocumentPath::Child::extract(const Element element) { - if (!element) { - throw std::invalid_argument("element is null"); - } - const Element parent = element.parent(); - if (!parent) { - throw std::invalid_argument("parent not found"); - } - - Element current = element; - std::uint32_t distance = 0; - for (; current.previous_sibling(); current = current.previous_sibling()) { - ++distance; - } - - return {parent, Child(distance)}; -} - -Element DocumentPath::Child::resolve(const Element element, - const Child &child) { - if (!element) { - throw std::invalid_argument("element is null"); - } - if (!element.first_child()) { - throw std::invalid_argument("child not found"); - } - Element result = element.first_child(); - for (std::uint32_t i = 0; i < child.m_number; ++i) { - if (!result.next_sibling()) { - throw std::invalid_argument("sibling not found"); - } - result = result.next_sibling(); - } - return result; -} - DocumentPath::Child::Child(const std::uint32_t number) : m_number{number} {} +std::uint32_t DocumentPath::Child::number() const { return m_number; } + bool DocumentPath::Child::operator==(const Child &other) const noexcept { return m_number == other.m_number; } @@ -64,37 +26,11 @@ const std::string &DocumentPath::Cell::prefix_string() { return result; } -std::pair -DocumentPath::Cell::extract(const SheetCell &element) { - if (!element) { - throw std::invalid_argument("element is null"); - } - const Element parent = element.parent(); - if (!parent) { - throw std::invalid_argument("parent not found"); - } - const Sheet sheet = parent.as_sheet(); - if (!sheet) { - throw std::invalid_argument("parent is not a sheet"); - } - const SheetCell cell = element.as_sheet_cell(); - if (!cell) { - throw std::invalid_argument("element is not a sheet cell"); - } - return {sheet, Cell(cell.position())}; -} - -SheetCell DocumentPath::Cell::resolve(const Sheet &element, const Cell &cell) { - if (!element) { - throw std::invalid_argument("element is null"); - } - return element.as_sheet().cell(cell.m_position.column(), - cell.m_position.row()); -} - DocumentPath::Cell::Cell(const TablePosition &position) : m_position{position} {} +TablePosition DocumentPath::Cell::position() const { return m_position; } + bool DocumentPath::Cell::operator==(const Cell &other) const noexcept { return m_position == other.m_position; } @@ -124,57 +60,6 @@ DocumentPath::component_from_string(const std::string &string) { throw std::invalid_argument("string"); } -DocumentPath DocumentPath::extract(const Element element) { - return extract(element, {}); -} - -DocumentPath DocumentPath::extract(const Element element, const Element root) { - std::vector reverse; - - for (Element current = element; current != root;) { - if (!current.parent()) { - break; - } - - if (const SheetCell sheet_cell = current.as_sheet_cell(); sheet_cell) { - const auto [parent, cell] = Cell::extract(sheet_cell); - reverse.emplace_back(cell); - current = static_cast(parent); - } else { - const auto [parent, child] = Child::extract(current); - reverse.emplace_back(child); - current = parent; - } - } - - std::ranges::reverse(reverse); - return DocumentPath(reverse); -} - -Element DocumentPath::resolve(const Element root, const DocumentPath &path) { - Element element = root; - - for (const Component &c : path) { - if (const auto *child = std::get_if(&c); child != nullptr) { - element = Child::resolve(element, *child); - } else if (const auto *cell = std::get_if(&c); cell != nullptr) { - const Sheet sheet = element.as_sheet(); - if (!sheet) { - throw std::invalid_argument("element is not a sheet"); - } - const SheetCell sheet_cell = Cell::resolve(sheet, *cell); - element = static_cast(sheet_cell); - } else { - throw std::invalid_argument("unknown component"); - } - if (!element) { - throw std::invalid_argument("element not found"); - } - } - - return element; -} - DocumentPath::DocumentPath() noexcept = default; DocumentPath::DocumentPath(const Container &components) @@ -228,7 +113,7 @@ std::string DocumentPath::to_string() const noexcept { bool DocumentPath::empty() const noexcept { return m_components.empty(); } -DocumentPath::Component DocumentPath::back() const { +const DocumentPath::Component &DocumentPath::back() const { return m_components.back(); } diff --git a/src/odr/document_path.hpp b/src/odr/document_path.hpp index 3cb33284..6b90fe4a 100644 --- a/src/odr/document_path.hpp +++ b/src/odr/document_path.hpp @@ -4,15 +4,10 @@ #include #include -#include #include #include namespace odr { -class Document; -class Element; -class Sheet; -class SheetCell; /// @brief A path to a specific element in a document. class DocumentPath final { @@ -22,11 +17,11 @@ class DocumentPath final { static constexpr std::string_view prefix = "child"; static const std::string &prefix_string(); - static std::pair extract(Element element); - static Element resolve(Element element, const Child &child); explicit Child(std::uint32_t number); + [[nodiscard]] std::uint32_t number() const; + bool operator==(const Child &other) const noexcept; [[nodiscard]] std::string to_string() const noexcept; @@ -39,11 +34,11 @@ class DocumentPath final { static constexpr std::string_view prefix = "cell"; static const std::string &prefix_string(); - static std::pair extract(const SheetCell &element); - static SheetCell resolve(const Sheet &element, const Cell &cell); explicit Cell(const TablePosition &position); + [[nodiscard]] TablePosition position() const; + bool operator==(const Cell &other) const noexcept; [[nodiscard]] std::string to_string() const noexcept; @@ -56,9 +51,6 @@ class DocumentPath final { using const_iterator = Container::const_iterator; static Component component_from_string(const std::string &string); - static DocumentPath extract(Element element); - static DocumentPath extract(Element element, Element root); - static Element resolve(Element root, const DocumentPath &path); DocumentPath() noexcept; explicit DocumentPath(const Container &components); @@ -73,7 +65,7 @@ class DocumentPath final { [[nodiscard]] bool empty() const noexcept; - [[nodiscard]] Component back() const; + [[nodiscard]] const Component &back() const; [[nodiscard]] DocumentPath parent() const; [[nodiscard]] DocumentPath join(const DocumentPath &other) const; diff --git a/src/odr/html.cpp b/src/odr/html.cpp index c01856d9..9b9bc942 100644 --- a/src/odr/html.cpp +++ b/src/odr/html.cpp @@ -40,7 +40,7 @@ void bring_offline(const HtmlResources &resources, resource.is_external() || !resource.is_accessible()) { continue; } - auto path = Path(output_path).join(RelPath(*location)); + const Path path = Path(output_path).join(RelPath(*location)); std::filesystem::create_directories(path.parent().path()); std::ofstream ostream = util::file::create(path.string()); @@ -113,8 +113,8 @@ Html HtmlService::bring_offline(const std::string &output_path, HtmlResources resources; - for (const auto &view : views) { - auto path = Path(output_path).join(RelPath(view.path())); + for (const HtmlView &view : views) { + const Path path = Path(output_path).join(RelPath(view.path())); std::filesystem::create_directories(path.parent().path()); std::ofstream ostream = util::file::create(path.string()); @@ -164,7 +164,7 @@ HtmlResources HtmlView::write_html(std::ostream &out) const { Html HtmlView::bring_offline(const std::string &output_path) const { HtmlResources resources; - const auto path = Path(output_path).join(RelPath(this->path())); + const Path path = Path(output_path).join(RelPath(this->path())); { std::filesystem::create_directories(path.parent().path()); @@ -248,7 +248,7 @@ HtmlResourceLocator html::standard_resource_locator() { } if (resource.is_shipped()) { - auto resource_path = + Path resource_path = Path(config.resource_path).join(RelPath(resource.path())); if (config.relative_resource_paths && config.output_path.has_value()) { resource_path = resource_path.rebase(Path(*config.output_path)); @@ -294,7 +294,7 @@ HtmlService html::translate(const DocumentFile &document_file, document_file.impl(); #ifdef ODR_WITH_WVWARE - if (const auto wv_document_file = + if (const std::shared_ptr wv_document_file = std::dynamic_pointer_cast( document_file_impl)) { std::filesystem::create_directories(cache_path); @@ -314,7 +314,7 @@ HtmlService html::translate(const PdfFile &pdf_file, const std::shared_ptr pdf_file_impl = pdf_file.impl(); #ifdef ODR_WITH_PDF2HTMLEX - if (const auto poppler_pdf_file = + if (const std::shared_ptr poppler_pdf_file = std::dynamic_pointer_cast(pdf_file_impl)) { std::filesystem::create_directories(cache_path); return internal::html::create_poppler_pdf_service( @@ -354,10 +354,10 @@ HtmlService html::translate(const Document &document, void html::edit(const Document &document, const char *diff, Logger & /*logger*/) { - for (auto json = nlohmann::json::parse(diff); - const auto &[key, value] : json["modifiedText"].items()) { - auto element = - DocumentPath::resolve(document.root_element(), DocumentPath(key)); + const nlohmann::json json = nlohmann::json::parse(diff); + for (const auto &[key, value] : json["modifiedText"].items()) { + const Element element = + document.root_element().navigate_path(DocumentPath(key)); if (!element) { throw std::invalid_argument("element with path " + key + " not found"); } diff --git a/src/odr/internal/abstract/document_element.hpp b/src/odr/internal/abstract/document_element.hpp index f93c821f..9fc6040c 100644 --- a/src/odr/internal/abstract/document_element.hpp +++ b/src/odr/internal/abstract/document_element.hpp @@ -9,6 +9,7 @@ namespace odr { enum class ElementType; class File; +class DocumentPath; } // namespace odr namespace odr::internal::abstract { @@ -56,12 +57,17 @@ class ElementAdapter { [[nodiscard]] virtual ElementIdentifier element_next_sibling(ElementIdentifier element_id) const = 0; - // TODO element_is_unique - // TODO element_is_self_locatable + [[nodiscard]] virtual bool + element_is_unique(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual bool + element_is_self_locatable(ElementIdentifier element_id) const = 0; [[nodiscard]] virtual bool element_is_editable(ElementIdentifier element_id) const = 0; - // TODO element_path_from_parent - // TODO element_path_from_document + [[nodiscard]] virtual DocumentPath + element_document_path(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ElementIdentifier + element_navigate_path(ElementIdentifier element_id, + const DocumentPath &path) const = 0; // TODO push to document [[nodiscard]] virtual const TextRootAdapter * diff --git a/src/odr/internal/html/document_element.cpp b/src/odr/internal/html/document_element.cpp index 04aa0754..75519a2f 100644 --- a/src/odr/internal/html/document_element.cpp +++ b/src/odr/internal/html/document_element.cpp @@ -240,8 +240,7 @@ void html::translate_text(const Element &element, const WritingState &state) { .set_attributes([&](const HtmlAttributeWriterCallback &clb) { if (state.config().editable && element.is_editable()) { clb("contenteditable", "true"); - clb("data-odr-path", - DocumentPath::extract(element).to_string()); + clb("data-odr-path", element.document_path().to_string()); } }) .set_style(translate_text_style(text.style()))); diff --git a/src/odr/internal/odf/odf_document.cpp b/src/odr/internal/odf/odf_document.cpp index e79254eb..240854a0 100644 --- a/src/odr/internal/odf/odf_document.cpp +++ b/src/odr/internal/odf/odf_document.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -9,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -18,8 +20,6 @@ #include #include -#include - namespace odr::internal::odf { namespace { @@ -212,6 +212,14 @@ class ElementAdapter final : public abstract::ElementAdapter, return null_element_id; } + [[nodiscard]] bool + element_is_unique(const ElementIdentifier element_id) const override { + return true; + } + [[nodiscard]] bool + element_is_self_locatable(const ElementIdentifier element_id) const override { + return true; + } [[nodiscard]] bool element_is_editable(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = @@ -229,6 +237,16 @@ class ElementAdapter final : public abstract::ElementAdapter, } return false; } + [[nodiscard]] + DocumentPath + element_document_path(const ElementIdentifier element_id) const override { + return util::document::extract_path(*this, element_id, null_element_id); + } + [[nodiscard]] ElementIdentifier + element_navigate_path(const ElementIdentifier element_id, + const DocumentPath &path) const override { + return util::document::navigate_path(*this, element_id, path); + } [[nodiscard]] const TextRootAdapter * text_root_adapter(const ElementIdentifier element_id) const override { @@ -1059,7 +1077,7 @@ class ElementAdapter final : public abstract::ElementAdapter, } return false; } - [[nodiscard]] std::optional + [[nodiscard]] std::optional image_file(const ElementIdentifier element_id) const override { if (m_document->as_filesystem() == nullptr) { return std::nullopt; @@ -1142,9 +1160,10 @@ class ElementAdapter final : public abstract::ElementAdapter, return base; } - ResolvedStyle get_partial_cell_style(const ElementIdentifier sheet_id, - const ElementIdentifier cell_id, - const TablePosition &position) const { + [[nodiscard]] ResolvedStyle + get_partial_cell_style(const ElementIdentifier sheet_id, + const ElementIdentifier cell_id, + const TablePosition &position) const { const char *style_name = nullptr; if (const pugi::xml_attribute attr = diff --git a/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp b/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp index 8d98f1a2..4ed8fb15 100644 --- a/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp +++ b/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -11,10 +12,9 @@ #include #include #include +#include #include -#include - namespace odr::internal::ooxml::presentation { namespace { @@ -201,14 +201,27 @@ class ElementAdapter final : public abstract::ElementAdapter, return null_element_id; } + [[nodiscard]] bool + element_is_unique(const ElementIdentifier element_id) const override { + return true; + } + [[nodiscard]] bool + element_is_self_locatable(const ElementIdentifier element_id) const override { + return true; + } [[nodiscard]] bool element_is_editable(const ElementIdentifier element_id) const override { - if (const ElementRegistry::Element *element = - m_registry->element(element_id); - element != nullptr) { - return element->is_editable; - } - return false; + return true; + } + [[nodiscard]] + DocumentPath + element_document_path(const ElementIdentifier element_id) const override { + return util::document::extract_path(*this, element_id, null_element_id); + } + [[nodiscard]] ElementIdentifier + element_navigate_path(const ElementIdentifier element_id, + const DocumentPath &path) const override { + return util::document::navigate_path(*this, element_id, path); } [[nodiscard]] const abstract::TextRootAdapter * @@ -664,7 +677,7 @@ class ElementAdapter final : public abstract::ElementAdapter, } return false; } - [[nodiscard]] std::optional + [[nodiscard]] std::optional image_file(const ElementIdentifier element_id) const override { if (m_document->as_filesystem() == nullptr) { return std::nullopt; diff --git a/src/odr/internal/ooxml/presentation/ooxml_presentation_element_registry.hpp b/src/odr/internal/ooxml/presentation/ooxml_presentation_element_registry.hpp index 81cb8239..60a8ada0 100644 --- a/src/odr/internal/ooxml/presentation/ooxml_presentation_element_registry.hpp +++ b/src/odr/internal/ooxml/presentation/ooxml_presentation_element_registry.hpp @@ -21,7 +21,6 @@ class ElementRegistry final { ElementIdentifier next_sibling_id{null_element_id}; ElementType type{ElementType::none}; pugi::xml_node node; - bool is_editable{false}; }; struct Table final { diff --git a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp index 3ccea132..cfdd1ff9 100644 --- a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp +++ b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -7,6 +8,7 @@ #include #include #include +#include #include #include @@ -166,14 +168,27 @@ class ElementAdapter final : public abstract::ElementAdapter, return null_element_id; } + [[nodiscard]] bool + element_is_unique(const ElementIdentifier element_id) const override { + return true; + } + [[nodiscard]] bool + element_is_self_locatable(const ElementIdentifier element_id) const override { + return true; + } [[nodiscard]] bool element_is_editable(const ElementIdentifier element_id) const override { - if (const ElementRegistry::Element *element = - m_registry->element(element_id); - element != nullptr) { - return element->is_editable; - } - return false; + return true; + } + [[nodiscard]] + DocumentPath + element_document_path(const ElementIdentifier element_id) const override { + return util::document::extract_path(*this, element_id, null_element_id); + } + [[nodiscard]] ElementIdentifier + element_navigate_path(const ElementIdentifier element_id, + const DocumentPath &path) const override { + return util::document::navigate_path(*this, element_id, path); } [[nodiscard]] const abstract::TextRootAdapter * @@ -567,7 +582,7 @@ class ElementAdapter final : public abstract::ElementAdapter, } return false; } - [[nodiscard]] std::optional + [[nodiscard]] std::optional image_file(const ElementIdentifier element_id) const override { if (m_document->as_filesystem() == nullptr) { return std::nullopt; diff --git a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_element_registry.hpp b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_element_registry.hpp index 629449c3..f25f3dbd 100644 --- a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_element_registry.hpp +++ b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_element_registry.hpp @@ -27,7 +27,6 @@ class ElementRegistry final { ElementIdentifier next_sibling_id{null_element_id}; ElementType type{ElementType::none}; pugi::xml_node node; - bool is_editable{false}; }; struct ElementRelations final { diff --git a/src/odr/internal/ooxml/text/ooxml_text_document.cpp b/src/odr/internal/ooxml/text/ooxml_text_document.cpp index 1f112ab2..e4e0d2cc 100644 --- a/src/odr/internal/ooxml/text/ooxml_text_document.cpp +++ b/src/odr/internal/ooxml/text/ooxml_text_document.cpp @@ -1,5 +1,6 @@ #include +#include #include #include @@ -9,8 +10,8 @@ #include #include #include +#include #include -#include #include #include @@ -176,14 +177,27 @@ class ElementAdapter final : public abstract::ElementAdapter, return null_element_id; } + [[nodiscard]] bool + element_is_unique(const ElementIdentifier element_id) const override { + return true; + } + [[nodiscard]] bool + element_is_self_locatable(const ElementIdentifier element_id) const override { + return true; + } [[nodiscard]] bool element_is_editable(const ElementIdentifier element_id) const override { - if (const ElementRegistry::Element *element = - m_registry->element(element_id); - element != nullptr) { - return element->is_editable; - } - return false; + return true; + } + [[nodiscard]] + DocumentPath + element_document_path(const ElementIdentifier element_id) const override { + return util::document::extract_path(*this, element_id, null_element_id); + } + [[nodiscard]] ElementIdentifier + element_navigate_path(const ElementIdentifier element_id, + const DocumentPath &path) const override { + return util::document::navigate_path(*this, element_id, path); } [[nodiscard]] const TextRootAdapter * @@ -579,8 +593,8 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] AnchorType frame_anchor_type(const ElementIdentifier element_id) const override { - const pugi::xml_node node = get_node(element_id); - if (node.child("wp:inline")) { + if (const pugi::xml_node node = get_node(element_id); + node.child("wp:inline")) { return AnchorType::as_char; } return AnchorType::as_char; // TODO default? @@ -636,7 +650,7 @@ class ElementAdapter final : public abstract::ElementAdapter, } return false; } - [[nodiscard]] std::optional + [[nodiscard]] std::optional image_file(const ElementIdentifier element_id) const override { if (m_document->as_filesystem() == nullptr) { return std::nullopt; diff --git a/src/odr/internal/ooxml/text/ooxml_text_element_registry.hpp b/src/odr/internal/ooxml/text/ooxml_text_element_registry.hpp index 2fb7f334..d4115b30 100644 --- a/src/odr/internal/ooxml/text/ooxml_text_element_registry.hpp +++ b/src/odr/internal/ooxml/text/ooxml_text_element_registry.hpp @@ -21,7 +21,6 @@ class ElementRegistry final { ElementIdentifier next_sibling_id{null_element_id}; ElementType type{ElementType::none}; pugi::xml_node node; - bool is_editable{false}; }; struct Table final { diff --git a/src/odr/internal/pdf/pdf_cmap_parser.cpp b/src/odr/internal/pdf/pdf_cmap_parser.cpp index da2582a9..f6a2779f 100644 --- a/src/odr/internal/pdf/pdf_cmap_parser.cpp +++ b/src/odr/internal/pdf/pdf_cmap_parser.cpp @@ -73,8 +73,8 @@ void CMapParser::read_bfchar(const std::uint32_t n, CMap &cmap) const { std::string unicode = m_parser.read_object().as_string(); m_parser.skip_whitespace(); - util::reverse_bytes(reinterpret_cast(unicode.data()), - unicode.size() / 2); + util::byte::reverse_bytes(reinterpret_cast(unicode.data()), + unicode.size() / 2); std::u16string_view unicode16( reinterpret_cast(unicode.data()), unicode.size() / 2); diff --git a/src/odr/internal/util/byte_util.cpp b/src/odr/internal/util/byte_util.cpp index e97406bc..388d42c7 100644 --- a/src/odr/internal/util/byte_util.cpp +++ b/src/odr/internal/util/byte_util.cpp @@ -1,29 +1,29 @@ #include -namespace odr::internal { +namespace odr::internal::util { -void util::reverse_bytes(char16_t *string, const std::size_t length) { +void byte::reverse_bytes(char16_t *string, const std::size_t length) { for (std::size_t i = 0; i < length; ++i) { reverse_bytes(string[i]); } } -void util::reverse_bytes(char32_t *string, const std::size_t length) { +void byte::reverse_bytes(char32_t *string, const std::size_t length) { for (std::size_t i = 0; i < length; ++i) { reverse_bytes(string[i]); } } -void util::reverse_bytes(std::u16string &string) { +void byte::reverse_bytes(std::u16string &string) { for (char16_t &c : string) { reverse_bytes(c); } } -void util::reverse_bytes(std::u32string &string) { +void byte::reverse_bytes(std::u32string &string) { for (char32_t &c : string) { reverse_bytes(c); } } -} // namespace odr::internal +} // namespace odr::internal::util diff --git a/src/odr/internal/util/byte_util.hpp b/src/odr/internal/util/byte_util.hpp index 4d046efa..85299cb7 100644 --- a/src/odr/internal/util/byte_util.hpp +++ b/src/odr/internal/util/byte_util.hpp @@ -3,7 +3,7 @@ #include #include -namespace odr::internal::util { +namespace odr::internal::util::byte { template void reverse_bytes(T &x) { for (char *a = reinterpret_cast(std::addressof(x)), @@ -18,4 +18,4 @@ void reverse_bytes(char32_t *string, std::size_t length); void reverse_bytes(std::u16string &string); void reverse_bytes(std::u32string &string); -} // namespace odr::internal::util +} // namespace odr::internal::util::byte diff --git a/test/src/document_test.cpp b/test/src/document_test.cpp index f9dffc36..9d301170 100644 --- a/test/src/document_test.cpp +++ b/test/src/document_test.cpp @@ -14,7 +14,8 @@ using namespace odr; using namespace odr::test; TEST(Document, odt) { - const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); + const std::unique_ptr logger = + Logger::create_stdio("odr-test", LogLevel::verbose); const DocumentFile document_file( TestData::test_file_path("odr-public/odt/about.odt"), *logger); @@ -25,7 +26,8 @@ TEST(Document, odt) { EXPECT_EQ(document.document_type(), DocumentType::text); - const auto page_layout = document.root_element().as_text_root().page_layout(); + const PageLayout page_layout = + document.root_element().as_text_root().page_layout(); EXPECT_TRUE(page_layout.width.has_value()); EXPECT_EQ(Measure("8.2673in"), page_layout.width); EXPECT_TRUE(page_layout.height.has_value()); @@ -35,7 +37,8 @@ TEST(Document, odt) { } TEST(Document, odt_element_path) { - const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); + const std::unique_ptr logger = + Logger::create_stdio("odr-test", LogLevel::verbose); const DocumentFile document_file( TestData::test_file_path("odr-public/odt/about.odt"), *logger); @@ -46,20 +49,20 @@ TEST(Document, odt_element_path) { EXPECT_EQ(document.document_type(), DocumentType::text); - const auto root = document.root_element(); - const auto p1 = root.first_child(); + const Element root = document.root_element(); + const Element p1 = root.first_child(); EXPECT_EQ(p1.type(), ElementType::paragraph); - const auto t1 = p1.first_child(); + const Element t1 = p1.first_child(); EXPECT_EQ(t1.type(), ElementType::text); - const DocumentPath t1_path = DocumentPath::extract(t1, root); - EXPECT_EQ(t1_path.to_string(), "/child:0/child:0"); - const Element t1_via_path = DocumentPath::resolve(root, t1_path); + const DocumentPath t1_path = t1.document_path(); + const Element t1_via_path = root.navigate_path(t1_path); EXPECT_EQ(t1_via_path, t1); } TEST(Document, odt_element_path2) { - const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); + const std::unique_ptr logger = + Logger::create_stdio("odr-test", LogLevel::verbose); const DocumentFile document_file( TestData::test_file_path("odr-public/odt/style-various-1.odt"), *logger); @@ -70,28 +73,29 @@ TEST(Document, odt_element_path2) { EXPECT_EQ(document.document_type(), DocumentType::text); - const auto root = document.root_element(); + const Element root = document.root_element(); - const Element cell_via_path = DocumentPath::resolve( - root, DocumentPath("/child:41/child:0/child:1/child:0/child:0")); + const Element cell_via_path = root.navigate_path( + DocumentPath("/child:41/child:0/child:1/child:0/child:0")); EXPECT_EQ(cell_via_path.type(), ElementType::text); EXPECT_EQ(cell_via_path.as_text().content(), "B1"); } TEST(Document, odg) { - auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); + const std::unique_ptr logger = + Logger::create_stdio("odr-test", LogLevel::verbose); - DocumentFile document_file( + const DocumentFile document_file( TestData::test_file_path("odr-public/odg/sample.odg"), *logger); EXPECT_EQ(document_file.file_type(), FileType::opendocument_graphics); - Document document = document_file.document(); + const Document document = document_file.document(); EXPECT_EQ(document.document_type(), DocumentType::drawing); - for (auto child : document.root_element().children()) { - auto page_layout = child.as_page().page_layout(); + for (const Element child : document.root_element().children()) { + const PageLayout page_layout = child.as_page().page_layout(); EXPECT_TRUE(page_layout.width.has_value()); EXPECT_EQ(Measure("21cm"), page_layout.width); EXPECT_TRUE(page_layout.height.has_value()); @@ -102,7 +106,8 @@ TEST(Document, odg) { } TEST(Document, edit_odt) { - const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); + const std::unique_ptr logger = + Logger::create_stdio("odr-test", LogLevel::verbose); const DocumentFile document_file( TestData::test_file_path("odr-public/odt/about.odt"), *logger); @@ -113,7 +118,7 @@ TEST(Document, edit_odt) { edit(child); } // TODO make editing empty text possible - if (const auto text = element.as_text(); text && !text.content().empty()) { + if (const Text text = element.as_text(); text && !text.content().empty()) { text.set_content("hello world!"); } }; @@ -130,7 +135,7 @@ TEST(Document, edit_odt) { validate(child); } // TODO make editing empty text possible - if (const auto text = element.as_text(); text && !text.content().empty()) { + if (const Text text = element.as_text(); text && !text.content().empty()) { EXPECT_EQ("hello world!", text.content()); } }; @@ -138,7 +143,8 @@ TEST(Document, edit_odt) { } TEST(Document, edit_docx) { - const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); + const std::unique_ptr logger = + Logger::create_stdio("odr-test", LogLevel::verbose); const DocumentFile document_file( TestData::test_file_path("odr-public/docx/style-various-1.docx"), @@ -150,7 +156,7 @@ TEST(Document, edit_docx) { edit(child); } // TODO make editing empty text possible - if (const auto text = element.as_text(); text && !text.content().empty()) { + if (const Text text = element.as_text(); text && !text.content().empty()) { text.set_content("hello world!"); } }; @@ -167,7 +173,7 @@ TEST(Document, edit_docx) { validate(child); } // TODO make editing empty text possible - if (const auto text = element.as_text(); text && !text.content().empty()) { + if (const Text text = element.as_text(); text && !text.content().empty()) { EXPECT_EQ("hello world!", text.content()); } }; @@ -175,9 +181,10 @@ TEST(Document, edit_docx) { } TEST(Document, edit_odt_diff) { - const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); + const std::unique_ptr logger = + Logger::create_stdio("odr-test", LogLevel::verbose); - const auto diff = + const char *diff = R"({"modifiedText":{"/child:16/child:0":"Outasdfsdafdline","/child:24/child:0":"Colorasdfasdfasdfed Line","/child:6/child:0":"Text hello world!"}})"; const DocumentFile document_file( TestData::test_file_path("odr-public/odt/style-various-1.odt"), *logger); @@ -193,26 +200,27 @@ TEST(Document, edit_odt_diff) { const DocumentFile validate_file(output_path); const Document validate_document = validate_file.document(); EXPECT_EQ("Outasdfsdafdline", - DocumentPath::resolve(validate_document.root_element(), - DocumentPath("/child:16/child:0")) + validate_document.root_element() + .navigate_path(DocumentPath("/child:16/child:0")) .as_text() .content()); EXPECT_EQ("Colorasdfasdfasdfed Line", - DocumentPath::resolve(validate_document.root_element(), - DocumentPath("/child:24/child:0")) + validate_document.root_element() + .navigate_path(DocumentPath("/child:24/child:0")) .as_text() .content()); EXPECT_EQ("Text hello world!", - DocumentPath::resolve(validate_document.root_element(), - DocumentPath("/child:6/child:0")) + validate_document.root_element() + .navigate_path(DocumentPath("/child:6/child:0")) .as_text() .content()); } TEST(Document, edit_ods_diff) { - const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); + const std::unique_ptr logger = + Logger::create_stdio("odr-test", LogLevel::verbose); - const auto diff = + const char *diff = R"({"modifiedText":{"/child:0/cell:A1/child:0/child:0":"Page 1 hi","/child:1/cell:A1/child:0/child:0":"Page 2 hihi","/child:2/cell:A1/child:0/child:0":"Page 3 hihihi","/child:3/cell:A1/child:0/child:0":"Page 4 hihihihi","/child:4/cell:A1/child:0/child:0":"Page 5 hihihihihi"}})"; DocumentFile document_file( TestData::test_file_path("odr-public/ods/pages.ods"), *logger); @@ -228,40 +236,38 @@ TEST(Document, edit_ods_diff) { const DocumentFile validate_file(output_path); const Document validate_document = validate_file.document(); - EXPECT_EQ("Page 1 hi", DocumentPath::resolve( - validate_document.root_element(), - DocumentPath("/child:0/cell:A1/child:0/child:0")) - .as_text() - .content()); - EXPECT_EQ("Page 2 hihi", DocumentPath::resolve( - validate_document.root_element(), - DocumentPath("/child:1/cell:A1/child:0/child:0")) - .as_text() - .content()); - EXPECT_EQ( - "Page 3 hihihi", - DocumentPath::resolve(validate_document.root_element(), - DocumentPath("/child:2/cell:A1/child:0/child:0")) - .as_text() - .content()); - EXPECT_EQ( - "Page 4 hihihihi", - DocumentPath::resolve(validate_document.root_element(), - DocumentPath("/child:3/cell:A1/child:0/child:0")) - .as_text() - .content()); - EXPECT_EQ( - "Page 5 hihihihihi", - DocumentPath::resolve(validate_document.root_element(), - DocumentPath("/child:4/cell:A1/child:0/child:0")) - .as_text() - .content()); + EXPECT_EQ("Page 1 hi", + validate_document.root_element() + .navigate_path(DocumentPath("/child:0/cell:A1/child:0/child:0")) + .as_text() + .content()); + EXPECT_EQ("Page 2 hihi", + validate_document.root_element() + .navigate_path(DocumentPath("/child:1/cell:A1/child:0/child:0")) + .as_text() + .content()); + EXPECT_EQ("Page 3 hihihi", + validate_document.root_element() + .navigate_path(DocumentPath("/child:2/cell:A1/child:0/child:0")) + .as_text() + .content()); + EXPECT_EQ("Page 4 hihihihi", + validate_document.root_element() + .navigate_path(DocumentPath("/child:3/cell:A1/child:0/child:0")) + .as_text() + .content()); + EXPECT_EQ("Page 5 hihihihihi", + validate_document.root_element() + .navigate_path(DocumentPath("/child:4/cell:A1/child:0/child:0")) + .as_text() + .content()); } TEST(Document, edit_docx_diff) { - const auto logger = Logger::create_stdio("odr-test", LogLevel::verbose); + const std::unique_ptr logger = + Logger::create_stdio("odr-test", LogLevel::verbose); - const auto diff = + const auto *diff = R"({"modifiedText":{"/child:16/child:0/child:0":"Outasdfsdafdline","/child:24/child:0/child:0":"Colorasdfasdfasdfed Line","/child:6/child:0/child:0":"Text hello world!"}})"; const DocumentFile document_file( TestData::test_file_path("odr-public/docx/style-various-1.docx"), @@ -278,18 +284,18 @@ TEST(Document, edit_docx_diff) { const DocumentFile validate_file(output_path); const Document validate_document = validate_file.document(); EXPECT_EQ("Outasdfsdafdline", - DocumentPath::resolve(validate_document.root_element(), - DocumentPath("/child:16/child:0/child:0")) + validate_document.root_element() + .navigate_path(DocumentPath("/child:16/child:0/child:0")) .as_text() .content()); EXPECT_EQ("Colorasdfasdfasdfed Line", - DocumentPath::resolve(validate_document.root_element(), - DocumentPath("/child:24/child:0/child:0")) + validate_document.root_element() + .navigate_path(DocumentPath("/child:24/child:0/child:0")) .as_text() .content()); EXPECT_EQ("Text hello world!", - DocumentPath::resolve(validate_document.root_element(), - DocumentPath("/child:6/child:0/child:0")) + validate_document.root_element() + .navigate_path(DocumentPath("/child:6/child:0/child:0")) .as_text() .content()); } From 50cab2119a59bc94b65a06038f36667931b96241 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 29 Dec 2025 00:30:02 +0100 Subject: [PATCH 2/8] missing files --- src/odr/internal/util/document_util.cpp | 110 ++++++++++++++++++++++++ src/odr/internal/util/document_util.hpp | 23 +++++ 2 files changed, 133 insertions(+) create mode 100644 src/odr/internal/util/document_util.cpp create mode 100644 src/odr/internal/util/document_util.hpp diff --git a/src/odr/internal/util/document_util.cpp b/src/odr/internal/util/document_util.cpp new file mode 100644 index 00000000..555d3635 --- /dev/null +++ b/src/odr/internal/util/document_util.cpp @@ -0,0 +1,110 @@ +#include + +#include + +#include + +namespace odr::internal::util { + +namespace { + +DocumentPath::Component +extract_path_component(const abstract::ElementAdapter &element_adapter, + const ElementIdentifier element_id) { + if (element_adapter.element_type(element_id) == ElementType::sheet_cell) { + const abstract::SheetCellAdapter *sheet_cell_adapter = + element_adapter.sheet_cell_adapter(element_id); + if (sheet_cell_adapter == nullptr) { + throw std::invalid_argument("Sheet cell adapter not found."); + } + return DocumentPath::Cell( + sheet_cell_adapter->sheet_cell_position(element_id)); + } + + std::uint32_t distance = 0; + for (ElementIdentifier current_id = + element_adapter.element_previous_sibling(element_id); + current_id != null_element_id; + current_id = element_adapter.element_previous_sibling(current_id)) { + ++distance; + } + + return DocumentPath::Child(distance); +} + +ElementIdentifier +navigate_path_component(const abstract::ElementAdapter &element_adapter, + const ElementIdentifier element_id, + const DocumentPath::Component &component) { + if (const auto *child = std::get_if(&component); + child != nullptr) { + ElementIdentifier result_id = + element_adapter.element_first_child(element_id); + if (result_id == null_element_id) { + throw std::invalid_argument("child not found"); + } + for (std::uint32_t i = 0; i < child->number(); ++i) { + result_id = element_adapter.element_next_sibling(result_id); + if (result_id == null_element_id) { + throw std::invalid_argument("child not found"); + } + } + return result_id; + } + + if (const auto *cell = std::get_if(&component); + cell != nullptr) { + const abstract::SheetAdapter *sheet_adapter = + element_adapter.sheet_adapter(element_id); + if (sheet_adapter == nullptr) { + throw std::invalid_argument("sheet adapter not found"); + } + return sheet_adapter->sheet_cell(element_id, cell->position().column(), + cell->position().row()); + } + + throw std::invalid_argument("unknown document path component"); +} + +} // namespace + +DocumentPath +document::extract_path(const abstract::ElementAdapter &element_adapter, + const ElementIdentifier to_element_id, + const ElementIdentifier from_element_id) { + if (to_element_id == null_element_id) { + throw std::invalid_argument("Element identifier cannot be null."); + } + + std::vector reverse; + + for (ElementIdentifier current_id = to_element_id; + current_id != from_element_id; + current_id = element_adapter.element_parent(current_id)) { + if (current_id == null_element_id) { + throw std::invalid_argument( + "Element is not a descendant of the specified root."); + } + + const DocumentPath::Component component = + extract_path_component(element_adapter, current_id); + reverse.push_back(component); + } + + std::ranges::reverse(reverse); + return DocumentPath(std::move(reverse)); +} + +ElementIdentifier +document::navigate_path(const abstract::ElementAdapter &element_adapter, + const ElementIdentifier from_element_id, + const DocumentPath &path) { + ElementIdentifier current_id = from_element_id; + for (const DocumentPath::Component &component : path) { + current_id = + navigate_path_component(element_adapter, current_id, component); + } + return current_id; +} + +} // namespace odr::internal::util diff --git a/src/odr/internal/util/document_util.hpp b/src/odr/internal/util/document_util.hpp new file mode 100644 index 00000000..e4d6321b --- /dev/null +++ b/src/odr/internal/util/document_util.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace odr { +class DocumentPath; +} + +namespace odr::internal::abstract { +class ElementAdapter; +} + +namespace odr::internal::util::document { + +DocumentPath extract_path(const abstract::ElementAdapter &element_adapter, + ElementIdentifier to_element_id, + ElementIdentifier from_element_id); + +ElementIdentifier navigate_path(const abstract::ElementAdapter &element_adapter, + ElementIdentifier from_element_id, + const DocumentPath &path); + +} // namespace odr::internal::util::document From a704c9898836afdbd45c30e568458738b7caaaf3 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 29 Dec 2025 00:36:43 +0100 Subject: [PATCH 3/8] fix build --- src/odr/internal/odf/odf_document.cpp | 2 ++ .../ooxml/presentation/ooxml_presentation_document.cpp | 3 +++ .../internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp | 3 +++ src/odr/internal/ooxml/text/ooxml_text_document.cpp | 3 +++ 4 files changed, 11 insertions(+) diff --git a/src/odr/internal/odf/odf_document.cpp b/src/odr/internal/odf/odf_document.cpp index 240854a0..7e1f9061 100644 --- a/src/odr/internal/odf/odf_document.cpp +++ b/src/odr/internal/odf/odf_document.cpp @@ -214,10 +214,12 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] bool element_is_unique(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] bool element_is_self_locatable(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] bool diff --git a/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp b/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp index 4ed8fb15..3f4dd211 100644 --- a/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp +++ b/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp @@ -203,14 +203,17 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] bool element_is_unique(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] bool element_is_self_locatable(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] bool element_is_editable(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] diff --git a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp index cfdd1ff9..f395d89a 100644 --- a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp +++ b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp @@ -170,14 +170,17 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] bool element_is_unique(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] bool element_is_self_locatable(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] bool element_is_editable(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] diff --git a/src/odr/internal/ooxml/text/ooxml_text_document.cpp b/src/odr/internal/ooxml/text/ooxml_text_document.cpp index e4e0d2cc..59cc292d 100644 --- a/src/odr/internal/ooxml/text/ooxml_text_document.cpp +++ b/src/odr/internal/ooxml/text/ooxml_text_document.cpp @@ -179,14 +179,17 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] bool element_is_unique(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] bool element_is_self_locatable(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] bool element_is_editable(const ElementIdentifier element_id) const override { + (void)element_id; return true; } [[nodiscard]] From c58eb73c9c0ac32a7722def3540f7be44e3cd62c Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 29 Dec 2025 00:37:50 +0100 Subject: [PATCH 4/8] disable xlsx editing --- .../internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp index f395d89a..30f67cb8 100644 --- a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp +++ b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp @@ -181,7 +181,7 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] bool element_is_editable(const ElementIdentifier element_id) const override { (void)element_id; - return true; + return false; } [[nodiscard]] DocumentPath From 88079e11023511ea2fd0cf01726fd96e0f8dc472 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 29 Dec 2025 00:46:02 +0100 Subject: [PATCH 5/8] fix build --- src/odr/internal/util/document_util.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/odr/internal/util/document_util.cpp b/src/odr/internal/util/document_util.cpp index 555d3635..9141f0c9 100644 --- a/src/odr/internal/util/document_util.cpp +++ b/src/odr/internal/util/document_util.cpp @@ -4,6 +4,10 @@ #include +#include +#include +#include + namespace odr::internal::util { namespace { From b4711d468a18fdcca17bf9557b0c3f78694a8e04 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 29 Dec 2025 09:04:45 +0100 Subject: [PATCH 6/8] fix build --- src/odr/internal/util/document_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odr/internal/util/document_util.cpp b/src/odr/internal/util/document_util.cpp index 9141f0c9..b7d44a5a 100644 --- a/src/odr/internal/util/document_util.cpp +++ b/src/odr/internal/util/document_util.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include #include From 5ba52a8185fbdcecf4bdb4de9cb55bd41b18f0b6 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 29 Dec 2025 14:12:57 +0100 Subject: [PATCH 7/8] generalize document element interface --- src/odr/definitions.hpp | 27 ++ src/odr/document.cpp | 2 +- src/odr/document_element.cpp | 75 +-- src/odr/document_element.hpp | 10 +- src/odr/internal/abstract/document.hpp | 430 +++++++++++++++++- .../internal/abstract/document_element.hpp | 425 ----------------- src/odr/internal/common/document.cpp | 8 +- src/odr/internal/common/document.hpp | 12 +- src/odr/internal/odf/odf_document.cpp | 66 +-- .../ooxml_presentation_document.cpp | 48 +- .../ooxml_presentation_parser.cpp | 86 ++-- .../ooxml_presentation_parser.hpp | 21 +- .../ooxml_spreadsheet_document.cpp | 50 +- .../spreadsheet/ooxml_spreadsheet_parser.cpp | 32 +- .../spreadsheet/ooxml_spreadsheet_parser.hpp | 21 +- .../ooxml/text/ooxml_text_document.cpp | 43 +- src/odr/internal/util/document_util.cpp | 48 +- src/odr/internal/util/document_util.hpp | 6 +- 18 files changed, 724 insertions(+), 686 deletions(-) delete mode 100644 src/odr/internal/abstract/document_element.hpp diff --git a/src/odr/definitions.hpp b/src/odr/definitions.hpp index 3627eac3..74a1ccb3 100644 --- a/src/odr/definitions.hpp +++ b/src/odr/definitions.hpp @@ -2,10 +2,37 @@ #include +namespace odr::internal::abstract { +class ElementAdapter; +} // namespace odr::internal::abstract + namespace odr { using ElementIdentifier = std::uint64_t; static constexpr ElementIdentifier null_element_id{0}; +struct ElementHandle final { + const internal::abstract::ElementAdapter *adapter_ptr{nullptr}; + ElementIdentifier identifier{null_element_id}; + + ElementHandle() = default; + ElementHandle(const internal::abstract::ElementAdapter *adapter_ptr_, + const ElementIdentifier identifier_) + : adapter_ptr(adapter_ptr_), identifier(identifier_) {} + ElementHandle(const internal::abstract::ElementAdapter &adapter_, + const ElementIdentifier identifier_) + : adapter_ptr(&adapter_), identifier(identifier_) {} + + [[nodiscard]] const internal::abstract::ElementAdapter &adapter() const { + return *adapter_ptr; + } + + [[nodiscard]] bool is_null() const { return identifier == null_element_id; } + + bool operator==(const ElementHandle &other) const { + return adapter_ptr == other.adapter_ptr && identifier == other.identifier; + } +}; + } // namespace odr diff --git a/src/odr/document.cpp b/src/odr/document.cpp index 23b0b98a..60f6e1e0 100644 --- a/src/odr/document.cpp +++ b/src/odr/document.cpp @@ -39,7 +39,7 @@ DocumentType Document::document_type() const noexcept { } Element Document::root_element() const { - return {m_impl->element_adapter(), m_impl->root_element()}; + return Element(m_impl->root_element()); } Filesystem Document::as_filesystem() const { diff --git a/src/odr/document_element.cpp b/src/odr/document_element.cpp index 92502d2d..1a9b94a0 100644 --- a/src/odr/document_element.cpp +++ b/src/odr/document_element.cpp @@ -6,12 +6,15 @@ #include #include -#include +#include namespace odr { Element::Element() = default; +Element::Element(const ElementHandle &handle) + : m_adapter{handle.adapter_ptr}, m_identifier{handle.identifier} {} + Element::Element(const internal::abstract::ElementAdapter *adapter, const ElementIdentifier identifier) : m_adapter{adapter}, m_identifier{identifier} {} @@ -27,26 +30,23 @@ ElementType Element::type() const { } Element Element::parent() const { - return exists_() ? Element(m_adapter, m_adapter->element_parent(m_identifier)) + return exists_() ? Element(m_adapter->element_parent(m_identifier)) : Element(); } Element Element::first_child() const { - return exists_() - ? Element(m_adapter, m_adapter->element_first_child(m_identifier)) - : Element(); + return exists_() ? Element(m_adapter->element_first_child(m_identifier)) + : Element(); } Element Element::previous_sibling() const { - return exists_() ? Element(m_adapter, - m_adapter->element_previous_sibling(m_identifier)) + return exists_() ? Element(m_adapter->element_previous_sibling(m_identifier)) : Element(); } Element Element::next_sibling() const { - return exists_() - ? Element(m_adapter, m_adapter->element_next_sibling(m_identifier)) - : Element(); + return exists_() ? Element(m_adapter->element_next_sibling(m_identifier)) + : Element(); } bool Element::is_unique() const { @@ -68,8 +68,7 @@ DocumentPath Element::document_path() const { Element Element::navigate_path(const DocumentPath &path) const { return exists_() - ? Element(m_adapter, - m_adapter->element_navigate_path(m_identifier, path)) + ? Element(m_adapter->element_navigate_path(m_identifier, path)) : Element(); } @@ -169,35 +168,39 @@ Image Element::as_image() const { } ElementRange Element::children() const { - return {exists_() ? ElementIterator(m_adapter, m_adapter->element_first_child( - m_identifier)) - : ElementIterator(), + return {exists_() + ? ElementIterator(m_adapter->element_first_child(m_identifier)) + : ElementIterator(), ElementIterator()}; } ElementIterator::ElementIterator() = default; +ElementIterator::ElementIterator(const ElementHandle &handle) + : m_adapter{handle.adapter_ptr}, m_identifier{handle.identifier} {} + ElementIterator::ElementIterator( const internal::abstract::ElementAdapter *adapter, const ElementIdentifier identifier) : m_adapter{adapter}, m_identifier{identifier} {} -ElementIterator::reference ElementIterator::operator*() const { - return {m_adapter, m_identifier}; -} +Element ElementIterator::operator*() const { return {m_adapter, m_identifier}; } ElementIterator &ElementIterator::operator++() { if (exists_()) { - m_identifier = m_adapter->element_next_sibling(m_identifier); + const auto [next_adapter, next_id] = + m_adapter->element_next_sibling(m_identifier); + m_adapter = next_adapter; + m_identifier = next_id; } return *this; } -ElementIterator ElementIterator::operator++(int) { +ElementIterator ElementIterator::operator++(int) const { if (!exists_()) { return {}; } - return {m_adapter, m_adapter->element_next_sibling(m_identifier)}; + return ElementIterator(m_adapter->element_next_sibling(m_identifier)); } bool ElementIterator::exists_() const { @@ -225,9 +228,9 @@ MasterPage TextRoot::first_master_page() const { if (!exists_()) { return {}; } - const ElementIdentifier master_page_id = + const auto [master_page_adapter, master_page_id] = m_adapter2->text_root_first_master_page(m_identifier); - return {m_adapter, master_page_id, + return {master_page_adapter, master_page_id, m_adapter->master_page_adapter(master_page_id)}; } @@ -269,18 +272,18 @@ SheetCell Sheet::cell(const std::uint32_t column, if (!exists_()) { return {}; } - const ElementIdentifier cell_id = + const auto [cell_adapter, cell_id] = m_adapter2->sheet_cell(m_identifier, column, row); - return {m_adapter, cell_id, m_adapter->sheet_cell_adapter(cell_id)}; + return {cell_adapter, cell_id, m_adapter->sheet_cell_adapter(cell_id)}; } ElementRange Sheet::shapes() const { if (!exists_()) { return {}; } - const ElementIdentifier first_shape_id = + const auto [first_shape_adapter, first_shape_id] = m_adapter2->sheet_first_shape(m_identifier); - return ElementRange(ElementIterator(m_adapter, first_shape_id)); + return ElementRange(ElementIterator(first_shape_adapter, first_shape_id)); } TableStyle Sheet::style() const { @@ -394,29 +397,29 @@ TableRow Table::first_row() const { if (!exists_()) { return {}; } - const ElementIdentifier row_id = m_adapter2->table_first_row(m_identifier); - return {m_adapter, row_id, m_adapter->table_row_adapter(row_id)}; + const auto [row_adapter, row_id] = m_adapter2->table_first_row(m_identifier); + return {row_adapter, row_id, m_adapter->table_row_adapter(row_id)}; } TableColumn Table::first_column() const { if (!exists_()) { return {}; } - const ElementIdentifier column_id = + const auto [column_adapter, column_id] = m_adapter2->table_first_column(m_identifier); - return {m_adapter, column_id, m_adapter->table_column_adapter(column_id)}; + return {column_adapter, column_id, + m_adapter->table_column_adapter(column_id)}; } ElementRange Table::columns() const { - return exists_() - ? ElementRange(ElementIterator( - m_adapter, m_adapter2->table_first_column(m_identifier))) - : ElementRange(); + return exists_() ? ElementRange(ElementIterator( + m_adapter2->table_first_column(m_identifier))) + : ElementRange(); } ElementRange Table::rows() const { return exists_() ? ElementRange(ElementIterator( - m_adapter, m_adapter2->table_first_row(m_identifier))) + m_adapter2->table_first_row(m_identifier))) : ElementRange(); } diff --git a/src/odr/document_element.hpp b/src/odr/document_element.hpp index dcb44867..b0e0b9fd 100644 --- a/src/odr/document_element.hpp +++ b/src/odr/document_element.hpp @@ -142,6 +142,7 @@ enum class ValueType { class Element { public: Element(); + explicit Element(const ElementHandle &handle); Element(const internal::abstract::ElementAdapter *adapter, ElementIdentifier identifier); @@ -207,13 +208,14 @@ class ElementIterator { using iterator_category = std::forward_iterator_tag; ElementIterator(); + explicit ElementIterator(const ElementHandle &handle); ElementIterator(const internal::abstract::ElementAdapter *adapter, ElementIdentifier identifier); - reference operator*() const; + Element operator*() const; ElementIterator &operator++(); - ElementIterator operator++(int); + ElementIterator operator++(int) const; private: const internal::abstract::ElementAdapter *m_adapter{nullptr}; @@ -246,8 +248,10 @@ class ElementRange { template class ElementBase : public Element { public: ElementBase() = default; + ElementBase(const ElementHandle &handle, const T *adapter2) + : Element(handle), m_adapter2{adapter2} {} ElementBase(const internal::abstract::ElementAdapter *adapter, - const ElementIdentifier identifier, const T *adapter2) + ElementIdentifier identifier, const T *adapter2) : Element(adapter, identifier), m_adapter2{adapter2} {} explicit operator bool() const { return exists_(); } diff --git a/src/odr/internal/abstract/document.hpp b/src/odr/internal/abstract/document.hpp index 9e8ea669..9798f609 100644 --- a/src/odr/internal/abstract/document.hpp +++ b/src/odr/internal/abstract/document.hpp @@ -1,11 +1,26 @@ #pragma once #include +#include namespace odr { class File; enum class FileType; enum class DocumentType; +enum class ElementType; +class DocumentPath; +enum class ValueType; +enum class AnchorType; +struct PageLayout; +struct TableDimensions; +struct TablePosition; +struct TableStyle; +struct TableColumnStyle; +struct TableRowStyle; +struct TableCellStyle; +struct TextStyle; +struct ParagraphStyle; +struct GraphicStyle; } // namespace odr namespace odr::internal { @@ -14,7 +29,35 @@ class Path; namespace odr::internal::abstract { class ReadableFilesystem; +} + +namespace odr::internal::abstract { class ElementAdapter; +class TextRootAdapter; +class SlideAdapter; +class PageAdapter; +class SheetAdapter; +class SheetColumnAdapter; +class SheetRowAdapter; +class SheetCellAdapter; +class MasterPageAdapter; +class LineBreakAdapter; +class ParagraphAdapter; +class SpanAdapter; +class TextAdapter; +class LinkAdapter; +class BookmarkAdapter; +class ListItemAdapter; +class TableAdapter; +class TableColumnAdapter; +class TableRowAdapter; +class TableCellAdapter; +class FrameAdapter; +class RectAdapter; +class LineAdapter; +class CircleAdapter; +class CustomShapeAdapter; +class ImageAdapter; class Document { public: @@ -45,12 +88,389 @@ class Document { as_filesystem() const noexcept = 0; /// \return cursor to the root element of the document. - [[nodiscard]] virtual ElementIdentifier root_element() const = 0; + [[nodiscard]] virtual ElementHandle root_element() const = 0; +}; + +class ElementAdapter { +public: + virtual ~ElementAdapter() = default; + + [[nodiscard]] virtual ElementType + element_type(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual ElementHandle + element_parent(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ElementHandle + element_first_child(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ElementHandle + element_last_child(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ElementHandle + element_previous_sibling(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ElementHandle + element_next_sibling(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual bool + element_is_unique(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual bool + element_is_self_locatable(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual bool + element_is_editable(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual DocumentPath + element_document_path(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ElementHandle + element_navigate_path(ElementIdentifier element_id, + const DocumentPath &path) const = 0; + + [[nodiscard]] virtual const TextRootAdapter * + text_root_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const SlideAdapter * + slide_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const PageAdapter * + page_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const SheetAdapter * + sheet_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const SheetCellAdapter * + sheet_cell_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const MasterPageAdapter * + master_page_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const LineBreakAdapter * + line_break_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const ParagraphAdapter * + paragraph_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const SpanAdapter * + span_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const TextAdapter * + text_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const LinkAdapter * + link_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const BookmarkAdapter * + bookmark_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const ListItemAdapter * + list_item_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const TableAdapter * + table_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const TableColumnAdapter * + table_column_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const TableRowAdapter * + table_row_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const TableCellAdapter * + table_cell_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const FrameAdapter * + frame_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const RectAdapter * + rect_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const LineAdapter * + line_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const CircleAdapter * + circle_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const CustomShapeAdapter * + custom_shape_adapter(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const ImageAdapter * + image_adapter(ElementIdentifier element_id) const = 0; +}; + +class TextRootAdapter { +public: + virtual ~TextRootAdapter() = default; + + [[nodiscard]] virtual PageLayout + text_root_page_layout(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual ElementHandle + text_root_first_master_page(ElementIdentifier element_id) const = 0; +}; + +class SlideAdapter { +public: + virtual ~SlideAdapter() = default; + + [[nodiscard]] virtual PageLayout + slide_page_layout(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual ElementIdentifier + slide_master_page(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual std::string + slide_name(ElementIdentifier element_id) const = 0; +}; + +class PageAdapter { +public: + virtual ~PageAdapter() = default; + + [[nodiscard]] virtual PageLayout + page_layout(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual ElementIdentifier + page_master_page(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual std::string + page_name(ElementIdentifier element_id) const = 0; +}; + +class SheetAdapter { +public: + virtual ~SheetAdapter() = default; + + [[nodiscard]] virtual std::string + sheet_name(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual TableDimensions + sheet_dimensions(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual TableDimensions + sheet_content(ElementIdentifier element_id, + std::optional range) const = 0; + + [[nodiscard]] virtual ElementHandle sheet_cell(ElementIdentifier element_id, + std::uint32_t column, + std::uint32_t row) const = 0; + [[nodiscard]] virtual ElementHandle + sheet_first_shape(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual TableStyle + sheet_style(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual TableColumnStyle + sheet_column_style(ElementIdentifier element_id, + std::uint32_t column) const = 0; + [[nodiscard]] virtual TableRowStyle + sheet_row_style(ElementIdentifier element_id, std::uint32_t row) const = 0; + [[nodiscard]] virtual TableCellStyle + sheet_cell_style(ElementIdentifier element_id, std::uint32_t column, + std::uint32_t row) const = 0; +}; + +class SheetCellAdapter { +public: + virtual ~SheetCellAdapter() = default; + + [[nodiscard]] virtual TablePosition + sheet_cell_position(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual bool + sheet_cell_is_covered(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual TableDimensions + sheet_cell_span(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ValueType + sheet_cell_value_type(ElementIdentifier element_id) const = 0; +}; + +class MasterPageAdapter { +public: + virtual ~MasterPageAdapter() = default; + + [[nodiscard]] virtual PageLayout + master_page_page_layout(ElementIdentifier element_id) const = 0; +}; + +class LineBreakAdapter { +public: + virtual ~LineBreakAdapter() = default; + + [[nodiscard]] virtual TextStyle + line_break_style(ElementIdentifier element_id) const = 0; +}; + +class ParagraphAdapter { +public: + virtual ~ParagraphAdapter() = default; + + [[nodiscard]] virtual ParagraphStyle + paragraph_style(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual TextStyle + paragraph_text_style(ElementIdentifier element_id) const = 0; +}; + +class SpanAdapter { +public: + virtual ~SpanAdapter() = default; + + [[nodiscard]] virtual TextStyle + span_style(ElementIdentifier element_id) const = 0; +}; + +class TextAdapter { +public: + virtual ~TextAdapter() = default; + + [[nodiscard]] virtual std::string + text_content(ElementIdentifier element_id) const = 0; + virtual void text_set_content(ElementIdentifier element_id, + const std::string &text) const = 0; + + [[nodiscard]] virtual TextStyle + text_style(ElementIdentifier element_id) const = 0; +}; + +class LinkAdapter { +public: + virtual ~LinkAdapter() = default; + + [[nodiscard]] virtual std::string + link_href(ElementIdentifier element_id) const = 0; +}; + +class BookmarkAdapter { +public: + virtual ~BookmarkAdapter() = default; + + [[nodiscard]] virtual std::string + bookmark_name(ElementIdentifier element_id) const = 0; +}; + +class ListItemAdapter { +public: + virtual ~ListItemAdapter() = default; + + [[nodiscard]] virtual TextStyle + list_item_style(ElementIdentifier element_id) const = 0; +}; + +class TableAdapter { +public: + virtual ~TableAdapter() = default; + + [[nodiscard]] virtual TableDimensions + table_dimensions(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual ElementHandle + table_first_column(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ElementHandle + table_first_row(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual TableStyle + table_style(ElementIdentifier element_id) const = 0; +}; + +class TableColumnAdapter { +public: + virtual ~TableColumnAdapter() = default; + + [[nodiscard]] virtual TableColumnStyle + table_column_style(ElementIdentifier element_id) const = 0; +}; + +class TableRowAdapter { +public: + virtual ~TableRowAdapter() = default; + + [[nodiscard]] virtual TableRowStyle + table_row_style(ElementIdentifier element_id) const = 0; +}; + +class TableCellAdapter { +public: + virtual ~TableCellAdapter() = default; + + [[nodiscard]] virtual bool + table_cell_is_covered(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual TableDimensions + table_cell_span(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ValueType + table_cell_value_type(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual TableCellStyle + table_cell_style(ElementIdentifier element_id) const = 0; +}; + +class FrameAdapter { +public: + virtual ~FrameAdapter() = default; + + [[nodiscard]] virtual AnchorType + frame_anchor_type(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::optional + frame_x(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::optional + frame_y(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::optional + frame_width(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::optional + frame_height(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::optional + frame_z_index(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual GraphicStyle + frame_style(ElementIdentifier element_id) const = 0; +}; + +class RectAdapter { +public: + virtual ~RectAdapter() = default; + + [[nodiscard]] virtual std::string + rect_x(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + rect_y(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + rect_width(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + rect_height(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual GraphicStyle + rect_style(ElementIdentifier element_id) const = 0; +}; + +class LineAdapter { +public: + virtual ~LineAdapter() = default; + + [[nodiscard]] virtual std::string + line_x1(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + line_y1(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + line_x2(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + line_y2(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual GraphicStyle + line_style(ElementIdentifier element_id) const = 0; +}; + +class CircleAdapter { +public: + virtual ~CircleAdapter() = default; + + [[nodiscard]] virtual std::string + circle_x(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + circle_y(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + circle_width(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + circle_height(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual GraphicStyle + circle_style(ElementIdentifier element_id) const = 0; +}; + +class CustomShapeAdapter { +public: + virtual ~CustomShapeAdapter() = default; + + [[nodiscard]] virtual std::optional + custom_shape_x(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::optional + custom_shape_y(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + custom_shape_width(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + custom_shape_height(ElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual GraphicStyle + custom_shape_style(ElementIdentifier element_id) const = 0; +}; + +class ImageAdapter { +public: + virtual ~ImageAdapter() = default; - // TODO element adapter per id - /// \return the element adapter for this document. - [[nodiscard]] virtual const ElementAdapter *element_adapter() const = 0; - // TODO move other adapters here + [[nodiscard]] virtual bool + image_is_internal(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::optional + image_file(ElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + image_href(ElementIdentifier element_id) const = 0; }; } // namespace odr::internal::abstract diff --git a/src/odr/internal/abstract/document_element.hpp b/src/odr/internal/abstract/document_element.hpp deleted file mode 100644 index 9fc6040c..00000000 --- a/src/odr/internal/abstract/document_element.hpp +++ /dev/null @@ -1,425 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -namespace odr { -enum class ElementType; -class File; -class DocumentPath; -} // namespace odr - -namespace odr::internal::abstract { -class TextRootAdapter; -class SlideAdapter; -class PageAdapter; -class SheetAdapter; -class SheetColumnAdapter; -class SheetRowAdapter; -class SheetCellAdapter; -class MasterPageAdapter; -class LineBreakAdapter; -class ParagraphAdapter; -class SpanAdapter; -class TextAdapter; -class LinkAdapter; -class BookmarkAdapter; -class ListItemAdapter; -class TableAdapter; -class TableColumnAdapter; -class TableRowAdapter; -class TableCellAdapter; -class FrameAdapter; -class RectAdapter; -class LineAdapter; -class CircleAdapter; -class CustomShapeAdapter; -class ImageAdapter; - -class ElementAdapter { -public: - virtual ~ElementAdapter() = default; - - [[nodiscard]] virtual ElementType - element_type(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual ElementIdentifier - element_parent(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual ElementIdentifier - element_first_child(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual ElementIdentifier - element_last_child(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual ElementIdentifier - element_previous_sibling(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual ElementIdentifier - element_next_sibling(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual bool - element_is_unique(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual bool - element_is_self_locatable(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual bool - element_is_editable(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual DocumentPath - element_document_path(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual ElementIdentifier - element_navigate_path(ElementIdentifier element_id, - const DocumentPath &path) const = 0; - - // TODO push to document - [[nodiscard]] virtual const TextRootAdapter * - text_root_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const SlideAdapter * - slide_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const PageAdapter * - page_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const SheetAdapter * - sheet_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const SheetCellAdapter * - sheet_cell_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const MasterPageAdapter * - master_page_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const LineBreakAdapter * - line_break_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const ParagraphAdapter * - paragraph_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const SpanAdapter * - span_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const TextAdapter * - text_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const LinkAdapter * - link_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const BookmarkAdapter * - bookmark_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const ListItemAdapter * - list_item_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const TableAdapter * - table_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const TableColumnAdapter * - table_column_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const TableRowAdapter * - table_row_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const TableCellAdapter * - table_cell_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const FrameAdapter * - frame_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const RectAdapter * - rect_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const LineAdapter * - line_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const CircleAdapter * - circle_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const CustomShapeAdapter * - custom_shape_adapter(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual const ImageAdapter * - image_adapter(ElementIdentifier element_id) const = 0; -}; - -class TextRootAdapter { -public: - virtual ~TextRootAdapter() = default; - - [[nodiscard]] virtual PageLayout - text_root_page_layout(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual ElementIdentifier - text_root_first_master_page(ElementIdentifier element_id) const = 0; -}; - -class SlideAdapter { -public: - virtual ~SlideAdapter() = default; - - [[nodiscard]] virtual PageLayout - slide_page_layout(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual ElementIdentifier - slide_master_page(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual std::string - slide_name(ElementIdentifier element_id) const = 0; -}; - -class PageAdapter { -public: - virtual ~PageAdapter() = default; - - [[nodiscard]] virtual PageLayout - page_layout(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual ElementIdentifier - page_master_page(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual std::string - page_name(ElementIdentifier element_id) const = 0; -}; - -class SheetAdapter { -public: - virtual ~SheetAdapter() = default; - - [[nodiscard]] virtual std::string - sheet_name(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual TableDimensions - sheet_dimensions(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual TableDimensions - sheet_content(ElementIdentifier element_id, - std::optional range) const = 0; - - [[nodiscard]] virtual ElementIdentifier - sheet_cell(ElementIdentifier element_id, std::uint32_t column, - std::uint32_t row) const = 0; - [[nodiscard]] virtual ElementIdentifier - sheet_first_shape(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual TableStyle - sheet_style(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual TableColumnStyle - sheet_column_style(ElementIdentifier element_id, - std::uint32_t column) const = 0; - [[nodiscard]] virtual TableRowStyle - sheet_row_style(ElementIdentifier element_id, std::uint32_t row) const = 0; - [[nodiscard]] virtual TableCellStyle - sheet_cell_style(ElementIdentifier element_id, std::uint32_t column, - std::uint32_t row) const = 0; -}; - -class SheetCellAdapter { -public: - virtual ~SheetCellAdapter() = default; - - [[nodiscard]] virtual TablePosition - sheet_cell_position(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual bool - sheet_cell_is_covered(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual TableDimensions - sheet_cell_span(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual ValueType - sheet_cell_value_type(ElementIdentifier element_id) const = 0; -}; - -class MasterPageAdapter { -public: - virtual ~MasterPageAdapter() = default; - - [[nodiscard]] virtual PageLayout - master_page_page_layout(ElementIdentifier element_id) const = 0; -}; - -class LineBreakAdapter { -public: - virtual ~LineBreakAdapter() = default; - - [[nodiscard]] virtual TextStyle - line_break_style(ElementIdentifier element_id) const = 0; -}; - -class ParagraphAdapter { -public: - virtual ~ParagraphAdapter() = default; - - [[nodiscard]] virtual ParagraphStyle - paragraph_style(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual TextStyle - paragraph_text_style(ElementIdentifier element_id) const = 0; -}; - -class SpanAdapter { -public: - virtual ~SpanAdapter() = default; - - [[nodiscard]] virtual TextStyle - span_style(ElementIdentifier element_id) const = 0; -}; - -class TextAdapter { -public: - virtual ~TextAdapter() = default; - - [[nodiscard]] virtual std::string - text_content(ElementIdentifier element_id) const = 0; - virtual void text_set_content(ElementIdentifier element_id, - const std::string &text) const = 0; - - [[nodiscard]] virtual TextStyle - text_style(ElementIdentifier element_id) const = 0; -}; - -class LinkAdapter { -public: - virtual ~LinkAdapter() = default; - - [[nodiscard]] virtual std::string - link_href(ElementIdentifier element_id) const = 0; -}; - -class BookmarkAdapter { -public: - virtual ~BookmarkAdapter() = default; - - [[nodiscard]] virtual std::string - bookmark_name(ElementIdentifier element_id) const = 0; -}; - -class ListItemAdapter { -public: - virtual ~ListItemAdapter() = default; - - [[nodiscard]] virtual TextStyle - list_item_style(ElementIdentifier element_id) const = 0; -}; - -class TableAdapter { -public: - virtual ~TableAdapter() = default; - - [[nodiscard]] virtual TableDimensions - table_dimensions(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual ElementIdentifier - table_first_column(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual ElementIdentifier - table_first_row(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual TableStyle - table_style(ElementIdentifier element_id) const = 0; -}; - -class TableColumnAdapter { -public: - virtual ~TableColumnAdapter() = default; - - [[nodiscard]] virtual TableColumnStyle - table_column_style(ElementIdentifier element_id) const = 0; -}; - -class TableRowAdapter { -public: - virtual ~TableRowAdapter() = default; - - [[nodiscard]] virtual TableRowStyle - table_row_style(ElementIdentifier element_id) const = 0; -}; - -class TableCellAdapter { -public: - virtual ~TableCellAdapter() = default; - - [[nodiscard]] virtual bool - table_cell_is_covered(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual TableDimensions - table_cell_span(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual ValueType - table_cell_value_type(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual TableCellStyle - table_cell_style(ElementIdentifier element_id) const = 0; -}; - -class FrameAdapter { -public: - virtual ~FrameAdapter() = default; - - [[nodiscard]] virtual AnchorType - frame_anchor_type(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::optional - frame_x(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::optional - frame_y(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::optional - frame_width(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::optional - frame_height(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::optional - frame_z_index(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual GraphicStyle - frame_style(ElementIdentifier element_id) const = 0; -}; - -class RectAdapter { -public: - virtual ~RectAdapter() = default; - - [[nodiscard]] virtual std::string - rect_x(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - rect_y(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - rect_width(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - rect_height(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual GraphicStyle - rect_style(ElementIdentifier element_id) const = 0; -}; - -class LineAdapter { -public: - virtual ~LineAdapter() = default; - - [[nodiscard]] virtual std::string - line_x1(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - line_y1(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - line_x2(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - line_y2(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual GraphicStyle - line_style(ElementIdentifier element_id) const = 0; -}; - -class CircleAdapter { -public: - virtual ~CircleAdapter() = default; - - [[nodiscard]] virtual std::string - circle_x(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - circle_y(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - circle_width(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - circle_height(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual GraphicStyle - circle_style(ElementIdentifier element_id) const = 0; -}; - -class CustomShapeAdapter { -public: - virtual ~CustomShapeAdapter() = default; - - [[nodiscard]] virtual std::optional - custom_shape_x(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::optional - custom_shape_y(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - custom_shape_width(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - custom_shape_height(ElementIdentifier element_id) const = 0; - - [[nodiscard]] virtual GraphicStyle - custom_shape_style(ElementIdentifier element_id) const = 0; -}; - -class ImageAdapter { -public: - virtual ~ImageAdapter() = default; - - [[nodiscard]] virtual bool - image_is_internal(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::optional - image_file(ElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string - image_href(ElementIdentifier element_id) const = 0; -}; - -} // namespace odr::internal::abstract diff --git a/src/odr/internal/common/document.cpp b/src/odr/internal/common/document.cpp index e10ae662..8641d024 100644 --- a/src/odr/internal/common/document.cpp +++ b/src/odr/internal/common/document.cpp @@ -1,7 +1,5 @@ #include -#include -#include #include namespace odr::internal { @@ -24,10 +22,8 @@ Document::as_filesystem() const noexcept { return m_files; } -ElementIdentifier Document::root_element() const { return m_root_element; } - -const abstract::ElementAdapter *Document::element_adapter() const { - return m_element_adapter.get(); +ElementHandle Document::root_element() const { + return {*m_element_adapter, m_root_element}; } } // namespace odr::internal diff --git a/src/odr/internal/common/document.hpp b/src/odr/internal/common/document.hpp index 0efdcb32..89f649ba 100644 --- a/src/odr/internal/common/document.hpp +++ b/src/odr/internal/common/document.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -23,18 +24,15 @@ class Document : public abstract::Document { [[nodiscard]] std::shared_ptr as_filesystem() const noexcept final; - [[nodiscard]] ElementIdentifier root_element() const override; - - [[nodiscard]] const abstract::ElementAdapter * - element_adapter() const override; + [[nodiscard]] ElementHandle root_element() const override; protected: - FileType m_file_type; - DocumentType m_document_type; + FileType m_file_type{FileType::unknown}; + DocumentType m_document_type{DocumentType::unknown}; std::shared_ptr m_files; - ElementIdentifier m_root_element; + ElementIdentifier m_root_element{null_element_id}; std::unique_ptr m_element_adapter; }; diff --git a/src/odr/internal/odf/odf_document.cpp b/src/odr/internal/odf/odf_document.cpp index 7e1f9061..3214a2a4 100644 --- a/src/odr/internal/odf/odf_document.cpp +++ b/src/odr/internal/odf/odf_document.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -166,50 +165,50 @@ class ElementAdapter final : public abstract::ElementAdapter, return ElementType::none; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_parent(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->parent_id; + return {this, element->parent_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_first_child(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->first_child_id; + return {this, element->first_child_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_last_child(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->last_child_id; + return {this, element->last_child_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_previous_sibling(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->previous_sibling_id; + return {this, element->previous_sibling_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_next_sibling(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->next_sibling_id; + return {this, element->next_sibling_id}; } - return null_element_id; + return {}; } [[nodiscard]] bool @@ -244,7 +243,7 @@ class ElementAdapter final : public abstract::ElementAdapter, element_document_path(const ElementIdentifier element_id) const override { return util::document::extract_path(*this, element_id, null_element_id); } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_navigate_path(const ElementIdentifier element_id, const DocumentPath &path) const override { return util::document::navigate_path(*this, element_id, path); @@ -460,20 +459,20 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] PageLayout text_root_page_layout(const ElementIdentifier element_id) const override { - if (const ElementIdentifier master_page_id = + if (const auto [_, master_page_id] = text_root_first_master_page(element_id); master_page_id != null_element_id) { return master_page_page_layout(master_page_id); } return {}; } - [[nodiscard]] ElementIdentifier text_root_first_master_page( + [[nodiscard]] ElementHandle text_root_first_master_page( const ElementIdentifier element_id) const override { (void)element_id; if (const ElementIdentifier first_master_page_id = m_document->style_registry().first_master_page(); first_master_page_id != null_element_id) { - return first_master_page_id; + return {this, first_master_page_id}; } return {}; } @@ -577,7 +576,7 @@ class ElementAdapter final : public abstract::ElementAdapter, return result; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle sheet_cell(const ElementIdentifier element_id, const std::uint32_t column, const std::uint32_t row) const override { if (const ElementRegistry::Sheet *sheet_registry = @@ -586,19 +585,19 @@ class ElementAdapter final : public abstract::ElementAdapter, if (const ElementRegistry::Sheet::Cell *sheet_cell = sheet_registry->cell(column, row); sheet_cell != nullptr) { - return sheet_cell->element_id; + return {this, sheet_cell->element_id}; } } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle sheet_first_shape(const ElementIdentifier element_id) const override { if (const ElementRegistry::Sheet *sheet_registry = m_registry->sheet_element(element_id); sheet_registry != nullptr) { - return sheet_registry->first_shape_id; + return {this, sheet_registry->first_shape_id}; } - return null_element_id; + return {}; } [[nodiscard]] TableStyle sheet_style(const ElementIdentifier element_id) const override { @@ -649,7 +648,7 @@ class ElementAdapter final : public abstract::ElementAdapter, sheet_cell_style(const ElementIdentifier element_id, const std::uint32_t column, const std::uint32_t row) const override { - const ElementIdentifier cell_id = sheet_cell(element_id, column, row); + const auto [_, cell_id] = sheet_cell(element_id, column, row); return get_partial_cell_style(element_id, cell_id, {column, row}) .table_cell_style; } @@ -844,16 +843,16 @@ class ElementAdapter final : public abstract::ElementAdapter, return result; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle table_first_column(const ElementIdentifier element_id) const override { if (const ElementRegistry::Table *table_registry = m_registry->table_element(element_id); table_registry != nullptr) { - return table_registry->first_column_id; + return {this, table_registry->first_column_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle table_first_row(const ElementIdentifier element_id) const override { return element_first_child(element_id); } @@ -1139,7 +1138,8 @@ class ElementAdapter final : public abstract::ElementAdapter, if (const ElementRegistry::SheetCell *cell_registry = m_registry->sheet_cell_element(element_id); cell_registry != nullptr) { - return get_partial_cell_style(element_parent(element_id), element_id, + const auto [_, parent_id] = element_parent(element_id); + return get_partial_cell_style(parent_id, element_id, cell_registry->position); } if (const char *style_name = get_style_name(element_id); @@ -1153,7 +1153,7 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] ResolvedStyle get_intermediate_style(const ElementIdentifier element_id) const { - const ElementIdentifier parent_id = element_parent(element_id); + const auto [_, parent_id] = element_parent(element_id); if (parent_id == null_element_id) { return get_partial_style(element_id); } diff --git a/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp b/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp index 3f4dd211..3abd782b 100644 --- a/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp +++ b/src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -33,8 +32,9 @@ Document::Document(std::shared_ptr files) util::xml::parse(*m_files, AbsPath("/ppt").join(RelPath(target))); } - m_root_element = parse_tree(m_element_registry, - m_document_xml.document_element(), m_slides_xml); + const ParseContext parse_context(m_slides_xml); + m_root_element = parse_tree(m_element_registry, parse_context, + m_document_xml.document_element()); m_element_adapter = create_element_adapter(*this, m_element_registry); } @@ -155,50 +155,50 @@ class ElementAdapter final : public abstract::ElementAdapter, return ElementType::none; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_parent(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->parent_id; + return {this, element->parent_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_first_child(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->first_child_id; + return {this, element->first_child_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_last_child(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->last_child_id; + return {this, element->last_child_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_previous_sibling(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->previous_sibling_id; + return {this, element->previous_sibling_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_next_sibling(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->next_sibling_id; + return {this, element->next_sibling_id}; } - return null_element_id; + return {}; } [[nodiscard]] bool @@ -221,7 +221,7 @@ class ElementAdapter final : public abstract::ElementAdapter, element_document_path(const ElementIdentifier element_id) const override { return util::document::extract_path(*this, element_id, null_element_id); } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_navigate_path(const ElementIdentifier element_id, const DocumentPath &path) const override { return util::document::navigate_path(*this, element_id, path); @@ -558,16 +558,16 @@ class ElementAdapter final : public abstract::ElementAdapter, return result; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle table_first_column(const ElementIdentifier element_id) const override { if (const ElementRegistry::Table *table_registry = m_registry->table_element(element_id); table_registry != nullptr) { - return table_registry->first_column_id; + return {this, table_registry->first_column_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle table_first_row(const ElementIdentifier element_id) const override { return element_first_child(element_id); } @@ -743,7 +743,7 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] ResolvedStyle get_intermediate_style(const ElementIdentifier element_id) const { - const ElementIdentifier parent_id = element_parent(element_id); + const auto [_, parent_id] = element_parent(element_id); if (parent_id == null_element_id) { return get_partial_style(element_id); } diff --git a/src/odr/internal/ooxml/presentation/ooxml_presentation_parser.cpp b/src/odr/internal/ooxml/presentation/ooxml_presentation_parser.cpp index f44bc96a..4391b8fa 100644 --- a/src/odr/internal/ooxml/presentation/ooxml_presentation_parser.cpp +++ b/src/odr/internal/ooxml/presentation/ooxml_presentation_parser.cpp @@ -10,58 +10,44 @@ namespace odr::internal::ooxml::presentation { namespace { -class Context { -public: - Context(ElementRegistry ®istry, - const std::unordered_map &slides_xml) - : m_registry(®istry), m_slides_xml(&slides_xml) {} - - ElementRegistry ®istry() const { return *m_registry; } - const std::unordered_map & - slides_xml() const { - return *m_slides_xml; - } - -private: - ElementRegistry *m_registry{nullptr}; - const std::unordered_map *m_slides_xml{ - nullptr}; -}; - using TreeParser = std::function( - const Context &context, pugi::xml_node node)>; -using ChildrenParser = std::function; + ElementRegistry ®istry, const ParseContext &context, + pugi::xml_node node)>; +using ChildrenParser = + std::function; std::tuple -parse_any_element_tree(const Context &context, pugi::xml_node node); +parse_any_element_tree(ElementRegistry ®istry, const ParseContext &context, + pugi::xml_node node); -void parse_any_element_children(const Context &context, +void parse_any_element_children(ElementRegistry ®istry, + const ParseContext &context, const ElementIdentifier parent_id, const pugi::xml_node node) { for (pugi::xml_node child_node = node.first_child(); child_node;) { if (const auto [child_id, next_sibling] = - parse_any_element_tree(context, child_node); + parse_any_element_tree(registry, context, child_node); child_id == null_element_id) { child_node = child_node.next_sibling(); } else { - context.registry().append_child(parent_id, child_id); + registry.append_child(parent_id, child_id); child_node = next_sibling; } } } std::tuple -parse_element_tree(const Context &context, const ElementType type, - const pugi::xml_node node, +parse_element_tree(ElementRegistry ®istry, const ParseContext &context, + const ElementType type, const pugi::xml_node node, const ChildrenParser &children_parser) { if (!node) { return {null_element_id, pugi::xml_node()}; } - const auto &[element_id, _] = context.registry().create_element(type, node); + const auto &[element_id, _] = registry.create_element(type, node); - children_parser(context, element_id, node); + children_parser(registry, context, element_id, node); return {element_id, node.next_sibling()}; } @@ -84,7 +70,10 @@ bool is_text_node(const pugi::xml_node node) { } std::tuple -parse_text_element(const Context &context, const pugi::xml_node first) { +parse_text_element(ElementRegistry ®istry, const ParseContext &context, + const pugi::xml_node first) { + (void)context; + if (!first) { return {null_element_id, pugi::xml_node()}; } @@ -94,20 +83,21 @@ parse_text_element(const Context &context, const pugi::xml_node first) { last = last.next_sibling()) { } - const auto &[element_id, _, __] = - context.registry().create_text_element(first, last); + const auto &[element_id, _, __] = registry.create_text_element(first, last); return {element_id, last.next_sibling()}; } -void parse_slide_children(const Context &context, +void parse_slide_children(ElementRegistry ®istry, + const ParseContext &context, const ElementIdentifier parent_id, const pugi::xml_node node) { - parse_any_element_children(context, parent_id, + parse_any_element_children(registry, context, parent_id, node.child("p:cSld").child("p:spTree")); } -void parse_presentation_children(const Context &context, +void parse_presentation_children(ElementRegistry ®istry, + const ParseContext &context, const ElementIdentifier root_id, const pugi::xml_node node) { for (const pugi::xml_node child_node : @@ -115,20 +105,23 @@ void parse_presentation_children(const Context &context, const std::string id = child_node.attribute("r:id").value(); const pugi::xml_node slide_node = context.slides_xml().at(id).document_element(); - auto [child_id, _] = parse_element_tree(context, ElementType::slide, - slide_node, parse_slide_children); - context.registry().append_child(root_id, child_id); + auto [child_id, _] = + parse_element_tree(registry, context, ElementType::slide, slide_node, + parse_slide_children); + registry.append_child(root_id, child_id); } } std::tuple -parse_any_element_tree(const Context &context, const pugi::xml_node node) { +parse_any_element_tree(ElementRegistry ®istry, const ParseContext &context, + const pugi::xml_node node) { const auto create_default_tree_parser = [](const ElementType type, const ChildrenParser &children_parser = parse_any_element_children) { return - [type, children_parser](const Context &c, const pugi::xml_node n) { - return parse_element_tree(c, type, n, children_parser); + [type, children_parser](ElementRegistry &r, const ParseContext &c, + const pugi::xml_node n) { + return parse_element_tree(r, c, type, n, children_parser); }; }; @@ -149,7 +142,7 @@ parse_any_element_tree(const Context &context, const pugi::xml_node node) { if (const auto constructor_it = parser_table.find(node.name()); constructor_it != std::end(parser_table)) { - return constructor_it->second(context, node); + return constructor_it->second(registry, context, node); } return {null_element_id, pugi::xml_node()}; @@ -161,11 +154,10 @@ parse_any_element_tree(const Context &context, const pugi::xml_node node) { namespace odr::internal::ooxml { -ElementIdentifier presentation::parse_tree( - ElementRegistry ®istry, const pugi::xml_node node, - const std::unordered_map &slides_xml) { - const Context context(registry, slides_xml); - auto [root, _] = parse_any_element_tree(context, node); +ElementIdentifier presentation::parse_tree(ElementRegistry ®istry, + const ParseContext &context, + const pugi::xml_node node) { + auto [root, _] = parse_any_element_tree(registry, context, node); return root; } diff --git a/src/odr/internal/ooxml/presentation/ooxml_presentation_parser.hpp b/src/odr/internal/ooxml/presentation/ooxml_presentation_parser.hpp index 3e006a34..58b7f6a9 100644 --- a/src/odr/internal/ooxml/presentation/ooxml_presentation_parser.hpp +++ b/src/odr/internal/ooxml/presentation/ooxml_presentation_parser.hpp @@ -10,8 +10,23 @@ namespace odr::internal::ooxml::presentation { class ElementRegistry; -ElementIdentifier parse_tree( - ElementRegistry ®istry, pugi::xml_node node, - const std::unordered_map &slides_xml); +class ParseContext { +public: + explicit ParseContext( + const std::unordered_map &slides_xml) + : m_slides_xml(&slides_xml) {} + + [[nodiscard]] const std::unordered_map & + slides_xml() const { + return *m_slides_xml; + } + +private: + const std::unordered_map *m_slides_xml{ + nullptr}; +}; + +ElementIdentifier parse_tree(ElementRegistry ®istry, + const ParseContext &context, pugi::xml_node node); } // namespace odr::internal::ooxml::presentation diff --git a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp index 30f67cb8..79310629 100644 --- a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp +++ b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -122,50 +121,50 @@ class ElementAdapter final : public abstract::ElementAdapter, return ElementType::none; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_parent(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->parent_id; + return {this, element->parent_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_first_child(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->first_child_id; + return {this, element->first_child_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_last_child(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->last_child_id; + return {this, element->last_child_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_previous_sibling(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->previous_sibling_id; + return {this, element->previous_sibling_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_next_sibling(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->next_sibling_id; + return {this, element->next_sibling_id}; } - return null_element_id; + return {}; } [[nodiscard]] bool @@ -188,7 +187,7 @@ class ElementAdapter final : public abstract::ElementAdapter, element_document_path(const ElementIdentifier element_id) const override { return util::document::extract_path(*this, element_id, null_element_id); } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_navigate_path(const ElementIdentifier element_id, const DocumentPath &path) const override { return util::document::navigate_path(*this, element_id, path); @@ -351,7 +350,7 @@ class ElementAdapter final : public abstract::ElementAdapter, (void)range; return sheet_dimensions(element_id); // TODO } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle sheet_cell(const ElementIdentifier element_id, const std::uint32_t column, const std::uint32_t row) const override { if (const ElementRegistry::Sheet *sheet_element = @@ -360,19 +359,19 @@ class ElementAdapter final : public abstract::ElementAdapter, if (const ElementRegistry::Sheet::Cell *cell = sheet_element->cell(column, row); cell != nullptr) { - return cell->element_id; + return {this, cell->element_id}; } } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle sheet_first_shape(const ElementIdentifier element_id) const override { if (const ElementRegistry::Sheet *sheet_element = m_registry->sheet_element(element_id); sheet_element != nullptr) { - return sheet_element->first_shape_id; + return {this, sheet_element->first_shape_id}; } - return null_element_id; + return {}; } [[nodiscard]] TableStyle sheet_style(const ElementIdentifier element_id) const override { @@ -635,7 +634,8 @@ class ElementAdapter final : public abstract::ElementAdapter, element_relations != nullptr) { return {element_relations->relations, element_relations->origin}; } - return get_relations_and_origin(element_parent(element_id)); + const auto [_, parent_id] = element_parent(element_id); + return get_relations_and_origin(parent_id); } [[nodiscard]] static std::string get_text(const pugi::xml_node node) { @@ -666,7 +666,7 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] ResolvedStyle get_intermediate_style(const ElementIdentifier element_id) const { - const ElementIdentifier parent_id = element_parent(element_id); + const auto [_, parent_id] = element_parent(element_id); if (parent_id == null_element_id) { return get_partial_style(element_id); } diff --git a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.cpp b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.cpp index 8bcfc06e..b9cdf32c 100644 --- a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.cpp +++ b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.cpp @@ -61,13 +61,13 @@ void parse_root_children(ElementRegistry ®istry, const ParseContext &context, const pugi::xml_node node) { for (pugi::xml_node child_node : node.child("sheets").children("sheet")) { const char *id = child_node.attribute("r:id").value(); - AbsPath sheet_path = context.get_document_path().parent().join( - RelPath(context.get_document_relations().at(id))); + AbsPath sheet_path = context.document_path().parent().join( + RelPath(context.document_relations().at(id))); const auto &[sheet_xml, sheet_relations] = - context.get_documents_and_relations().at(sheet_path); + context.documents_and_relations().at(sheet_path); ParseContext newContext(sheet_path, sheet_relations, - context.get_documents_and_relations(), - context.get_shared_strings()); + context.documents_and_relations(), + context.shared_strings()); const auto &[sheet, _] = parse_any_element_tree( registry, newContext, sheet_xml.document_element()); registry.append_child(parent_id, sheet); @@ -82,7 +82,7 @@ void parse_sheet_cell_children(ElementRegistry ®istry, type_attr.value() == std::string("s")) { const pugi::xml_node v_node = node.child("v"); const std::size_t ref = v_node.first_child().text().as_ullong(); - const pugi::xml_node shared_node = context.get_shared_strings().at(ref); + const pugi::xml_node shared_node = context.shared_strings().at(ref); parse_any_element_children(registry, context, parent_id, shared_node); return; } @@ -98,9 +98,8 @@ parse_sheet_element(ElementRegistry ®istry, const ParseContext &context, } const auto &[element_id, _, sheet] = registry.create_sheet_element(node); - registry.attach_element_relations(element_id, - context.get_document_relations(), - context.get_document_path()); + registry.attach_element_relations(element_id, context.document_relations(), + context.document_path()); for (const pugi::xml_node col_node : node.child("cols").children("col")) { const std::uint32_t min = col_node.attribute("min").as_uint() - 1; @@ -140,14 +139,14 @@ parse_sheet_element(ElementRegistry ®istry, const ParseContext &context, if (const pugi::xml_node drawing_node = node.child("drawing")) { const char *id = drawing_node.attribute("r:id").value(); - const AbsPath drawing_path = context.get_document_path().parent().join( - RelPath(context.get_document_relations().at(id))); + const AbsPath drawing_path = context.document_path().parent().join( + RelPath(context.document_relations().at(id))); const auto &[drawing_xml, drawing_relations] = - context.get_documents_and_relations().at(drawing_path); + context.documents_and_relations().at(drawing_path); const ParseContext drawing_context(drawing_path, drawing_relations, - context.get_documents_and_relations(), - context.get_shared_strings()); + context.documents_and_relations(), + context.shared_strings()); for (const pugi::xml_node shape_node : drawing_xml.document_element().children()) { @@ -208,9 +207,8 @@ parse_frame_element(ElementRegistry ®istry, const ParseContext &context, const auto &[element_id, _] = registry.create_element(ElementType::frame, node); - registry.attach_element_relations(element_id, - context.get_document_relations(), - context.get_document_path()); + registry.attach_element_relations(element_id, context.document_relations(), + context.document_path()); if (const pugi::xml_node image_node = node.child("xdr:pic").child("xdr:blipFill").child("a:blip")) { diff --git a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.hpp b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.hpp index 0a8456c7..1057afae 100644 --- a/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.hpp +++ b/src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.hpp @@ -22,20 +22,25 @@ class ParseContext { m_xml_documents_and_relations(&xml_documents_and_relations), m_shared_strings(&shared_strings) {} - const AbsPath &get_document_path() const { return *m_document_path; } - const Relations &get_document_relations() const { + [[nodiscard]] const AbsPath &document_path() const { + return *m_document_path; + } + [[nodiscard]] const Relations &document_relations() const { return *m_document_relations; } - const XmlDocumentsAndRelations &get_documents_and_relations() const { + [[nodiscard]] const XmlDocumentsAndRelations & + documents_and_relations() const { return *m_xml_documents_and_relations; } - const SharedStrings &get_shared_strings() const { return *m_shared_strings; } + [[nodiscard]] const SharedStrings &shared_strings() const { + return *m_shared_strings; + } private: - const AbsPath *m_document_path{}; - const Relations *m_document_relations{}; - const XmlDocumentsAndRelations *m_xml_documents_and_relations{}; - const SharedStrings *m_shared_strings{}; + const AbsPath *m_document_path{nullptr}; + const Relations *m_document_relations{nullptr}; + const XmlDocumentsAndRelations *m_xml_documents_and_relations{nullptr}; + const SharedStrings *m_shared_strings{nullptr}; }; ElementIdentifier parse_tree(ElementRegistry ®istry, diff --git a/src/odr/internal/ooxml/text/ooxml_text_document.cpp b/src/odr/internal/ooxml/text/ooxml_text_document.cpp index 59cc292d..6fe9405a 100644 --- a/src/odr/internal/ooxml/text/ooxml_text_document.cpp +++ b/src/odr/internal/ooxml/text/ooxml_text_document.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -131,50 +130,50 @@ class ElementAdapter final : public abstract::ElementAdapter, return ElementType::none; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_parent(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->parent_id; + return {this, element->parent_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_first_child(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->first_child_id; + return {this, element->first_child_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_last_child(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->last_child_id; + return {this, element->last_child_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_previous_sibling(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->previous_sibling_id; + return {this, element->previous_sibling_id}; } - return null_element_id; + return {}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_next_sibling(const ElementIdentifier element_id) const override { if (const ElementRegistry::Element *element = m_registry->element(element_id); element != nullptr) { - return element->next_sibling_id; + return {this, element->next_sibling_id}; } - return null_element_id; + return {}; } [[nodiscard]] bool @@ -197,7 +196,7 @@ class ElementAdapter final : public abstract::ElementAdapter, element_document_path(const ElementIdentifier element_id) const override { return util::document::extract_path(*this, element_id, null_element_id); } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle element_navigate_path(const ElementIdentifier element_id, const DocumentPath &path) const override { return util::document::navigate_path(*this, element_id, path); @@ -371,7 +370,7 @@ class ElementAdapter final : public abstract::ElementAdapter, (void)element_id; return {}; } - [[nodiscard]] ElementIdentifier text_root_first_master_page( + [[nodiscard]] ElementHandle text_root_first_master_page( const ElementIdentifier element_id) const override { (void)element_id; return {}; @@ -533,11 +532,11 @@ class ElementAdapter final : public abstract::ElementAdapter, return result; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle table_first_column(const ElementIdentifier element_id) const override { - return m_registry->table_element_at(element_id).first_column_id; + return {this, m_registry->table_element_at(element_id).first_column_id}; } - [[nodiscard]] ElementIdentifier + [[nodiscard]] ElementHandle table_first_row(const ElementIdentifier element_id) const override { return element_first_child(element_id); } @@ -735,7 +734,7 @@ class ElementAdapter final : public abstract::ElementAdapter, [[nodiscard]] ResolvedStyle get_intermediate_style(const ElementIdentifier element_id) const { - const ElementIdentifier parent_id = element_parent(element_id); + const auto [_, parent_id] = element_parent(element_id); ResolvedStyle base; if (parent_id == null_element_id) { base = m_document->style_registry().default_style()->resolved(); diff --git a/src/odr/internal/util/document_util.cpp b/src/odr/internal/util/document_util.cpp index b7d44a5a..48b6c704 100644 --- a/src/odr/internal/util/document_util.cpp +++ b/src/odr/internal/util/document_util.cpp @@ -1,8 +1,9 @@ #include +#include #include -#include +#include #include #include @@ -26,34 +27,33 @@ extract_path_component(const abstract::ElementAdapter &element_adapter, } std::uint32_t distance = 0; - for (ElementIdentifier current_id = + for (ElementHandle current = element_adapter.element_previous_sibling(element_id); - current_id != null_element_id; - current_id = element_adapter.element_previous_sibling(current_id)) { + !current.is_null(); current = current.adapter().element_previous_sibling( + current.identifier)) { ++distance; } return DocumentPath::Child(distance); } -ElementIdentifier +ElementHandle navigate_path_component(const abstract::ElementAdapter &element_adapter, const ElementIdentifier element_id, const DocumentPath::Component &component) { if (const auto *child = std::get_if(&component); child != nullptr) { - ElementIdentifier result_id = - element_adapter.element_first_child(element_id); - if (result_id == null_element_id) { + ElementHandle result = element_adapter.element_first_child(element_id); + if (result.is_null()) { throw std::invalid_argument("child not found"); } for (std::uint32_t i = 0; i < child->number(); ++i) { - result_id = element_adapter.element_next_sibling(result_id); - if (result_id == null_element_id) { + result = result.adapter().element_next_sibling(result.identifier); + if (result.is_null()) { throw std::invalid_argument("child not found"); } } - return result_id; + return result; } if (const auto *cell = std::get_if(&component); @@ -82,33 +82,39 @@ document::extract_path(const abstract::ElementAdapter &element_adapter, std::vector reverse; - for (ElementIdentifier current_id = to_element_id; - current_id != from_element_id; - current_id = element_adapter.element_parent(current_id)) { - if (current_id == null_element_id) { + for (ElementHandle current = {&element_adapter, to_element_id}; + current.identifier != from_element_id;) { + const ElementHandle parent = + current.adapter().element_parent(current.identifier); + if (parent.is_null()) { + break; + } + if (current.is_null()) { throw std::invalid_argument( "Element is not a descendant of the specified root."); } const DocumentPath::Component component = - extract_path_component(element_adapter, current_id); + extract_path_component(element_adapter, current.identifier); reverse.push_back(component); + + current = parent; } std::ranges::reverse(reverse); return DocumentPath(std::move(reverse)); } -ElementIdentifier +ElementHandle document::navigate_path(const abstract::ElementAdapter &element_adapter, const ElementIdentifier from_element_id, const DocumentPath &path) { - ElementIdentifier current_id = from_element_id; + ElementHandle current{element_adapter, from_element_id}; for (const DocumentPath::Component &component : path) { - current_id = - navigate_path_component(element_adapter, current_id, component); + current = navigate_path_component(current.adapter(), current.identifier, + component); } - return current_id; + return current; } } // namespace odr::internal::util diff --git a/src/odr/internal/util/document_util.hpp b/src/odr/internal/util/document_util.hpp index e4d6321b..02a06c31 100644 --- a/src/odr/internal/util/document_util.hpp +++ b/src/odr/internal/util/document_util.hpp @@ -16,8 +16,8 @@ DocumentPath extract_path(const abstract::ElementAdapter &element_adapter, ElementIdentifier to_element_id, ElementIdentifier from_element_id); -ElementIdentifier navigate_path(const abstract::ElementAdapter &element_adapter, - ElementIdentifier from_element_id, - const DocumentPath &path); +ElementHandle navigate_path(const abstract::ElementAdapter &element_adapter, + ElementIdentifier from_element_id, + const DocumentPath &path); } // namespace odr::internal::util::document From 12f729ce3966db364a821e0660c8093918c1c36f Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 29 Dec 2025 14:16:22 +0100 Subject: [PATCH 8/8] fix build --- src/odr/internal/abstract/document.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odr/internal/abstract/document.hpp b/src/odr/internal/abstract/document.hpp index 9798f609..7265f9b3 100644 --- a/src/odr/internal/abstract/document.hpp +++ b/src/odr/internal/abstract/document.hpp @@ -13,7 +13,7 @@ enum class ValueType; enum class AnchorType; struct PageLayout; struct TableDimensions; -struct TablePosition; +class TablePosition; struct TableStyle; struct TableColumnStyle; struct TableRowStyle;