diff --git a/src/imports/ods_writer.cpp b/src/imports/ods_writer.cpp index 91faa3e..66d459d 100644 --- a/src/imports/ods_writer.cpp +++ b/src/imports/ods_writer.cpp @@ -73,11 +73,14 @@ std::string build_content_xml(const std::vector &sheets) { } std::ostringstream oss; - doc.save(oss, " ", pugi::format_no_declaration | pugi::format_raw); - // pugi's `format_no_declaration` drops the `` line; we want - // it. Re-emit explicitly to control encoding. - return std::string(R"()" "\n") - + oss.str(); + // We added the declaration node explicitly above, so pugi will emit + // it. `format_no_declaration` only suppresses *implicit* injection; + // setting it here would leave the explicit node in place and silently + // duplicate would-be auto-emission elsewhere. Keep format_raw to + // avoid pretty-print overhead — the file is read by software, not + // humans. + doc.save(oss, "", pugi::format_raw); + return oss.str(); } // Minimum META-INF/manifest.xml that satisfies the spec. diff --git a/src/tui/commands_export.cpp b/src/tui/commands_export.cpp index 2fe7f20..7c4a3f7 100644 --- a/src/tui/commands_export.cpp +++ b/src/tui/commands_export.cpp @@ -98,12 +98,18 @@ void Tui::RegisterExportCommands() { int total = 0; for (auto &ckv : *sys->connections()) { Connection *c = ckv.second; - // Sheet names: Excel rejects /\?*:[] characters - // (LibreOffice tolerates them but stays portable). + // Sheet names: Excel rejects /\?*:[] characters, + // ODS forbids < > & in raw cell/table names + // (they'd need entity-escaping but a few viewers + // choke on them). Sanitise to underscores. std::string sname = c->name; for (char &ch : sname) if (ch == '/' || ch == '\\' || ch == '?' || ch == '*' - || ch == ':' || ch == '[' || ch == ']') ch = '_'; + || ch == ':' || ch == '[' || ch == ']' + || ch == '<' || ch == '>' || ch == '&') ch = '_'; + // Sheet names also can't exceed 31 chars in + // Excel; clip aggressively to stay portable. + if (sname.size() > 31) sname = sname.substr(0, 31); OdsSheet *s = w.add_sheet(sname); const char *hdr[] = { "transform",