Skip to content
Merged
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
7 changes: 4 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ bytes ─▢ magic/open_strategy ─▢ DecodedFile ─▢ Document ─▢ Eleme
| `src/odr/*.hpp` | **Public API**: `file`, `document`, `document_element`, `html`, `style`, `quantity` (`Measure`), `odr`. |
| `src/odr/internal/abstract/` | Core interfaces: `File`/`DecodedFile`, `Document` + `ElementAdapter`, `Filesystem`, `Archive`, `HtmlService`. |
| `src/odr/internal/common/` | Reusable impls: `Path`/`AbsPath`, base `Document`, filesystem, `style`, table cursor/range, temp files. |
| `src/odr/internal/util/` | Helpers: `byte_stream_util`, `string_util`, `stream_util`, `document_util`, `xml_util`. |
| `src/odr/internal/util/` | Helpers: `byte_stream_util`, `string_util`, `stream_util`, `document_util`. |
| `src/odr/internal/magic.*`, `open_strategy.*` | File-type detection + open/dispatch. |
| `src/odr/internal/file_type_table.*` | **The** per-`FileType` table: extensions, MIME types, category, document type, `FileTypeCapabilities`. Every public lookup in `odr.hpp` is a thin forward into it β€” extend the table, not the lookups. |
| `src/odr/internal/html/` | Generic HTML renderer. |
Expand All @@ -67,9 +67,10 @@ bytes ─▢ magic/open_strategy ─▢ DecodedFile ─▢ Document ─▢ Eleme
| `src/odr/internal/oldms/` | **Legacy MS binary** (.doc/.ppt/.xls). |
| `src/odr/internal/iwork/` | Apple iWork (`.pages`, `.key`, `.numbers`); see [`iwork/AGENTS.md`](src/odr/internal/iwork/AGENTS.md) + [`iwork/PLAN.md`](src/odr/internal/iwork/PLAN.md). |
| `src/odr/internal/pdf/` | PDF (own parser). |
| `src/odr/internal/png/` | PNG encoder: the writer `pdf` image extraction and `svm` bitmaps hand their pixels to. |
| `src/odr/internal/rtf/` | RTF, read as a text document; see [`rtf/AGENTS.md`](src/odr/internal/rtf/AGENTS.md) + [`rtf/PLAN.md`](src/odr/internal/rtf/PLAN.md). |
| `src/odr/internal/markdown/` | Markdown (CommonMark + GFM via md4c), decoded to a text document; see [`markdown/AGENTS.md`](src/odr/internal/markdown/AGENTS.md) + [`markdown/PLAN.md`](src/odr/internal/markdown/PLAN.md). |
| `src/odr/internal/xml/` | XML, rendered as a source view; see [`xml/AGENTS.md`](src/odr/internal/xml/AGENTS.md). |
| `src/odr/internal/xml/` | XML: the pugixml parse and the escaping every xml-writing engine shares (`xml_util`), plus the source view (`xml_file`); see [`xml/AGENTS.md`](src/odr/internal/xml/AGENTS.md). |
| `src/odr/internal/svg/` | SVG, detected by reading it as xml; see [`svg/AGENTS.md`](src/odr/internal/svg/AGENTS.md). |
| `src/odr/internal/svm/` | StarView metafile, the vector image odf/ooxml packages carry for charts and OLE objects; translated to svg. See [`svm/AGENTS.md`](src/odr/internal/svm/AGENTS.md) + [`svm/PLAN.md`](src/odr/internal/svm/PLAN.md). |
| `src/odr/internal/{csv,json,text}/` | Smaller formats. |
Expand Down Expand Up @@ -120,7 +121,7 @@ cmake --build cmake-build-relwithdebinfo --target translate # CLI: file β†’ HTM
link error β€” hence the imported target, and no prebuilt library to mismatch
against. A new target that includes `pugixml.hpp` has to get it too, and the
installed internal headers expose pugixml types, so `odr` carries the define
INTERFACE and `package_info` declares it. `util/xml_util.cpp` asserts the
INTERFACE and `package_info` declares it. `xml/xml_util.cpp` asserts the
layout it compiled against.

