Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ set(ODR_SOURCE_FILES
"src/odr/internal/odf/odf_parser.cpp"
"src/odr/internal/odf/odf_style.cpp"

"src/odr/internal/oldms/word/io.cpp"
"src/odr/internal/oldms/text/doc_document.cpp"
"src/odr/internal/oldms/text/doc_element_registry.cpp"
"src/odr/internal/oldms/text/doc_helper.cpp"
"src/odr/internal/oldms/text/doc_io.cpp"
"src/odr/internal/oldms/text/doc_parser.cpp"
"src/odr/internal/oldms/oldms_file.cpp"

"src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp"
Expand Down
11 changes: 6 additions & 5 deletions src/odr/internal/odf/odf_element_registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ namespace odr::internal::odf {

void ElementRegistry::clear() noexcept {
m_elements.clear();
m_tables.clear();
m_texts.clear();
m_tables.clear();
m_sheets.clear();
m_sheet_cells.clear();
}

[[nodiscard]] std::size_t ElementRegistry::size() const noexcept {
Expand Down Expand Up @@ -219,17 +220,17 @@ void ElementRegistry::check_element_id(const ElementIdentifier id) const {
}
}

void ElementRegistry::check_table_id(const ElementIdentifier id) const {
void ElementRegistry::check_text_id(const ElementIdentifier id) const {
check_element_id(id);
if (!m_tables.contains(id)) {
if (!m_texts.contains(id)) {
throw std::out_of_range(
"DocumentElementRegistry::check_id: identifier not found");
}
}

void ElementRegistry::check_text_id(const ElementIdentifier id) const {
void ElementRegistry::check_table_id(const ElementIdentifier id) const {
check_element_id(id);
if (!m_texts.contains(id)) {
if (!m_tables.contains(id)) {
throw std::out_of_range(
"DocumentElementRegistry::check_id: identifier not found");
}
Expand Down
2 changes: 1 addition & 1 deletion src/odr/internal/odf/odf_element_registry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ class ElementRegistry final {
std::unordered_map<ElementIdentifier, SheetCell> m_sheet_cells;

void check_element_id(ElementIdentifier id) const;
void check_table_id(ElementIdentifier id) const;
void check_text_id(ElementIdentifier id) const;
void check_table_id(ElementIdentifier id) const;
void check_sheet_id(ElementIdentifier id) const;
void check_sheet_cell_id(ElementIdentifier id) const;
};
Expand Down
199 changes: 199 additions & 0 deletions src/odr/internal/oldms/text/doc_document.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
#include <odr/internal/oldms/text/doc_document.hpp>

#include <odr/document_path.hpp>
#include <odr/exceptions.hpp>
#include <odr/style.hpp>

#include <odr/internal/abstract/filesystem.hpp>
#include <odr/internal/common/file.hpp>
#include <odr/internal/oldms/text/doc_parser.hpp>
#include <odr/internal/util/document_util.hpp>

namespace odr::internal::oldms::text {

namespace {
std::unique_ptr<abstract::ElementAdapter>
create_element_adapter(const Document &document, ElementRegistry &registry);
}

Document::Document(std::shared_ptr<abstract::ReadableFilesystem> files)
: internal::Document(FileType::legacy_word_document, DocumentType::text,
std::move(files)) {
m_root_element = parse_tree(m_element_registry, *files);

m_element_adapter = create_element_adapter(*this, m_element_registry);
}

ElementRegistry &Document::element_registry() { return m_element_registry; }

const ElementRegistry &Document::element_registry() const {
return m_element_registry;
}

bool Document::is_editable() const noexcept { return true; }

bool Document::is_savable(const bool encrypted) const noexcept {
return !encrypted;
}

void Document::save(const Path &path) const {
(void)path;
throw UnsupportedOperation();
}

void Document::save(const Path &path, const char *password) const {
(void)path;
(void)password;
throw UnsupportedOperation();
}

namespace {

class ElementAdapter final : public abstract::ElementAdapter,
public abstract::TextRootAdapter,
public abstract::LineBreakAdapter,
public abstract::ParagraphAdapter,
public abstract::SpanAdapter,
public abstract::TextAdapter {
public:
ElementAdapter(const Document &document, ElementRegistry &registry)
: m_document(&document), m_registry(&registry) {}

[[nodiscard]] ElementType
element_type(const ElementIdentifier element_id) const override {
return m_registry->element_at(element_id).type;
}

[[nodiscard]] ElementIdentifier
element_parent(const ElementIdentifier element_id) const override {
return m_registry->element_at(element_id).parent_id;
}
[[nodiscard]] ElementIdentifier
element_first_child(const ElementIdentifier element_id) const override {
return m_registry->element_at(element_id).first_child_id;
}
[[nodiscard]] ElementIdentifier
element_last_child(const ElementIdentifier element_id) const override {
return m_registry->element_at(element_id).last_child_id;
}
[[nodiscard]] ElementIdentifier
element_previous_sibling(const ElementIdentifier element_id) const override {
return m_registry->element_at(element_id).previous_sibling_id;
}
[[nodiscard]] ElementIdentifier
element_next_sibling(const ElementIdentifier element_id) const override {
return m_registry->element_at(element_id).next_sibling_id;
}

[[nodiscard]] bool element_is_unique(
[[maybe_unused]] const ElementIdentifier element_id) const override {
(void)element_id;
return true;
}
[[nodiscard]] bool element_is_self_locatable(
[[maybe_unused]] const ElementIdentifier element_id) const override {
(void)element_id;
return true;
}
[[nodiscard]] bool element_is_editable(
[[maybe_unused]] const ElementIdentifier element_id) const override {
(void)element_id;
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 {
return element_type(element_id) == ElementType::root ? this : nullptr;
}
[[nodiscard]] const LineBreakAdapter *
line_break_adapter(const ElementIdentifier element_id) const override {
return element_type(element_id) == ElementType::line_break ? this : nullptr;
}
[[nodiscard]] const ParagraphAdapter *
paragraph_adapter(const ElementIdentifier element_id) const override {
return element_type(element_id) == ElementType::paragraph ? this : nullptr;
}
[[nodiscard]] const SpanAdapter *
span_adapter(const ElementIdentifier element_id) const override {
return element_type(element_id) == ElementType::span ? this : nullptr;
}
[[nodiscard]] const TextAdapter *
text_adapter(const ElementIdentifier element_id) const override {
return element_type(element_id) == ElementType::text ? this : nullptr;
}

[[nodiscard]] PageLayout text_root_page_layout(
[[maybe_unused]] const ElementIdentifier element_id) const override {
(void)element_id;
return {};
}
[[nodiscard]] ElementIdentifier text_root_first_master_page(
[[maybe_unused]] const ElementIdentifier element_id) const override {
(void)element_id;
return {};
}

[[nodiscard]] TextStyle
line_break_style(const ElementIdentifier element_id) const override {
(void)element_id;
return {}; // TODO
}

[[nodiscard]] ParagraphStyle
paragraph_style(const ElementIdentifier element_id) const override {
(void)element_id;
return {}; // TODO
}
[[nodiscard]] TextStyle
paragraph_text_style(const ElementIdentifier element_id) const override {
(void)element_id;
return {}; // TODO
}

[[nodiscard]] TextStyle
span_style(const ElementIdentifier element_id) const override {
(void)element_id;
return {}; // TODO
}

[[nodiscard]] std::string
text_content(const ElementIdentifier element_id) const override {
return m_registry->text_element_at(element_id).text;
}
void text_set_content(const ElementIdentifier element_id,
const std::string &text) const override {
(void)element_id;
(void)text;
throw UnsupportedOperation();
}
[[nodiscard]] TextStyle
text_style(const ElementIdentifier element_id) const override {
(void)element_id;
return {}; // TODO
}

private:
// TODO remove maybe_unused
[[maybe_unused]]
const Document *m_document{nullptr};
ElementRegistry *m_registry{nullptr};
};

std::unique_ptr<abstract::ElementAdapter>
create_element_adapter(const Document &document, ElementRegistry &registry) {
return std::make_unique<ElementAdapter>(document, registry);
}

} // namespace

} // namespace odr::internal::oldms::text
28 changes: 28 additions & 0 deletions src/odr/internal/oldms/text/doc_document.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <odr/internal/common/document.hpp>
#include <odr/internal/oldms/text/doc_element_registry.hpp>

#include <memory>

namespace odr::internal::oldms::text {

class Document final : public internal::Document {
public:
explicit Document(std::shared_ptr<abstract::ReadableFilesystem> files);

ElementRegistry &element_registry();

[[nodiscard]] const ElementRegistry &element_registry() const;

[[nodiscard]] bool is_editable() const noexcept override;
[[nodiscard]] bool is_savable(bool encrypted) const noexcept override;

void save(const Path &path) const override;
void save(const Path &path, const char *password) const override;

private:
ElementRegistry m_element_registry;
};

} // namespace odr::internal::oldms::text
98 changes: 98 additions & 0 deletions src/odr/internal/oldms/text/doc_element_registry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include <odr/internal/oldms/text/doc_element_registry.hpp>

#include <stdexcept>

namespace odr::internal::oldms::text {

void ElementRegistry::clear() noexcept {
m_elements.clear();
m_texts.clear();
}

[[nodiscard]] std::size_t ElementRegistry::size() const noexcept {
return m_elements.size();
}

std::tuple<ElementIdentifier, ElementRegistry::Element &>
ElementRegistry::create_element(const ElementType type) {
Element &element = m_elements.emplace_back();
ElementIdentifier element_id = m_elements.size();
element.type = type;
return {element_id, element};
}

std::tuple<ElementIdentifier, ElementRegistry::Element &,
ElementRegistry::Text &>
ElementRegistry::create_text_element() {
const auto &[element_id, element] = create_element(ElementType::text);
auto [it, success] = m_texts.emplace(element_id, Text{});
return {element_id, element, it->second};
}

ElementRegistry::Element &
ElementRegistry::element_at(const ElementIdentifier id) {
check_element_id(id);
return m_elements.at(id - 1);
}

ElementRegistry::Text &
ElementRegistry::text_element_at(const ElementIdentifier id) {
check_text_id(id);
return m_texts.at(id);
}

const ElementRegistry::Element &
ElementRegistry::element_at(const ElementIdentifier id) const {
check_element_id(id);
return m_elements.at(id - 1);
}

const ElementRegistry::Text &
ElementRegistry::text_element_at(const ElementIdentifier id) const {
check_text_id(id);
return m_texts.at(id);
}

void ElementRegistry::append_child(const ElementIdentifier parent_id,
const ElementIdentifier child_id) {
check_element_id(parent_id);
check_element_id(child_id);
if (element_at(child_id).parent_id != null_element_id) {
throw std::invalid_argument(
"DocumentElementRegistry::append_child: child already has a parent");
}

const ElementIdentifier previous_sibling_id =
element_at(parent_id).last_child_id;

element_at(child_id).parent_id = parent_id;
element_at(child_id).previous_sibling_id = previous_sibling_id;

if (element_at(parent_id).first_child_id == null_element_id) {
element_at(parent_id).first_child_id = child_id;
} else {
element_at(previous_sibling_id).next_sibling_id = child_id;
}
element_at(parent_id).last_child_id = child_id;
}

void ElementRegistry::check_element_id(const ElementIdentifier id) const {
if (id == null_element_id) {
throw std::out_of_range(
"DocumentElementRegistry::check_id: null identifier");
}
if (id - 1 >= m_elements.size()) {
throw std::out_of_range(
"DocumentElementRegistry::check_id: identifier out of range");
}
}

void ElementRegistry::check_text_id(const ElementIdentifier id) const {
check_element_id(id);
if (!m_texts.contains(id)) {
throw std::out_of_range(
"DocumentElementRegistry::check_id: identifier not found");
}
}

} // namespace odr::internal::oldms::text
Loading