## Releasing
Expand Down
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ set(ODR_SOURCE_FILES
"src/odr/internal/pdf/pdf_page_extractor.cpp"
"src/odr/internal/pdf/pdf_shading.cpp"

"src/odr/internal/png/png_util.cpp"

"src/odr/internal/font/cff_builder.cpp"
"src/odr/internal/font/cff_font.cpp"
"src/odr/internal/font/cff_standard_strings.cpp"
Expand Down Expand Up @@ -289,11 +291,10 @@ set(ODR_SOURCE_FILES
"src/odr/internal/util/number_util.cpp"
"src/odr/internal/util/odr_meta_util.cpp"
"src/odr/internal/util/stream_util.cpp"
"src/odr/internal/util/png_util.cpp"
"src/odr/internal/util/string_util.cpp"
"src/odr/internal/util/xml_util.cpp"

"src/odr/internal/xml/xml_file.cpp"
"src/odr/internal/xml/xml_util.cpp"

"src/odr/internal/zip/zip_archive.cpp"
"src/odr/internal/zip/zip_exceptions.cpp"
Expand Down
2 changes: 1 addition & 1 deletion docs/design/editing.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ all against an in-memory copy, writing only on full success (decision 7).
| `toggleMark(range, bold)` | split run; assign an **automatic style** (`text:style-name`) β€” find or create a `<style:style>` with `fo:font-weight="bold"` | split `w:r`; set `<w:rPr><w:b/>` on the middle run |
| `splitParagraph` | clone `<text:p>` (copy style-name), move trailing nodes into the clone | clone `<w:p>` incl. `w:pPr`, move trailing `w:r` |
| `insertParagraph` | `insert_child_after` a fresh `<text:p>` at anchor; **append** registry entry | fresh `<w:p>`; append |
| `insertText(range)` | reuse the `text_set_content` tokenizer (`util::xml::tokenize_text`) on a sub-range | same, `w:t` tokenizer |
| `insertText(range)` | reuse the `text_set_content` tokenizer (`xml::tokenize_text`) on a sub-range | same, `w:t` tokenizer |

Two genuinely format-specific complications, both already visible in the code:

Expand Down
6 changes: 3 additions & 3 deletions src/odr/internal/html/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <odr/internal/html/html_writer.hpp>
#include <odr/internal/util/stream_util.hpp>
#include <odr/internal/util/string_util.hpp>
#include <odr/internal/util/xml_util.hpp>
#include <odr/internal/xml/xml_util.hpp>

#include <odr/html.hpp>
#include <odr/quantity.hpp>
Expand All @@ -32,7 +32,7 @@ void html::write_viewport_meta(
const std::optional<HtmlViewportMode> mode_override) {
if (config.viewport_content.has_value()) {
out.write_header_viewport(
util::xml::escape_attribute(config.viewport_content.value()));
xml::escape_attribute(config.viewport_content.value()));
return;
}

Expand Down Expand Up @@ -257,7 +257,7 @@ std::string html::escape_text(std::string text) {
return text;
}

text = util::xml::escape_text(text);
text = xml::escape_text(text);

if (text.front() == ' ') {
text = "&nbsp;" + text.substr(1);
Expand Down
4 changes: 2 additions & 2 deletions src/odr/internal/html/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ void write_zoom_style(HtmlWriter &out, const HtmlConfig &config, WidthFit fits,
/// length, which leaves those insets as shipped.
void write_content_margin_style(HtmlWriter &out, const HtmlConfig &config);

/// @ref util::xml::escape_text, plus the `&nbsp;` and `&emsp;` that keep html
/// @ref xml::escape_text, plus the `&nbsp;` and `&emsp;` that keep html
/// from collapsing the run's own whitespace. An attribute value wants
/// @ref util::xml::escape_attribute instead, which leaves spaces intact.
/// @ref xml::escape_attribute instead, which leaves spaces intact.
std::string escape_text(std::string text);

/// What a target is, as an `href` would be dispatched. Whitespace and control
Expand Down
9 changes: 4 additions & 5 deletions src/odr/internal/html/document_element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include <odr/internal/html/html_service.hpp>
#include <odr/internal/html/html_writer.hpp>
#include <odr/internal/html/image_file.hpp>
#include <odr/internal/util/xml_util.hpp>
#include <odr/internal/xml/xml_util.hpp>

namespace odr::internal {

Expand Down Expand Up @@ -414,7 +414,7 @@ void html::translate_link(const Element &element, const WritingState &state) {
// A refused target loses the attribute, not the element.
HtmlAttributesVector attributes;
if (kind != UriKind::refused) {
attributes.emplace_back("href", util::xml::escape_attribute(href));
attributes.emplace_back("href", xml::escape_attribute(href));
}

HtmlElementOptions options =
Expand All @@ -437,7 +437,7 @@ void html::translate_bookmark(const Element &element,
state.out().write_element_begin(
"a",
HtmlElementOptions().set_inline(true).set_attributes(HtmlAttributesVector{
{"id", util::xml::escape_attribute(bookmark.name())}}));
{"id", xml::escape_attribute(bookmark.name())}}));
state.out().write_element_end("a");
}

Expand Down Expand Up @@ -566,8 +566,7 @@ void html::translate_image(const Element &element, const WritingState &state) {
.set_attributes([&](const HtmlAttributeWriterCallback &clb) {
clb("alt", "Error: image not found or unsupported");
if (resource_location.has_value()) {
clb("src",
util::xml::escape_attribute(resource_location.value()));
clb("src", xml::escape_attribute(resource_location.value()));
} else {
clb("src", [&](std::ostream &o) {
// reached only for internal images, which have a file
Expand Down
16 changes: 8 additions & 8 deletions src/odr/internal/html/document_style.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <odr/style.hpp>

#include <odr/internal/html/common.hpp>
#include <odr/internal/util/xml_util.hpp>
#include <odr/internal/xml/xml_util.hpp>

namespace odr::internal {

Expand Down Expand Up @@ -151,7 +151,7 @@ std::string html::translate_text_style(const TextStyle &text_style) {
if (const std::optional<std::string_view> font_name = text_style.font_name;
font_name.has_value()) {
result.append("font-family:")
.append(util::xml::escape_attribute(std::string(*font_name)))
.append(xml::escape_attribute(std::string(*font_name)))
.append(";");
}
if (const std::optional<Measure> font_size = text_style.font_size;
Expand Down Expand Up @@ -179,7 +179,7 @@ std::string html::translate_text_style(const TextStyle &text_style) {
if (const std::optional<std::string> font_shadow = text_style.font_shadow;
font_shadow.has_value()) {
result.append("text-shadow:")
.append(util::xml::escape_attribute(*font_shadow))
.append(xml::escape_attribute(*font_shadow))
.append(";");
}
if (const std::optional<Color> font_color = text_style.font_color;
Expand Down Expand Up @@ -207,7 +207,7 @@ std::string html::translate_block_font_style(const TextStyle &text_style) {
if (const std::optional<std::string_view> font_name = text_style.font_name;
font_name.has_value()) {
result.append("font-family:")
.append(util::xml::escape_attribute(std::string(*font_name)))
.append(xml::escape_attribute(std::string(*font_name)))
.append(";");
}
if (const std::optional<Measure> font_size = text_style.font_size;
Expand Down Expand Up @@ -357,27 +357,27 @@ html::translate_table_cell_style(const TableCellStyle &table_cell_style) {
table_cell_style.border.right;
border_right.has_value()) {
result.append("border-right:")
.append(util::xml::escape_attribute(*border_right))
.append(xml::escape_attribute(*border_right))
.append(";");
}
if (const std::optional<std::string> border_top = table_cell_style.border.top;
border_top.has_value()) {
result.append("border-top:")
.append(util::xml::escape_attribute(*border_top))
.append(xml::escape_attribute(*border_top))
.append(";");
}
if (const std::optional<std::string> border_left =
table_cell_style.border.left;
border_left.has_value()) {
result.append("border-left:")
.append(util::xml::escape_attribute(*border_left))
.append(xml::escape_attribute(*border_left))
.append(";");
}
if (const std::optional<std::string> border_bottom =
table_cell_style.border.bottom;
border_bottom.has_value()) {
result.append("border-bottom:")
.append(util::xml::escape_attribute(*border_bottom))
.append(xml::escape_attribute(*border_bottom))
.append(";");
}
if (const std::optional<double> text_rotation =
Expand Down
22 changes: 11 additions & 11 deletions src/odr/internal/html/filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include <odr/internal/html/frontend.hpp>
#include <odr/internal/html/html_service.hpp>
#include <odr/internal/html/html_writer.hpp>
#include <odr/internal/util/xml_util.hpp>
#include <odr/internal/xml/xml_util.hpp>

#include <array>
#include <iomanip>
Expand Down Expand Up @@ -226,10 +226,10 @@ class HtmlServiceImpl final : public HtmlService {
HtmlElementOptions().set_inline(true).set_class("odr-files-name"));
if (location.has_value()) {
out.write_element_begin(
"a", HtmlElementOptions().set_inline(true).set_attributes(
HtmlAttributesVector{
{"href", util::xml::escape_attribute(*location)},
{"title", util::xml::escape_attribute(name)}}));
"a",
HtmlElementOptions().set_inline(true).set_attributes(
HtmlAttributesVector{{"href", xml::escape_attribute(*location)},
{"title", xml::escape_attribute(name)}}));
out.write_raw(escape_text(file_path.string()));
out.write_element_end("a");
} else {
Expand All @@ -250,15 +250,15 @@ class HtmlServiceImpl final : public HtmlService {
HtmlElementOptions().set_inline(true).set_class("odr-files-action"));
if (const std::optional<std::string> href =
location.has_value()
? std::optional(util::xml::escape_attribute(*location))
? std::optional(xml::escape_attribute(*location))
: entry_data_url(file, mime_type_of(file_path));
href.has_value()) {
out.write_element_begin(
"a", HtmlElementOptions().set_inline(true).set_attributes(
HtmlAttributesVector{
{"href", *href},
{"download", util::xml::escape_attribute(name)},
{"title", util::xml::escape_attribute(name)}}));
"a",
HtmlElementOptions().set_inline(true).set_attributes(
HtmlAttributesVector{{"href", *href},
{"download", xml::escape_attribute(name)},
{"title", xml::escape_attribute(name)}}));
out.write_raw("\u2193");
out.write_element_end("a");
}
Expand Down
7 changes: 3 additions & 4 deletions src/odr/internal/html/frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <odr/internal/html/common.hpp>
#include <odr/internal/html/html_service.hpp>
#include <odr/internal/html/html_writer.hpp>
#include <odr/internal/util/xml_util.hpp>
#include <odr/internal/xml/xml_util.hpp>

#include <array>
#include <span>
Expand Down Expand Up @@ -1561,8 +1561,7 @@ void write_style(const Asset &asset, const WritingState &state,
if (const HtmlResourceLocation location =
locate(asset, state.config(), state.resources());
location.has_value()) {
state.out().write_header_style(util::xml::escape_attribute(*location),
media);
state.out().write_header_style(xml::escape_attribute(*location), media);
return;
}

Expand All @@ -1581,7 +1580,7 @@ void write_script(const Asset &asset, const WritingState &state) {
if (const HtmlResourceLocation location =
locate(asset, state.config(), state.resources());
location.has_value()) {
state.out().write_script(util::xml::escape_attribute(*location));
state.out().write_script(xml::escape_attribute(*location));
return;
}

Expand Down
4 changes: 2 additions & 2 deletions src/odr/internal/html/media_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <odr/internal/html/html_service.hpp>
#include <odr/internal/html/html_writer.hpp>
#include <odr/internal/util/string_util.hpp>
#include <odr/internal/util/xml_util.hpp>
#include <odr/internal/xml/xml_util.hpp>

#include <algorithm>
#include <filesystem>
Expand Down Expand Up @@ -182,7 +182,7 @@ class HtmlServiceImpl final : public HtmlService {
: "controls preload=\"metadata\"")
.set_attributes([&](const HtmlAttributeWriterCallback &clb) {
if (location.has_value()) {
clb("src", util::xml::escape_attribute(*location));
clb("src", xml::escape_attribute(*location));
} else {
clb("src", [&](std::ostream &o) {
o << file_to_url(*m_media_file.file().impl(), m_mime_type);
Expand Down
6 changes: 3 additions & 3 deletions src/odr/internal/html/pdf_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include <odr/internal/pdf/pdf_file.hpp>
#include <odr/internal/pdf/pdf_page_extractor.hpp>
#include <odr/internal/util/string_util.hpp>
#include <odr/internal/util/xml_util.hpp>
#include <odr/internal/xml/xml_util.hpp>

#include <utf8cpp/utf8/unchecked.h>

Expand Down Expand Up @@ -246,7 +246,7 @@ std::vector<LinkOut> collect_page_links(const pdf::Page &page,
link.top = std::min(p0[1], p1[1]);
link.width = std::abs(p1[0] - p0[0]);
link.height = std::abs(p1[1] - p0[1]);
link.href = util::xml::escape_attribute(std::move(href));
link.href = xml::escape_attribute(std::move(href));
link.internal = internal;
links.push_back(std::move(link));
}
Expand Down Expand Up @@ -675,7 +675,7 @@ std::string svg_image_fragment(const pdf::ImageElement &image,
!blend.empty()) {
f << " style=\"mix-blend-mode:" << blend << '"';
}
f << " href=\"" << util::xml::escape_attribute(images.url(image)) << "\"/>";
f << " href=\"" << xml::escape_attribute(images.url(image)) << "\"/>";
if (!clip_id.empty()) {
f << "</g>";
}
Expand Down
19 changes: 9 additions & 10 deletions src/odr/internal/odf/odf_document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include <odr/internal/odf/odf_table.hpp>
#include <odr/internal/util/document_util.hpp>
#include <odr/internal/util/string_util.hpp>
#include <odr/internal/util/xml_util.hpp>
#include <odr/internal/xml/xml_util.hpp>
#include <odr/internal/zip/zip_archive.hpp>

#include <cstring>
Expand All @@ -31,10 +31,10 @@ create_element_adapter(const Document &document, ElementRegistry &registry);
Document::Document(const FileType file_type, const DocumentType document_type,
std::shared_ptr<abstract::ReadableFilesystem> files)
: internal::Document(file_type, document_type, std::move(files)) {
m_content_xml = util::xml::parse(*m_files, AbsPath("/content.xml"));
m_content_xml = xml::parse(*m_files, AbsPath("/content.xml"));

if (m_files->exists(AbsPath("/styles.xml"))) {
m_styles_xml = util::xml::parse(*m_files, AbsPath("/styles.xml"));
m_styles_xml = xml::parse(*m_files, AbsPath("/styles.xml"));
}

init_(m_content_xml.document_element(), m_styles_xml.document_element());
Expand Down Expand Up @@ -121,8 +121,7 @@ void Document::save(std::ostream &out) const {
}
if (abs_path == Path("/META-INF/manifest.xml")) {
// TODO
auto manifest =
util::xml::parse(*m_files, AbsPath("/META-INF/manifest.xml"));
auto manifest = xml::parse(*m_files, AbsPath("/META-INF/manifest.xml"));

for (auto &&node : manifest.select_nodes("//manifest:encryption-data")) {
node.node().parent().remove_child(node.node());
Expand Down Expand Up @@ -651,19 +650,19 @@ class ElementAdapter final : public abstract::ElementAdapter,
return track(parent.insert_child_before(node, old_first));
};

for (const util::xml::StringToken &token : util::xml::tokenize_text(text)) {
for (const xml::StringToken &token : xml::tokenize_text(text)) {
switch (token.type) {
case util::xml::StringToken::Type::none:
case xml::StringToken::Type::none:
break;
case util::xml::StringToken::Type::string: {
case xml::StringToken::Type::string: {
auto text_node = insert_pcdata();
text_node.text().set(token.string.c_str());
} break;
case util::xml::StringToken::Type::spaces: {
case xml::StringToken::Type::spaces: {
auto space_node = insert_node("text:s");
space_node.prepend_attribute("text:c").set_value(token.string.size());
} break;
case util::xml::StringToken::Type::tabs: {
case xml::StringToken::Type::tabs: {
for (std::size_t i = 0; i < token.string.size(); ++i) {
insert_node("text:tab");
}
Expand Down
4 changes: 2 additions & 2 deletions src/odr/internal/odf/odf_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <odr/internal/abstract/filesystem.hpp>
#include <odr/internal/odf/odf_crypto.hpp>
#include <odr/internal/odf/odf_document.hpp>
#include <odr/internal/util/xml_util.hpp>
#include <odr/internal/xml/xml_util.hpp>

namespace odr::internal::abstract {
class Document;
Expand All @@ -19,7 +19,7 @@ OpenDocumentFile::OpenDocumentFile(
: m_filesystem{std::move(filesystem)} {
if (m_filesystem->exists(AbsPath("/META-INF/manifest.xml"))) {
const pugi::xml_document manifest =
util::xml::parse(*m_filesystem, AbsPath("/META-INF/manifest.xml"));
xml::parse(*m_filesystem, AbsPath("/META-INF/manifest.xml"));

m_file_meta = parse_file_meta(*m_filesystem, &manifest, false);
m_manifest = parse_manifest(manifest);
Expand Down
Loading
Loading