diff --git a/include/xlnt/packaging/manifest.hpp b/include/xlnt/packaging/manifest.hpp
index 82ae89c8..5e7659a7 100644
--- a/include/xlnt/packaging/manifest.hpp
+++ b/include/xlnt/packaging/manifest.hpp
@@ -115,106 +115,82 @@ public:
///
bool has_package_relationship(relationship::type type) const;
+ ///
+ /// Returns true if the manifest contains a package relationship with the given id.
+ ///
+ bool has_package_relationship(const std::string &rel_id) const;
+
///
/// Returns true if the manifest contains a relationship with the given type with part as the source.
///
bool has_part_relationship(const path &part, relationship::type type) const;
+ ///
+ /// Returns true if the manifest contains a relationship with the given type with part as the source.
+ ///
+ bool has_part_relationship(const path &part, const std::string &rel_id) const;
+
relationship get_package_relationship(relationship::type type) const;
+ relationship get_package_relationship(const std::string &rel_id) const;
+
+ std::vector get_package_relationships() const;
+
std::vector get_package_relationships(relationship::type type) const;
relationship get_part_relationship(const path &part, relationship::type type) const;
+ relationship get_part_relationship(const path &part, const std::string &rel_id) const;
+
+ std::vector get_part_relationships(const path &part) const;
+
std::vector get_part_relationships(const path &part, relationship::type type) const;
///
/// Given the path to a part, returns the content type of the part as
/// a content_type enum value or content_type::unknown if it isn't known.
///
- content_type get_part_content_type(const path &part) const;
+ content_type get_content_type(const path &part) const;
///
/// Given the path to a part, returns the content type of the part as a string.
///
- std::string get_part_content_type_string(const path &part) const;
+ std::string get_content_type_string(const path &part) const;
- ///
- /// Registers a part of the given type at the standard path and creates a
- /// relationship with the new part as a target of "source". The type of the
- /// relationship is inferred based on the provided types.
- ///
- void register_part(const path &part, const path &parent, const std::string &content_type, relationship::type relation);
-
- ///
- ///
- ///
- void register_part(const path &parent, const relationship &rel, const std::string &content_type);
-
- ///
- /// Registers a package part of the given type at the standard path and creates a
- /// relationship with the package root as the source. The type of the
- /// relationship is inferred based on the provided type.
- ///
- void register_package_part(const path &part, const std::string &content_type, relationship::type relation);
+ void register_override_type(const path &part, const std::string &content_type);
///
/// Unregisters the path of the part of the given type and removes all relationships
/// with the part as a source or target.
///
- void unregister_part(const path &part);
+ void unregister_override_type(const path &part);
///
/// Returns true if the part at the given path has been registered in this manifest.
///
- bool has_part(const path &part) const;
+ bool has_override_type(const path &part) const;
- ///
- /// Returns the path of every registered part in this manifest.
- ///
- std::vector get_parts() const;
-
- ///
- /// Returns every registered relationship with the package root as the source.
- ///
- std::vector get_package_relationships() const;
-
- ///
- /// Returns the package relationship with the given ID.
- ///
- relationship get_package_relationship(const std::string &rel_id);
-
- ///
- /// Returns every registered relationship with the part of the given type
- /// as the source.
- ///
- std::vector get_part_relationships(const path &part) const;
-
- ///
- /// Returns the registered relationship with the part of the given type
- /// as the source and the ID matching the provided ID.
- ///
- relationship get_part_relationship(const path &part, const std::string &rel_id) const;
+ std::vector get_overriden_parts() const;
///
///
///
- std::string register_external_package_relationship(relationship::type type, const std::string &target_uri);
+ std::string register_package_relationship(relationship::type type, const path &target_uri, target_mode mode);
///
///
///
- std::string register_external_package_relationship(relationship::type type, const std::string &target_uri, const std::string &rel_id);
+ std::string register_package_relationship(relationship::type type, const path &target_uri, target_mode mode, const std::string &rel_id);
///
///
///
- std::string register_external_relationship(const path &source_part, relationship::type type, const std::string &target_uri);
+ std::string register_part_relationship(const path &source_uri, relationship::type type, const path &target_uri, target_mode mode);
///
///
///
- std::string register_external_relationship(const path &source_part, relationship::type type, const std::string &target_uri, const std::string &rel_id);
+ std::string register_part_relationship(const path &source_uri, relationship::type type, const path &target_uri, target_mode mode, const std::string &rel_id);
///
/// Returns true if a default content type for the extension has been registered.
@@ -226,6 +202,8 @@ public:
///
std::vector get_default_type_extensions() const;
+ std::vector get_parts_with_relationships() const;
+
///
/// Returns the registered default content type for parts of the given extension.
///
@@ -248,7 +226,7 @@ private:
std::vector relationships;
};
- std::string next_package_relationship_id() const;\
+ std::string next_package_relationship_id() const;
std::string next_relationship_id(const path &part) const;
diff --git a/include/xlnt/packaging/relationship.hpp b/include/xlnt/packaging/relationship.hpp
index e60dc560..05c88e08 100644
--- a/include/xlnt/packaging/relationship.hpp
+++ b/include/xlnt/packaging/relationship.hpp
@@ -85,7 +85,6 @@ enum class XLNT_CLASS relationship_type
styles,
table_definition,
volatile_dependencies,
- workbook,
worksheet,
hyperlink,
diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp
index b7acd4fd..9858e0f0 100644
--- a/include/xlnt/workbook/workbook.hpp
+++ b/include/xlnt/workbook/workbook.hpp
@@ -373,10 +373,10 @@ public:
// serialization
- void save(std::vector &data);
- void save(const std::string &filename);
- void save(const xlnt::path &filename);
- void save(std::ostream &stream);
+ void save(std::vector &data) const;
+ void save(const std::string &filename) const;
+ void save(const xlnt::path &filename) const;
+ void save(std::ostream &stream) const;
void load(const std::vector &data);
void load(const std::string &filename);
@@ -423,7 +423,8 @@ public:
// thumbnail
- void set_thumbnail(const std::vector &thumbnail);
+ void set_thumbnail(const std::vector &thumbnail,
+ const std::string &extension, const std::string &content_type);
const std::vector &get_thumbnail() const;
// operators
diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp
index 39a95e6c..9815afb2 100644
--- a/source/cell/cell.cpp
+++ b/source/cell/cell.cpp
@@ -77,41 +77,63 @@ std::pair cast_time(const std::string &s)
{
xlnt::time result;
- try
+ std::vector time_components;
+ std::size_t prev = 0;
+ auto colon_index = s.find(':');
+
+ while (colon_index != std::string::npos)
{
- auto last_colon = s.find_last_of(':');
- if (last_colon == std::string::npos) return{ false, result };
- double seconds = std::stod(s.substr(last_colon + 1));
- result.second = static_cast(seconds);
- result.microsecond = static_cast((seconds - static_cast(result.second)) * 1e6);
-
- auto first_colon = s.find_first_of(':');
-
- if (first_colon == last_colon)
- {
- auto decimal_pos = s.find('.');
- if (decimal_pos != std::string::npos)
- {
- result.minute = std::stoi(s.substr(0, first_colon));
- }
- else
- {
- result.hour = std::stoi(s.substr(0, first_colon));
- result.minute = result.second;
- result.second = 0;
- }
- }
- else
- {
- result.hour = std::stoi(s.substr(0, first_colon));
- result.minute = std::stoi(s.substr(first_colon + 1, last_colon - first_colon - 1));
- }
+ time_components.push_back(s.substr(prev, colon_index - prev));
+ prev = colon_index + 1;
+ colon_index = s.find(':', colon_index + 1);
}
- catch (std::invalid_argument)
+
+ time_components.push_back(s.substr(prev, colon_index - prev));
+
+ if (time_components.size() < 2 || time_components.size() > 3)
{
return{ false, result };
}
+ std::vector numeric_components;
+
+ for (auto component : time_components)
+ {
+ if (component.empty() || (component.substr(0, component.find('.')).size() > 2))
+ {
+ return{ false, result };
+ }
+
+ for (auto d : component)
+ {
+ if (!(d >= '0' && d <= '9') && d != '.')
+ {
+ return{ false, result };
+ }
+ }
+
+ auto without_leading_zero = component.front() == '0' ? component.substr(1) : component;
+ auto numeric = std::stod(without_leading_zero);
+
+ numeric_components.push_back(numeric);
+ }
+
+ result.hour = static_cast(numeric_components[0]);
+ result.minute = static_cast(numeric_components[1]);
+
+ if (result.minute != numeric_components[1])
+ {
+ result.minute = result.hour;
+ result.hour = 0;
+ result.second = static_cast(numeric_components[1]);
+ result.microsecond = static_cast((numeric_components[1] - result.second) * 1E6);
+ }
+ else if (numeric_components.size() > 2)
+ {
+ result.second = static_cast(numeric_components[2]);
+ result.microsecond = static_cast((numeric_components[2] - result.second) * 1E6);
+ }
+
return{ true, result };
}
@@ -453,9 +475,9 @@ void cell::set_hyperlink(const std::string &hyperlink)
void cell::set_formula(const std::string &formula)
{
- if (formula.length() == 0)
+ if (formula.empty())
{
- throw invalid_data_type();
+ throw invalid_parameter();
}
if (formula[0] == '=')
@@ -477,7 +499,7 @@ std::string cell::get_formula() const
{
if (d_->formula_.empty())
{
- throw invalid_data_type();
+ throw invalid_attribute();
}
return d_->formula_;
diff --git a/source/cell/tests/test_cell.hpp b/source/cell/tests/test_cell.hpp
index 211ebc47..d625956b 100644
--- a/source/cell/tests/test_cell.hpp
+++ b/source/cell/tests/test_cell.hpp
@@ -139,8 +139,8 @@ public:
auto cell = ws.get_cell(xlnt::cell_reference(1, 1));
TS_ASSERT(!cell.has_formula());
- TS_ASSERT_THROWS(cell.set_formula(""), std::runtime_error);
- TS_ASSERT_THROWS(cell.get_formula(), std::runtime_error);
+ TS_ASSERT_THROWS(cell.set_formula(""), xlnt::invalid_parameter);
+ TS_ASSERT_THROWS(cell.get_formula(), xlnt::invalid_attribute);
cell.set_formula("=42");
TS_ASSERT(cell.has_formula());
TS_ASSERT_EQUALS(cell.get_formula(), "42");
diff --git a/source/detail/stylesheet.hpp b/source/detail/stylesheet.hpp
index 820f491c..b2697844 100644
--- a/source/detail/stylesheet.hpp
+++ b/source/detail/stylesheet.hpp
@@ -37,7 +37,7 @@
namespace {
template
-std::size_t search_vector(const std::vector &items, const T &to_find)
+std::size_t index(const std::vector &items, const T &to_find)
{
auto match = std::find(items.begin(), items.end(), to_find);
@@ -49,6 +49,13 @@ std::size_t search_vector(const std::vector &items, const T &to_find)
return std::distance(items.begin(), match);
}
+template
+bool contains(const std::vector &items, const T &to_find)
+{
+ auto match = std::find(items.begin(), items.end(), to_find);
+ return match != items.end();
+}
+
} // namespace
namespace xlnt {
@@ -58,7 +65,10 @@ struct stylesheet
{
~stylesheet() {}
- std::size_t index(const format &f) { return search_vector(formats, f); }
+ std::size_t index(const format &f)
+ {
+ return ::index(formats, f);
+ }
std::size_t index(const std::string &style_name)
{
@@ -72,11 +82,6 @@ struct stylesheet
return std::distance(styles.begin(), match);
}
-
- std::size_t index(const border &b) { return search_vector(borders, b); }
- std::size_t index(const fill &f) { return search_vector(fills, f); }
- std::size_t index(const font &f) { return search_vector(fonts, f); }
- std::size_t index(const number_format &f) { return search_vector(number_formats, f); }
std::size_t add_format(const format &f)
{
@@ -97,43 +102,24 @@ struct stylesheet
formats.push_back(f);
format_styles.push_back("Normal");
- try
- {
- search_vector(borders, f.get_border());
- }
- catch(std::out_of_range)
+ if (!contains(borders, f.get_border()))
{
borders.push_back(f.get_border());
}
- try
- {
- search_vector(fills, f.get_fill());
- }
- catch(std::out_of_range)
- {
- fills.push_back(f.get_fill());
- }
+ if (!contains(fills, f.get_fill()))
+ {
+ fills.push_back(f.get_fill());
+ }
+
+ if (!contains(fonts, f.get_font()))
+ {
+ fonts.push_back(f.get_font());
+ }
- try
+ if (f.get_number_format().get_id() >= 164 && !contains(number_formats, f.get_number_format()))
{
- search_vector(fonts, f.get_font());
- }
- catch(std::out_of_range)
- {
- fonts.push_back(f.get_font());
- }
-
- if (f.get_number_format().get_id() >= 164)
- {
- try
- {
- search_vector(number_formats, f.get_number_format());
- }
- catch(std::out_of_range)
- {
- number_formats.push_back(f.get_number_format());
- }
+ number_formats.push_back(f.get_number_format());
}
return formats.size() - 1;
diff --git a/source/detail/workbook_impl.hpp b/source/detail/workbook_impl.hpp
index 34f3dcac..7379a1af 100644
--- a/source/detail/workbook_impl.hpp
+++ b/source/detail/workbook_impl.hpp
@@ -22,8 +22,9 @@
// @author: see AUTHORS file
#pragma once
-#include
#include
+#include
+#include
#include
#include
@@ -92,7 +93,8 @@ struct workbook_impl
links_up_to_date_(other.links_up_to_date_),
shared_doc_(other.shared_doc_),
hyperlinks_changed_(other.hyperlinks_changed_),
- app_version_(other.app_version_)
+ app_version_(other.app_version_),
+ sheet_title_rel_id_map_(other.sheet_title_rel_id_map_)
{
}
@@ -131,6 +133,8 @@ struct workbook_impl
hyperlinks_changed_ = other.hyperlinks_changed_;
app_version_ = other.app_version_;
+ sheet_title_rel_id_map_ = other.sheet_title_rel_id_map_;
+
return *this;
}
@@ -173,6 +177,8 @@ struct workbook_impl
bool shared_doc_;
bool hyperlinks_changed_;
std::string app_version_;
+
+ std::unordered_map sheet_title_rel_id_map_;
};
} // namespace detail
diff --git a/source/detail/xlsx_consumer.cpp b/source/detail/xlsx_consumer.cpp
index 7bb2087c..45c9165b 100644
--- a/source/detail/xlsx_consumer.cpp
+++ b/source/detail/xlsx_consumer.cpp
@@ -708,18 +708,21 @@ xlsx_consumer::xlsx_consumer(workbook &destination) : destination_(destination)
void xlsx_consumer::read(const path &source)
{
+ destination_.clear();
source_.load(source);
populate_workbook();
}
void xlsx_consumer::read(std::istream &source)
{
+ destination_.clear();
source_.load(source);
populate_workbook();
}
void xlsx_consumer::read(const std::vector &source)
{
+ destination_.clear();
source_.load(source);
populate_workbook();
}
@@ -729,10 +732,8 @@ void xlsx_consumer::read(const std::vector &source)
void xlsx_consumer::populate_workbook()
{
auto &manifest = destination_.get_manifest();
- manifest.clear();
- destination_.d_->worksheets_.clear();
-
read_manifest();
+ path workbook_part;
for (const auto &rel : manifest.get_package_relationships())
{
@@ -751,13 +752,14 @@ void xlsx_consumer::populate_workbook()
read_custom_property(document.root());
break;
case relationship::type::office_document:
- check_document_type(manifest.get_part_content_type_string(rel.get_target_uri()));
+ check_document_type(manifest.get_content_type_string(rel.get_target_uri()));
+ workbook_part = rel.get_target_uri();
read_workbook(document.root());
break;
}
}
- for (const auto &rel : manifest.get_part_relationships(constants::part_workbook()))
+ for (const auto &rel : manifest.get_part_relationships(workbook_part))
{
pugi::xml_document document;
document.load_string(source_.read(path(rel.get_target_uri())).c_str());
@@ -767,18 +769,12 @@ void xlsx_consumer::populate_workbook()
case relationship::type::calculation_chain:
read_calculation_chain(document.root());
break;
- case relationship::type::chartsheet:
- read_chartsheet(document.root(), rel.get_id());
- break;
case relationship::type::connections:
read_connections(document.root());
break;
case relationship::type::custom_xml_mappings:
read_custom_xml_mappings(document.root());
break;
- case relationship::type::dialogsheet:
- read_dialogsheet(document.root(), rel.get_id());
- break;
case relationship::type::external_workbook_references:
read_external_workbook_references(document.root());
break;
@@ -795,7 +791,7 @@ void xlsx_consumer::populate_workbook()
read_shared_workbook_revision_headers(document.root());
break;
case relationship::type::styles:
- read_styles(document.root());
+ read_stylesheet(document.root());
break;
case relationship::type::theme:
read_theme(document.root());
@@ -803,6 +799,22 @@ void xlsx_consumer::populate_workbook()
case relationship::type::volatile_dependencies:
read_volatile_dependencies(document.root());
break;
+ }
+ }
+
+ for (const auto &rel : manifest.get_part_relationships(workbook_part))
+ {
+ pugi::xml_document document;
+ document.load_string(source_.read(path(rel.get_target_uri())).c_str());
+
+ switch (rel.get_type())
+ {
+ case relationship::type::chartsheet:
+ read_chartsheet(document.root(), rel.get_id());
+ break;
+ case relationship::type::dialogsheet:
+ read_dialogsheet(document.root(), rel.get_id());
+ break;
case relationship::type::worksheet:
read_worksheet(document.root(), rel.get_id());
break;
@@ -818,38 +830,15 @@ void xlsx_consumer::populate_workbook()
void read_unknown_parts();
void read_unknown_relationships();
-
- auto current_iter = destination_.d_->worksheets_.begin();
- for (std::size_t current_index = 0; current_index < destination_.get_sheet_titles().size(); ++current_index)
- {
- auto current_id = current_iter->id_;
-
- for (const auto j : worksheet_rel_title_id_index_map_)
- {
- if (std::get<1>(j.second) == current_id)
- {
- if (std::get<2>(j.second) == current_index) break;
-
- auto switch_iter = destination_.d_->worksheets_.begin();
-
- for (std::size_t k = 0; k < std::get<2>(j.second); ++k)
- {
- ++switch_iter;
- }
-
- std::swap(*switch_iter, *current_iter);
- }
- }
-
- ++current_iter;
- }
}
// Package Parts
void xlsx_consumer::read_manifest()
{
- auto package_rels = read_relationships(path("_rels/.rels"), source_);
+ path package_rels_path("_rels/.rels");
+ if (!source_.has_file(package_rels_path)) throw invalid_file("missing package rels");
+ auto package_rels = read_relationships(package_rels_path, source_);
pugi::xml_document document;
document.load_string(source_.read(path("[Content_Types].xml")).c_str());
@@ -857,8 +846,6 @@ void xlsx_consumer::read_manifest()
const auto root_node = document.child("Types");
auto &manifest = destination_.get_manifest();
- std::unordered_map> part_types;
-
auto make_relative = [](const path &p)
{
path copy;
@@ -881,30 +868,32 @@ void xlsx_consumer::read_manifest()
else if (child.name() == std::string("Override"))
{
path part(child.attribute("PartName").value());
- part_types[make_relative(part)] = child.attribute("ContentType").value();
+ manifest.register_override_type(part, child.attribute("ContentType").value());
}
}
for (const auto &package_rel : package_rels)
{
- manifest.register_package_part(package_rel.get_target_uri(),
- part_types.at(package_rel.get_target_uri()), package_rel.get_type());
+ manifest.register_package_relationship(package_rel.get_type(),
+ package_rel.get_target_uri(),
+ package_rel.get_target_mode(),
+ package_rel.get_id());
}
- for (const auto &relationship_source : part_types)
+ for (const auto &relationship_source : source_.infolist())
{
- auto rels_name = relationship_source.first.parent()
- .append("_rels")
- .append(relationship_source.first.basename() + ".rels");
- auto part_rels = read_relationships(rels_name, source_);
+ if (relationship_source.filename == path("_rels/.rels")
+ || relationship_source.filename.extension() != ".rels") continue;
- if (part_rels.empty()) continue;
+ auto part_rels = read_relationships(relationship_source.filename, source_);
+ auto source_uri = relationship_source.filename.parent().parent()
+ .append(relationship_source.filename.basename());
for (const auto part_rel : part_rels)
{
- auto part = relationship_source.first.parent().append(part_rel.get_target_uri());
- relationship new_part_rel(part_rel.get_id(), part_rel.get_type(), part, target_mode::internal);
- manifest.register_part(relationship_source.first, new_part_rel, part_types.at(part));
+ auto part = source_uri;
+ manifest.register_part_relationship(source_uri, part_rel.get_type(),
+ part_rel.get_target_uri(), part_rel.get_target_mode(), part_rel.get_id());
}
}
}
@@ -965,14 +954,16 @@ void xlsx_consumer::read_workbook(const pugi::xml_node root)
}
}
+ std::size_t index = 0;
for (auto sheet_node : workbook_node.child("sheets").children("sheet"))
{
std::string rel_id(sheet_node.attribute("r:id").value());
std::string title(sheet_node.attribute("name").value());
auto id = string_to_size_t(sheet_node.attribute("sheetId").value());
- worksheet_rel_title_id_index_map_[rel_id] =
- { title, id, worksheet_rel_title_id_index_map_.size() };
+ sheet_title_id_map_[rel_id] = id;
+ sheet_title_index_map_[rel_id] = index++;
+ destination_.d_->sheet_title_rel_id_map_[title] = rel_id;
}
}
@@ -1135,21 +1126,18 @@ void xlsx_consumer::read_shared_workbook_user_data(const pugi::xml_node root)
auto root_node = document.append_child("users");
}
-void xlsx_consumer::read_styles(const pugi::xml_node root)
+void xlsx_consumer::read_stylesheet(const pugi::xml_node root)
{
- pugi::xml_document document;
-
- auto stylesheet_node = document.child("styleSheet");
-
+ auto stylesheet_node = root.child("styleSheet");
auto &stylesheet = destination_.impl().stylesheet_;
- ::read_borders(stylesheet_node.child("borders"), stylesheet.borders);
- ::read_fills(stylesheet_node.child("fills"), stylesheet.fills);
- ::read_fonts(stylesheet_node.child("fonts"), stylesheet.fonts);
- ::read_number_formats(stylesheet_node.child("numFmts"), stylesheet.number_formats);
- ::read_colors(stylesheet_node.child("colors"), stylesheet.colors);
- ::read_styles(stylesheet_node.child("cellStyles"), stylesheet_node.child("cellStyleXfs"), stylesheet, stylesheet.styles, stylesheet.style_name_map);
- ::read_formats(stylesheet_node.child("cellXfs"), stylesheet, stylesheet.formats, stylesheet.format_styles);
+ read_borders(stylesheet_node.child("borders"), stylesheet.borders);
+ read_fills(stylesheet_node.child("fills"), stylesheet.fills);
+ read_fonts(stylesheet_node.child("fonts"), stylesheet.fonts);
+ read_number_formats(stylesheet_node.child("numFmts"), stylesheet.number_formats);
+ read_colors(stylesheet_node.child("colors"), stylesheet.colors);
+ read_styles(stylesheet_node.child("cellStyles"), stylesheet_node.child("cellStyleXfs"), stylesheet, stylesheet.styles, stylesheet.style_name_map);
+ read_formats(stylesheet_node.child("cellXfs"), stylesheet, stylesheet.formats, stylesheet.format_styles);
}
void xlsx_consumer::read_theme(const pugi::xml_node root)
@@ -1167,10 +1155,24 @@ void xlsx_consumer::read_volatile_dependencies(const pugi::xml_node root)
void xlsx_consumer::read_worksheet(const pugi::xml_node root, const std::string &rel_id)
{
- auto title = std::get<0>(worksheet_rel_title_id_index_map_[rel_id]);
- auto id = std::get<1>(worksheet_rel_title_id_index_map_[rel_id]);
+ auto title = std::find_if(destination_.d_->sheet_title_rel_id_map_.begin(),
+ destination_.d_->sheet_title_rel_id_map_.end(),
+ [&](const std::pair &p)
+ {
+ return p.second == rel_id;
+ })->first;
- destination_.d_->worksheets_.emplace_back(&destination_, id, title);
+ auto id = sheet_title_id_map_[title];
+ auto index = sheet_title_index_map_[title];
+
+ auto insertion_iter = destination_.d_->worksheets_.begin();
+ while (insertion_iter != destination_.d_->worksheets_.end()
+ && sheet_title_index_map_[insertion_iter->title_] < index)
+ {
+ ++insertion_iter;
+ }
+
+ destination_.d_->worksheets_.emplace(insertion_iter, &destination_, id, title);
auto ws = destination_.get_sheet_by_id(id);
diff --git a/source/detail/xlsx_consumer.hpp b/source/detail/xlsx_consumer.hpp
index a6bd31ee..bd8c4adf 100644
--- a/source/detail/xlsx_consumer.hpp
+++ b/source/detail/xlsx_consumer.hpp
@@ -86,7 +86,7 @@ private:
void read_shared_workbook_revision_headers(const pugi::xml_node root);
void read_shared_workbook(const pugi::xml_node root);
void read_shared_workbook_user_data(const pugi::xml_node root);
- void read_styles(const pugi::xml_node root);
+ void read_stylesheet(const pugi::xml_node root);
void read_theme(const pugi::xml_node root);
void read_volatile_dependencies(const pugi::xml_node root);
@@ -110,11 +110,8 @@ private:
///
zip_file source_;
- ///
- /// Worksheet titles from workbook.xml are saved here so we know what its
- /// title is when readind the associated worksheet XML.
- ///
- std::unordered_map> worksheet_rel_title_id_index_map_;
+ std::unordered_map sheet_title_id_map_;
+ std::unordered_map sheet_title_index_map_;
///
/// A reference to the workbook which is being read.
diff --git a/source/detail/xlsx_producer.cpp b/source/detail/xlsx_producer.cpp
index 0b72328f..05f90532 100644
--- a/source/detail/xlsx_producer.cpp
+++ b/source/detail/xlsx_producer.cpp
@@ -180,14 +180,14 @@ std::string to_string(xlnt::horizontal_alignment horizontal_alignment)
}
}
-void write_relationships(const std::vector &relationships, pugi::xml_document &document)
+void write_relationships(const std::vector &relationships, pugi::xml_node root)
{
- auto root_node = document.append_child("Relationships");
- root_node.append_attribute("xmlns").set_value(xlnt::constants::get_namespace("relationships").c_str());
+ auto relationships_node = root.append_child("Relationships");
+ relationships_node.append_attribute("xmlns").set_value(xlnt::constants::get_namespace("relationships").c_str());
for (const auto &relationship : relationships)
{
- auto relationship_node = root_node.append_child("Relationship");
+ auto relationship_node = relationships_node.append_child("Relationship");
relationship_node.append_attribute("Id").set_value(relationship.get_id().c_str());
relationship_node.append_attribute("Type").set_value(to_string(relationship.get_type()).c_str());
@@ -565,104 +565,113 @@ xlsx_producer::xlsx_producer(const workbook &target) : source_(target)
void xlsx_producer::write(const path &destination)
{
- xlnt::zip_file archive;
- populate_archive(destination_);
- archive.save(destination);
+ populate_archive();
+ destination_.save(destination);
}
void xlsx_producer::write(std::ostream &destination)
{
- xlnt::zip_file archive;
- populate_archive(destination_);
- archive.save(destination);
+ populate_archive();
+ destination_.save(destination);
}
void xlsx_producer::write(std::vector &destination)
{
- xlnt::zip_file archive;
- populate_archive(destination_);
- archive.save(destination);
+ populate_archive();
+ destination_.save(destination);
}
// Part Writing Methods
-void xlsx_producer::populate_archive(zip_file &destination_)
+void xlsx_producer::populate_archive()
{
- write_package_relationships();
- write_content_types();
- write_workbook();
- write_workbook_relationships();
+ write_manifest();
+ path workbook_part;
for (auto &rel : source_.impl().manifest_.get_package_relationships())
{
+ pugi::xml_document document;
+
switch (rel.get_type())
{
case relationship::type::core_properties:
- write_core_properties();
+ write_core_properties(document.root());
break;
case relationship::type::extended_properties:
- write_app_properties();
+ write_extended_properties(document.root());
break;
case relationship::type::custom_properties:
- write_custom_property();
+ write_custom_properties(document.root());
break;
+ case relationship::type::office_document:
+ write_workbook(document.root());
+ workbook_part = rel.get_target_uri();
+ break;
+ case relationship::type::thumbnail:
+ destination_.write_string(
+ std::string(source_.get_thumbnail().begin(), source_.get_thumbnail().end()),
+ rel.get_target_uri());
+ continue;
}
+
+ write_document_to_archive(document, rel.get_target_uri(), destination_);
}
- for (auto rel : source_.impl().manifest_.get_part_relationships(constants::part_workbook()))
+ for (auto rel : source_.impl().manifest_.get_part_relationships(workbook_part))
{
+ pugi::xml_document document;
+
switch (rel.get_type())
{
case relationship::type::calculation_chain:
- write_calculation_chain();
+ write_calculation_chain(document.root());
break;
case relationship::type::chartsheet:
- write_chartsheet(rel);
+ write_chartsheet(document.root(), rel);
break;
case relationship::type::connections:
- write_connections();
+ write_connections(document.root());
break;
case relationship::type::custom_xml_mappings:
- write_custom_xml_mappings();
+ write_custom_xml_mappings(document.root());
break;
case relationship::type::dialogsheet:
- write_dialogsheet(rel);
+ write_dialogsheet(document.root(), rel);
break;
case relationship::type::external_workbook_references:
- write_external_workbook_references();
+ write_external_workbook_references(document.root());
break;
case relationship::type::metadata:
- write_metadata();
+ write_metadata(document.root());
break;
case relationship::type::pivot_table:
- write_pivot_table();
+ write_pivot_table(document.root());
break;
case relationship::type::shared_string_table:
- write_shared_string_table();
+ write_shared_string_table(document.root());
break;
case relationship::type::shared_workbook_revision_headers:
- write_shared_workbook_revision_headers();
+ write_shared_workbook_revision_headers(document.root());
break;
case relationship::type::styles:
- write_styles();
+ write_styles(document.root());
break;
case relationship::type::theme:
- write_theme();
+ write_theme(document.root());
break;
case relationship::type::volatile_dependencies:
- write_volatile_dependencies();
+ write_volatile_dependencies(document.root());
break;
case relationship::type::worksheet:
- write_worksheet(rel);
+ write_worksheet(document.root(), rel);
break;
}
+
+ std::ostringstream document_stream;
+ document.save(document_stream);
+ destination_.write_string(document_stream.str(), rel.get_target_uri());
}
- // Sheet Relationship Target Parts
-
- void write_comments();
- void write_drawings();
-
// Unknown Parts
void write_unknown_parts();
@@ -671,30 +680,11 @@ void xlsx_producer::populate_archive(zip_file &destination_)
// Package Parts
-void xlsx_producer::write_package_relationships()
+void xlsx_producer::write_manifest()
{
- pugi::xml_document document;
+ pugi::xml_document content_types_document;
- auto relationships_node = document.append_child("Relationships");
- relationships_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/package/2006/relationships");
-
- for (const auto &relationship : source_.impl().manifest_.get_package_relationships())
- {
- auto relationship_node = relationships_node.append_child("Relationship");
-
- relationship_node.append_attribute("Id").set_value(relationship.get_id().c_str());
- relationship_node.append_attribute("Type").set_value(to_string(relationship.get_type()).c_str());
- relationship_node.append_attribute("Target").set_value(relationship.get_target_uri().to_string('/').c_str());
- }
-
- write_document_to_archive(document, xlnt::constants::part_root_relationships(), destination_);
-}
-
-void xlsx_producer::write_content_types()
-{
- pugi::xml_document document;
-
- auto types_node = document.append_child("Types");
+ auto types_node = content_types_document.append_child("Types");
types_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/package/2006/content-types");
for (const auto &extension : source_.get_manifest().get_default_type_extensions())
@@ -705,44 +695,57 @@ void xlsx_producer::write_content_types()
default_node.append_attribute("ContentType").set_value(content_type.c_str());
}
- for (const auto &part : source_.get_manifest().get_parts())
+ for (const auto &part : source_.get_manifest().get_overriden_parts())
{
auto override_node = types_node.append_child("Override");
- override_node.append_attribute("PartName").set_value(part.to_string('/').c_str());
- auto content_type = source_.get_manifest().get_part_content_type_string(part);
+ override_node.append_attribute("PartName").set_value(("/" + part.to_string('/')).c_str());
+ auto content_type = source_.get_manifest().get_content_type_string(part);
override_node.append_attribute("ContentType").set_value(content_type.c_str());
}
- write_document_to_archive(document, xlnt::constants::part_content_types(), destination_);
+ for (const auto &part : source_.get_manifest().get_parts_with_relationships())
+ {
+ auto part_rels = source_.get_manifest().get_part_relationships(part);
+
+ pugi::xml_document part_rels_document;
+ write_relationships(part_rels, part_rels_document.root());
+ path rels_path = part.parent().append("_rels").append(part.basename() + ".rels");
+ write_document_to_archive(part_rels_document, rels_path, destination_);
+ }
+
+ write_document_to_archive(content_types_document, path("[Content_Types].xml"), destination_);
+
+ pugi::xml_document package_rels_document;
+ write_relationships(source_.get_manifest().get_package_relationships(), package_rels_document);
+ write_document_to_archive(package_rels_document, path("_rels/.rels"), destination_);
}
-void xlsx_producer::write_app_properties()
+void xlsx_producer::write_extended_properties(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("Properties");
+ auto properties_node = root.append_child("Properties");
- root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
- root_node.append_attribute("xmlns:vt").set_value("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
+ properties_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
+ properties_node.append_attribute("xmlns:vt").set_value("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
- root_node.append_child("Application").text().set(source_.get_application().c_str());
- root_node.append_child("DocSecurity").text().set(std::to_string(source_.get_doc_security()).c_str());
- root_node.append_child("ScaleCrop").text().set(source_.get_scale_crop() ? "true" : "false");
+ properties_node.append_child("Application").text().set(source_.get_application().c_str());
+ properties_node.append_child("DocSecurity").text().set(std::to_string(source_.get_doc_security()).c_str());
+ properties_node.append_child("ScaleCrop").text().set(source_.get_scale_crop() ? "true" : "false");
- auto company_node = root_node.append_child("Company");
+ auto company_node = properties_node.append_child("Company");
if (!source_.get_company().empty())
{
company_node.text().set(source_.get_company().c_str());
}
- root_node.append_child("LinksUpToDate").text().set(source_.links_up_to_date() ? "true" : "false");
- root_node.append_child("SharedDoc").text().set(source_.is_shared_doc() ? "true" : "false");
- root_node.append_child("HyperlinksChanged").text().set(source_.hyperlinks_changed() ? "true" : "false");
- root_node.append_child("AppVersion").text().set(source_.get_app_version().c_str());
+ properties_node.append_child("LinksUpToDate").text().set(source_.links_up_to_date() ? "true" : "false");
+ properties_node.append_child("SharedDoc").text().set(source_.is_shared_doc() ? "true" : "false");
+ properties_node.append_child("HyperlinksChanged").text().set(source_.hyperlinks_changed() ? "true" : "false");
+ properties_node.append_child("AppVersion").text().set(source_.get_app_version().c_str());
// TODO what is this stuff?
- auto heading_pairs_node = root_node.append_child("HeadingPairs");
+ auto heading_pairs_node = properties_node.append_child("HeadingPairs");
auto heading_pairs_vector_node = heading_pairs_node.append_child("vt:vector");
heading_pairs_vector_node.append_attribute("size").set_value("2");
heading_pairs_vector_node.append_attribute("baseType").set_value("variant");
@@ -751,7 +754,7 @@ void xlsx_producer::write_app_properties()
.append_child("vt:i4")
.text().set(std::to_string(source_.get_sheet_titles().size()).c_str());
- auto titles_of_parts_node = root_node.append_child("TitlesOfParts");
+ auto titles_of_parts_node = properties_node.append_child("TitlesOfParts");
auto titles_of_parts_vector_node = titles_of_parts_node.append_child("vt:vector");
titles_of_parts_vector_node.append_attribute("size").set_value(std::to_string(source_.get_sheet_titles().size()).c_str());
titles_of_parts_vector_node.append_attribute("baseType").set_value("lpstr");
@@ -760,49 +763,40 @@ void xlsx_producer::write_app_properties()
{
titles_of_parts_vector_node.append_child("vt:lpstr").text().set(ws.get_title().c_str());
}
-
- write_document_to_archive(document, xlnt::constants::part_app(), destination_);
}
-void xlsx_producer::write_core_properties()
+void xlsx_producer::write_core_properties(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("cp:coreProperties");
+ auto core_properties_node = root.append_child("cp:coreProperties");
- root_node.append_attribute("xmlns:cp").set_value("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
- root_node.append_attribute("xmlns:dc").set_value("http://purl.org/dc/elements/1.1/");
- root_node.append_attribute("xmlns:dcmitype").set_value("http://purl.org/dc/dcmitype/");
- root_node.append_attribute("xmlns:dcterms").set_value("http://purl.org/dc/terms/");
- root_node.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance");
+ core_properties_node.append_attribute("xmlns:cp").set_value("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
+ core_properties_node.append_attribute("xmlns:dc").set_value("http://purl.org/dc/elements/1.1/");
+ core_properties_node.append_attribute("xmlns:dcmitype").set_value("http://purl.org/dc/dcmitype/");
+ core_properties_node.append_attribute("xmlns:dcterms").set_value("http://purl.org/dc/terms/");
+ core_properties_node.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance");
- root_node.append_child("dc:creator").text().set(source_.get_creator().c_str());
- root_node.append_child("cp:lastModifiedBy").text().set(source_.get_last_modified_by().c_str());
- root_node.append_child("dcterms:created").text().set(datetime_to_w3cdtf(source_.get_created()).c_str());
- root_node.child("dcterms:created").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
- root_node.append_child("dcterms:modified").text().set(datetime_to_w3cdtf(source_.get_modified()).c_str());
- root_node.child("dcterms:modified").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
- root_node.append_child("dc:title").text().set(source_.get_title().c_str());
- root_node.append_child("dc:description");
- root_node.append_child("dc:subject");
- root_node.append_child("cp:keywords");
- root_node.append_child("cp:category");
-
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ core_properties_node.append_child("dc:creator").text().set(source_.get_creator().c_str());
+ core_properties_node.append_child("cp:lastModifiedBy").text().set(source_.get_last_modified_by().c_str());
+ core_properties_node.append_child("dcterms:created").text().set(datetime_to_w3cdtf(source_.get_created()).c_str());
+ core_properties_node.child("dcterms:created").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
+ core_properties_node.append_child("dcterms:modified").text().set(datetime_to_w3cdtf(source_.get_modified()).c_str());
+ core_properties_node.child("dcterms:modified").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
+ core_properties_node.append_child("dc:title").text().set(source_.get_title().c_str());
+ core_properties_node.append_child("dc:description");
+ core_properties_node.append_child("dc:subject");
+ core_properties_node.append_child("cp:keywords");
+ core_properties_node.append_child("cp:category");
}
-void xlsx_producer::write_custom_file_properties()
+void xlsx_producer::write_custom_properties(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("customFileProperties");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto properties_node = root.append_child("Properties");
}
// Write SpreadsheetML-Specific Package Parts
-void xlsx_producer::write_workbook()
+void xlsx_producer::write_workbook(pugi::xml_node root)
{
- pugi::xml_document document;
-
std::size_t num_visible = 0;
for (auto ws : source_)
@@ -818,23 +812,23 @@ void xlsx_producer::write_workbook()
throw xlnt::no_visible_worksheets();
}
- auto root_node = document.append_child("workbook");
+ auto workbook_node = root.append_child("workbook");
- root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
- root_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
+ workbook_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+ workbook_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
- auto file_version_node = root_node.append_child("fileVersion");
+ auto file_version_node = workbook_node.append_child("fileVersion");
file_version_node.append_attribute("appName").set_value("xl");
file_version_node.append_attribute("lastEdited").set_value("4");
file_version_node.append_attribute("lowestEdited").set_value("4");
file_version_node.append_attribute("rupBuild").set_value("4505");
- auto workbook_pr_node = root_node.append_child("workbookPr");
+ auto workbook_pr_node = workbook_node.append_child("workbookPr");
workbook_pr_node.append_attribute("codeName").set_value("ThisWorkbook");
workbook_pr_node.append_attribute("defaultThemeVersion").set_value("124226");
workbook_pr_node.append_attribute("date1904").set_value(source_.get_base_date() == calendar::mac_1904 ? "1" : "0");
- auto book_views_node = root_node.append_child("bookViews");
+ auto book_views_node = workbook_node.append_child("bookViews");
auto workbook_view_node = book_views_node.append_child("workbookView");
workbook_view_node.append_attribute("activeTab").set_value("0");
workbook_view_node.append_attribute("autoFilterDateGrouping").set_value("1");
@@ -846,45 +840,41 @@ void xlsx_producer::write_workbook()
workbook_view_node.append_attribute("tabRatio").set_value("600");
workbook_view_node.append_attribute("visibility").set_value("visible");
- auto sheets_node = root_node.append_child("sheets");
- auto defined_names_node = root_node.append_child("definedNames");
+ auto sheets_node = workbook_node.append_child("sheets");
+ auto defined_names_node = workbook_node.append_child("definedNames");
std::size_t index = 1;
+ auto wb_rel = source_.d_->manifest_.get_package_relationship(xlnt::relationship::type::office_document);
+
for (const auto ws : source_)
{
- path target("worksheets/sheet" + std::to_string(index++) + ".xml");
+ auto sheet_rel_id = source_.d_->sheet_title_rel_id_map_[ws.get_title()];
+ auto sheet_rel = source_.d_->manifest_.get_part_relationship(wb_rel.get_target_uri(), sheet_rel_id);
- for (const auto &rel : source_.impl().manifest_.get_part_relationships(constants::part_workbook()))
+ auto sheet_node = sheets_node.append_child("sheet");
+ sheet_node.append_attribute("name").set_value(ws.get_title().c_str());
+ sheet_node.append_attribute("sheetId").set_value(std::to_string(ws.get_id()).c_str());
+
+ if (ws.get_sheet_state() == xlnt::sheet_state::hidden)
{
- if (rel.get_target_uri().to_string('/') != target.to_string('/')) continue;
+ sheet_node.append_attribute("state").set_value("hidden");
+ }
- auto sheet_node = sheets_node.append_child("sheet");
- sheet_node.append_attribute("name").set_value(ws.get_title().c_str());
- sheet_node.append_attribute("sheetId").set_value(std::to_string(ws.get_id()).c_str());
+ sheet_node.append_attribute("r:id").set_value(sheet_rel_id.c_str());
- if (ws.get_sheet_state() == xlnt::sheet_state::hidden)
- {
- sheet_node.append_attribute("state").set_value("hidden");
- }
-
- sheet_node.append_attribute("r:id").set_value(rel.get_id().c_str());
-
- if (ws.has_auto_filter())
- {
- auto defined_name_node = defined_names_node.append_child("definedName");
- defined_name_node.append_attribute("name").set_value("_xlnm._FilterDatabase");
- defined_name_node.append_attribute("hidden").set_value("1");
- defined_name_node.append_attribute("localSheetId").set_value("0");
- std::string name =
- "'" + ws.get_title() + "'!" + range_reference::make_absolute(ws.get_auto_filter()).to_string();
- defined_name_node.text().set(name.c_str());
- }
-
- break;
+ if (ws.has_auto_filter())
+ {
+ auto defined_name_node = defined_names_node.append_child("definedName");
+ defined_name_node.append_attribute("name").set_value("_xlnm._FilterDatabase");
+ defined_name_node.append_attribute("hidden").set_value("1");
+ defined_name_node.append_attribute("localSheetId").set_value("0");
+ std::string name =
+ "'" + ws.get_title() + "'!" + range_reference::make_absolute(ws.get_auto_filter()).to_string();
+ defined_name_node.text().set(name.c_str());
}
}
- auto calc_pr_node = root_node.append_child("calcPr");
+ auto calc_pr_node = workbook_node.append_child("calcPr");
calc_pr_node.append_attribute("calcId").set_value("124519");
calc_pr_node.append_attribute("calcMode").set_value("auto");
calc_pr_node.append_attribute("fullCalcOnLoad").set_value("1");
@@ -903,110 +893,68 @@ void xlsx_producer::write_workbook()
defined_name_node.text().set(target_string.c_str());
}
*/
-
- write_document_to_archive(document, xlnt::path("workbook.xml"), destination_);
-}
-
-void xlsx_producer::write_workbook_relationships()
-{
- pugi::xml_document document;
-
- auto relationships_node = document.append_child("Relationships");
- relationships_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/package/2006/relationships");
-
- auto relationship_node = relationships_node.append_child("Relationship");
- relationship_node.append_attribute("Id").set_value("rId1");
- relationship_node.append_attribute("Type").set_value("http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet");
- relationship_node.append_attribute("Target").set_value("sheet1.xml");
-
- write_document_to_archive(document, xlnt::path("_rels/workbook.xml.rels"), destination_);
}
// Write Workbook Relationship Target Parts
-void xlsx_producer::write_calculation_chain()
+void xlsx_producer::write_calculation_chain(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("calcChain");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto calc_chain_node = root.append_child("calcChain");
}
-void xlsx_producer::write_chartsheet(const relationship &rel)
+void xlsx_producer::write_chartsheet(pugi::xml_node root, const relationship &rel)
{
- pugi::xml_document document;
- auto root_node = document.append_child("chartsheet");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto chartsheet_node = root.append_child("chartsheet");
}
-void xlsx_producer::write_connections()
+void xlsx_producer::write_connections(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("connections");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto connections_node = root.append_child("connections");
}
-void xlsx_producer::write_custom_property()
+void xlsx_producer::write_custom_xml_mappings(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("customProperty");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto map_info_node = root.append_child("MapInfo");
}
-void xlsx_producer::write_custom_xml_mappings()
+void xlsx_producer::write_dialogsheet(pugi::xml_node root, const relationship &rel)
{
- pugi::xml_document document;
- auto root_node = document.append_child("connections");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto dialogsheet_node = root.append_child("dialogsheet");
}
-void xlsx_producer::write_dialogsheet(const relationship &rel)
+void xlsx_producer::write_external_workbook_references(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("dialogsheet");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto external_link_node = root.append_child("externalLink");
}
-void xlsx_producer::write_external_workbook_references()
+void xlsx_producer::write_metadata(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("externalLink");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto metadata_node = root.append_child("metadata");
}
-void xlsx_producer::write_metadata()
+void xlsx_producer::write_pivot_table(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("metadata");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto pivot_table_definition_node = root.append_child("pivotTableDefinition");
}
-void xlsx_producer::write_pivot_table()
+void xlsx_producer::write_shared_string_table(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("pivotTableDefinition");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
-}
+ auto sst_node = root.append_child("sst");
-void xlsx_producer::write_shared_string_table()
-{
- pugi::xml_document document;
+ sst_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
- auto root_node = document.append_child("sst");
-
- root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
-
- root_node.append_attribute("count").set_value(std::to_string(source_.get_shared_strings().size()).c_str());
- root_node.append_attribute("uniqueCount").set_value(std::to_string(source_.get_shared_strings().size()).c_str());
+ sst_node.append_attribute("count").set_value(std::to_string(source_.get_shared_strings().size()).c_str());
+ sst_node.append_attribute("uniqueCount").set_value(std::to_string(source_.get_shared_strings().size()).c_str());
for (const auto &string : source_.get_shared_strings())
{
if (string.get_runs().size() == 1 && !string.get_runs().at(0).has_formatting())
{
- root_node.append_child("si").append_child("t").text().set(string.get_plain_string().c_str());
+ sst_node.append_child("si").append_child("t").text().set(string.get_plain_string().c_str());
}
else
{
- auto string_item_node = root_node.append_child("si");
+ auto string_item_node = sst_node.append_child("si");
for (const auto &run : string.get_runs())
{
@@ -1047,95 +995,81 @@ void xlsx_producer::write_shared_string_table()
}
}
}
-
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
}
-void xlsx_producer::write_shared_workbook_revision_headers()
+void xlsx_producer::write_shared_workbook_revision_headers(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("headers");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto headers_node = root.append_child("headers");
}
-void xlsx_producer::write_shared_workbook()
+void xlsx_producer::write_shared_workbook(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("revisions");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto revisions_node = root.append_child("revisions");
}
-void xlsx_producer::write_shared_workbook_user_data()
+void xlsx_producer::write_shared_workbook_user_data(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("users");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto users_node = root.append_child("users");
}
-void xlsx_producer::write_styles()
+void xlsx_producer::write_styles(pugi::xml_node root)
{
- pugi::xml_document document;
-
- auto root_node = document.append_child("styleSheet");
- root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
- root_node.append_attribute("xmlns:mc").set_value("http://schemas.openxmlformats.org/markup-compatibility/2006");
- root_node.append_attribute("mc:Ignorable").set_value("x14ac");
- root_node.append_attribute("xmlns:x14ac").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
+ auto stylesheet_node = root.append_child("styleSheet");
+ stylesheet_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+ stylesheet_node.append_attribute("xmlns:mc").set_value("http://schemas.openxmlformats.org/markup-compatibility/2006");
+ stylesheet_node.append_attribute("mc:Ignorable").set_value("x14ac");
+ stylesheet_node.append_attribute("xmlns:x14ac").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
const auto &stylesheet = source_.impl().stylesheet_;
if (!stylesheet.number_formats.empty())
{
- auto number_formats_node = root_node.append_child("numFmts");
+ auto number_formats_node = stylesheet_node.append_child("numFmts");
write_number_formats(stylesheet.number_formats, number_formats_node);
}
if (!stylesheet.fonts.empty())
{
- auto fonts_node = root_node.append_child("fonts");
+ auto fonts_node = stylesheet_node.append_child("fonts");
write_fonts(stylesheet.fonts, fonts_node);
}
if (!stylesheet.fills.empty())
{
- auto fills_node = root_node.append_child("fills");
+ auto fills_node = stylesheet_node.append_child("fills");
write_fills(stylesheet.fills, fills_node);
}
if (!stylesheet.borders.empty())
{
- auto borders_node = root_node.append_child("borders");
+ auto borders_node = stylesheet_node.append_child("borders");
write_borders(stylesheet.borders, borders_node);
}
- auto cell_style_xfs_node = root_node.append_child("cellStyleXfs");
+ auto cell_style_xfs_node = stylesheet_node.append_child("cellStyleXfs");
- auto cell_xfs_node = root_node.append_child("cellXfs");
+ auto cell_xfs_node = stylesheet_node.append_child("cellXfs");
write_formats(stylesheet, cell_xfs_node);
- auto cell_styles_node = root_node.append_child("cellStyles");
+ auto cell_styles_node = stylesheet_node.append_child("cellStyles");
::write_styles(stylesheet, cell_styles_node, cell_style_xfs_node);
- auto dxfs_node = root_node.append_child("dxfs");
+ auto dxfs_node = stylesheet_node.append_child("dxfs");
write_dxfs(dxfs_node);
- auto table_styles_node = root_node.append_child("tableStyles");
+ auto table_styles_node = stylesheet_node.append_child("tableStyles");
write_table_styles(table_styles_node);
if (!stylesheet.colors.empty())
{
- auto colors_node = root_node.append_child("colors");
+ auto colors_node = stylesheet_node.append_child("colors");
write_colors(stylesheet.colors, colors_node);
}
-
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
}
-void xlsx_producer::write_theme()
+void xlsx_producer::write_theme(pugi::xml_node root)
{
- pugi::xml_document document;
-
- auto theme_node = document.append_child("a:theme");
+ auto theme_node = root.append_child("a:theme");
theme_node.append_attribute("xmlns:a").set_value(constants::get_namespace("drawingml").c_str());
theme_node.append_attribute("name").set_value("Office Theme");
@@ -1467,191 +1401,16 @@ void xlsx_producer::write_theme()
theme_node.append_child("a:objectDefaults");
theme_node.append_child("a:extraClrSchemeLst");
-
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
}
-void xlsx_producer::write_volatile_dependencies()
+void xlsx_producer::write_volatile_dependencies(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("volTypes");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto vol_types_node = root.append_child("volTypes");
}
-/*
-bool xlsx_producer::read_worksheet(const relationship &rel)
+void xlsx_producer::write_worksheet(pugi::xml_node root, const relationship &rel)
{
- const auto ws = source_.get_active_sheet();
- auto root_node = xml.child("worksheet");
-
- auto dimension_node = root_node.child("dimension");
- std::string dimension(dimension_node.attribute("ref").value());
- auto full_range = xlnt::range_reference(dimension);
- auto sheet_data_node = root_node.child("sheetData");
-
- if (root_node.child("mergeCells"))
- {
- auto merge_cells_node = root_node.child("mergeCells");
- auto count = std::stoull(merge_cells_node.attribute("count").value());
-
- for (auto merge_cell_node : merge_cells_node.children("mergeCell"))
- {
- sheet_.merge_cells(range_reference(merge_cell_node.attribute("ref").value()));
- count--;
- }
-
- if (count != 0)
- {
- throw std::runtime_error("mismatch between count and actual number of merged cells");
- }
- }
-
- auto &shared_strings = sheet_.get_workbook().get_shared_strings();
-
- for (auto row_node : sheet_data_node.children("row"))
- {
- auto row_index = static_cast(std::stoull(row_node.attribute("r").value()));
-
- if (row_node.attribute("ht"))
- {
- sheet_.get_row_properties(row_index).height = std::stold(row_node.attribute("ht").value());
- }
-
- std::string span_string = row_node.attribute("spans").value();
- auto colon_index = span_string.find(':');
-
- column_t min_column = 0;
- column_t max_column = 0;
-
- if (colon_index != std::string::npos)
- {
- min_column = static_cast(std::stoll(span_string.substr(0, colon_index)));
- max_column = static_cast(std::stoll(span_string.substr(colon_index + 1)));
- }
- else
- {
- min_column = full_range.get_top_left().get_column_index();
- max_column = full_range.get_bottom_right().get_column_index();
- }
-
- for (column_t i = min_column; i <= max_column; i++)
- {
- std::string address = i.column_string() + std::to_string(row_index);
-
- pugi::xml_node cell_node;
- bool cell_found = false;
-
- for (auto &check_cell_node : row_node.children("c"))
- {
- if (check_cell_node.attribute("r") && check_cell_node.attribute("r").value() == address)
- {
- cell_node = check_cell_node;
- cell_found = true;
- break;
- }
- }
-
- if (cell_found)
- {
- bool has_value = cell_node.child("v") != nullptr;
- std::string value_string = has_value ? cell_node.child("v").text().get() : "";
-
- bool has_type = cell_node.attribute("t") != nullptr;
- std::string type = has_type ? cell_node.attribute("t").value() : "";
-
- bool has_format = cell_node.attribute("s") != nullptr;
- auto format_id = static_cast(has_format ? std::stoull(cell_node.attribute("s").value()) : 0LL);
-
- bool has_formula = cell_node.child("f") != nullptr;
- bool has_shared_formula = has_formula && cell_node.child("f").attribute("t") != nullptr
- && cell_node.child("f").attribute("t").value() == std::string("shared");
-
- auto cell = sheet_.get_cell(address);
-
- if (has_formula && !has_shared_formula && !sheet_.get_workbook().get_data_only())
- {
- std::string formula = cell_node.child("f").text().get();
- cell.set_formula(formula);
- }
-
- if (has_type && type == "inlineStr") // inline string
- {
- std::string inline_string = cell_node.child("is").child("t").text().get();
- cell.set_value(inline_string);
- }
- else if (has_type && type == "s" && !has_formula) // shared string
- {
- auto shared_string_index = static_cast(std::stoull(value_string));
- auto shared_string = shared_strings.at(shared_string_index);
- cell.set_value(shared_string);
- }
- else if (has_type && type == "b") // boolean
- {
- cell.set_value(value_string != "0");
- }
- else if (has_type && type == "str")
- {
- cell.set_value(value_string);
- }
- else if (has_value && !value_string.empty())
- {
- if (!value_string.empty() && value_string[0] == '#')
- {
- cell.set_error(value_string);
- }
- else
- {
- cell.set_value(std::stold(value_string));
- }
- }
-
- if (has_format)
- {
- cell.set_format(stylesheet.formats.at(format_id));
- }
- }
- }
- }
-
- auto cols_node = root_node.child("cols");
-
- for (auto col_node : cols_node.children("col"))
- {
- auto min = static_cast(std::stoull(col_node.attribute("min").value()));
- auto max = static_cast(std::stoull(col_node.attribute("max").value()));
- auto width = std::stold(col_node.attribute("width").value());
- bool custom = col_node.attribute("customWidth").value() == std::string("1");
- auto column_style = static_cast(col_node.attribute("style") ? std::stoull(col_node.attribute("style").value()) : 0);
-
- for (auto column = min; column <= max; column++)
- {
- if (!sheet_.has_column_properties(column))
- {
- sheet_.add_column_properties(column, column_properties());
- }
-
- sheet_.get_column_properties(min).width = width;
- sheet_.get_column_properties(min).style = column_style;
- sheet_.get_column_properties(min).custom = custom;
- }
- }
-
- if (root_node.child("autoFilter"))
- {
- auto auto_filter_node = root_node.child("autoFilter");
- xlnt::range_reference ref(auto_filter_node.attribute("ref").value());
- sheet_.auto_filter(ref);
- }
-
- return true;
-}
-*/
-
-void xlsx_producer::write_worksheet(const relationship &rel)
-{
- pugi::xml_document document;
-
- auto worksheet_node = document.append_child("worksheet");
+ auto worksheet_node = root.append_child("worksheet");
worksheet_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
worksheet_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/package/2006/relationships");
@@ -1661,7 +1420,14 @@ void xlsx_producer::write_worksheet(const relationship &rel)
outline_pr_node.append_attribute("summaryBelow").set_value("1");
outline_pr_node.append_attribute("summaryRight").set_value("1");
- auto ws = source_.get_sheet_by_index(0);
+ auto title = std::find_if(source_.d_->sheet_title_rel_id_map_.begin(),
+ source_.d_->sheet_title_rel_id_map_.end(),
+ [&](const std::pair &p)
+ {
+ return p.second == rel.get_id();
+ })->first;
+
+ auto ws = source_.get_sheet_by_title(title);
if (!ws.get_page_setup().is_default())
{
@@ -1821,11 +1587,6 @@ void xlsx_producer::write_worksheet(const relationship &rel)
{
if (!cell.garbage_collectible())
{
- if (cell.has_hyperlink())
- {
-// hyperlink_references[cell.get_hyperlink().get_id()] = cell.get_reference().to_string();
- }
-
auto cell_node = row_node.append_child("c");
cell_node.append_attribute("r").set_value(cell.get_reference().to_string().c_str());
@@ -1943,14 +1704,28 @@ void xlsx_producer::write_worksheet(const relationship &rel)
if (!source_.impl().manifest_.get_part_relationships(rel.get_target_uri()).empty())
{
- auto hyperlinks_node = worksheet_node.append_child("hyperlinks");
+ auto sheet_rels = source_.impl().manifest_.get_part_relationships(rel.get_target_uri());
+ std::vector hyperlink_sheet_rels;
- for (const auto &relationship : source_.impl().manifest_.get_part_relationships(rel.get_target_uri()))
+ for (const auto &sheet_rel : sheet_rels)
{
- auto hyperlink_node = hyperlinks_node.append_child("hyperlink");
- hyperlink_node.append_attribute("display").set_value(relationship.get_target_uri().to_string('/').c_str());
- hyperlink_node.append_attribute("ref").set_value(hyperlink_references.at(relationship.get_id()).c_str());
- hyperlink_node.append_attribute("r:id").set_value(relationship.get_id().c_str());
+ if (sheet_rel.get_type() == relationship::type::hyperlink)
+ {
+ hyperlink_sheet_rels.push_back(sheet_rel);
+ }
+ }
+
+ if (!hyperlink_sheet_rels.empty())
+ {
+ auto hyperlinks_node = worksheet_node.append_child("hyperlinks");
+
+ for (const auto &hyperlink_rel : hyperlink_sheet_rels)
+ {
+ auto hyperlink_node = hyperlinks_node.append_child("hyperlink");
+ hyperlink_node.append_attribute("display").set_value(hyperlink_rel.get_target_uri().to_string('/').c_str());
+ hyperlink_node.append_attribute("ref").set_value(hyperlink_references.at(hyperlink_rel.get_id()).c_str());
+ hyperlink_node.append_attribute("r:id").set_value(hyperlink_rel.get_id().c_str());
+ }
}
}
@@ -2022,40 +1797,32 @@ void xlsx_producer::write_worksheet(const relationship &rel)
"Text &P of &N";
odd_footer_node.text().set(footer_text.c_str());
}
-
- write_document_to_archive(document, rel.get_target_uri(), destination_);
}
// Sheet Relationship Target Parts
-void xlsx_producer::write_comments()
+void xlsx_producer::write_comments(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("comments");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto comments_node = root.append_child("comments");
}
-void xlsx_producer::write_drawings()
+void xlsx_producer::write_drawings(pugi::xml_node root)
{
- pugi::xml_document document;
- auto root_node = document.append_child("wsDr");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
+ auto ws_dr_node = root.append_child("wsDr");
}
-// Unknown Parts
+// Other Parts
+
+void xlsx_producer::write_custom_property()
+{
+}
void xlsx_producer::write_unknown_parts()
{
- pugi::xml_document document;
- auto root_node = document.append_child("Hmm");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
}
void xlsx_producer::write_unknown_relationships()
{
- pugi::xml_document document;
- auto root_node = document.append_child("Relationships");
- write_document_to_archive(document, xlnt::constants::part_core(), destination_);
}
} // namespace detail
diff --git a/source/detail/xlsx_producer.hpp b/source/detail/xlsx_producer.hpp
index 45504a31..41622e2d 100644
--- a/source/detail/xlsx_producer.hpp
+++ b/source/detail/xlsx_producer.hpp
@@ -27,6 +27,7 @@
#include
#include
+#include
#include
#include
@@ -57,50 +58,47 @@ private:
/// Write all files needed to create a valid XLSX file which represents all
/// data contained in workbook.
///
- void populate_archive(zip_file &archive);
+ void populate_archive();
// Package Parts
- void write_package_relationships();
- void write_content_types();
- void write_app_properties();
- void write_core_properties();
- void write_custom_file_properties();
+ void write_manifest();
+ void write_core_properties(pugi::xml_node root);
+ void write_extended_properties(pugi::xml_node root);
+ void write_custom_properties(pugi::xml_node root);
// SpreadsheetML-Specific Package Parts
- void write_workbook();
- void write_workbook_relationships();
+ void write_workbook(pugi::xml_node root);
// Workbook Relationship Target Parts
- void write_calculation_chain();
- void write_connections();
- void write_custom_property();
- void write_custom_xml_mappings();
- void write_external_workbook_references();
- void write_metadata();
- void write_pivot_table();
- void write_shared_string_table();
- void write_shared_workbook_revision_headers();
- void write_shared_workbook();
- void write_shared_workbook_user_data();
- void write_styles();
- void write_theme();
- void write_volatile_dependencies();
+ void write_calculation_chain(pugi::xml_node root);
+ void write_connections(pugi::xml_node root);
+ void write_custom_xml_mappings(pugi::xml_node root);
+ void write_external_workbook_references(pugi::xml_node root);
+ void write_metadata(pugi::xml_node root);
+ void write_pivot_table(pugi::xml_node root);
+ void write_shared_string_table(pugi::xml_node root);
+ void write_shared_workbook_revision_headers(pugi::xml_node root);
+ void write_shared_workbook(pugi::xml_node root);
+ void write_shared_workbook_user_data(pugi::xml_node root);
+ void write_styles(pugi::xml_node root);
+ void write_theme(pugi::xml_node root);
+ void write_volatile_dependencies(pugi::xml_node root);
- void write_chartsheet(const relationship &rel);
- void write_dialogsheet(const relationship &rel);
- bool read_worksheet(const relationship &rel);
- void write_worksheet(const relationship &rel);
+ void write_chartsheet(pugi::xml_node root, const relationship &rel);
+ void write_dialogsheet(pugi::xml_node root, const relationship &rel);
+ void write_worksheet(pugi::xml_node root, const relationship &rel);
// Sheet Relationship Target Parts
- void write_comments();
- void write_drawings();
+ void write_comments(pugi::xml_node root);
+ void write_drawings(pugi::xml_node root);
- // Unknown Parts
+ // Other Parts
+ void write_custom_property();
void write_unknown_parts();
void write_unknown_relationships();
diff --git a/source/packaging/manifest.cpp b/source/packaging/manifest.cpp
index d8d0380f..cae62231 100644
--- a/source/packaging/manifest.cpp
+++ b/source/packaging/manifest.cpp
@@ -169,99 +169,77 @@ std::vector manifest::get_part_relationships(const path &part, rel
return matches;
}
-content_type manifest::get_part_content_type(const path &part) const
+content_type manifest::get_content_type(const path &part) const
{
- return from_string(get_part_content_type_string(part));
+ return from_string(get_content_type_string(part));
}
-std::string manifest::get_part_content_type_string(const path &part) const
+std::string manifest::get_content_type_string(const path &part) const
{
if (part_infos_.find(part) == part_infos_.end())
{
+ auto extension = part.extension();
+
+ if (has_default_type(extension))
+ {
+ return get_default_type(extension);
+ }
+
throw key_not_found();
}
return part_infos_.at(part).content_type;
}
-void manifest::register_part(const path &part, const path &parent, const std::string &content_type, relationship::type relation)
+void manifest::register_override_type(const path &part, const std::string &content_type)
{
part_infos_[part] = { content_type, {} };
-
- relationship rel(next_package_relationship_id(), relation, part, target_mode::internal);
- part_infos_[parent].relationships.push_back(rel);
}
-void manifest::register_part(const path &parent, const relationship &rel, const std::string &content_type)
+std::string manifest::register_package_relationship(relationship::type type, const path &target_uri, target_mode mode)
{
- part_infos_[rel.get_target_uri()] = { content_type,{} };
- part_infos_[parent].relationships.push_back(rel);
+ return register_package_relationship(type, target_uri, mode, next_package_relationship_id());
}
-void manifest::register_package_part(const path &part, const std::string &content_type, relationship::type relation)
+std::string manifest::register_package_relationship(relationship::type type, const path &target_uri, target_mode mode, const std::string &rel_id)
{
- part_infos_[part] = { content_type, {} };
+ if (has_package_relationship(rel_id))
+ {
+ throw invalid_parameter();
+ }
- relationship rel(next_package_relationship_id(), relation, part, target_mode::internal);
+ relationship rel(rel_id, type, target_uri, mode);
package_relationships_.push_back(rel);
+
+ return rel_id;
}
-void manifest::unregister_part(const path &part)
+bool manifest::has_package_relationship(const std::string &rel_id) const
{
- if (part_infos_.find(part) != part_infos_.end())
+ for (const auto &rel : package_relationships_)
{
- part_infos_.erase(part);
- }
- else
- {
- throw key_not_found();
- }
-
- auto package_rels_iter = package_relationships_.begin();
-
- while (package_rels_iter != package_relationships_.end())
- {
- if (package_rels_iter->get_target_uri() == part)
+ if (rel.get_id() == rel_id)
{
- package_rels_iter = package_relationships_.erase(package_rels_iter);
- continue;
- }
-
- ++package_rels_iter;
- }
-
- for (auto ¤t_part : part_infos_)
- {
- auto rels_iter = current_part.second.relationships.begin();
-
- while (rels_iter != current_part.second.relationships.end())
- {
- if (rels_iter->get_target_uri() == part)
- {
- rels_iter = current_part.second.relationships.erase(rels_iter);
- continue;
- }
-
- ++rels_iter;
+ return true;
}
}
+
+ return false;
}
-std::vector manifest::get_parts() const
+std::vector manifest::get_overriden_parts() const
{
- std::vector parts;
+ std::vector overriden;
for (const auto &part : part_infos_)
{
- parts.push_back(part.first);
+ if (!part.second.content_type.empty())
+ {
+ overriden.push_back(part.first);
+ }
}
- return parts;
-}
-
-bool manifest::has_part(const path &part) const
-{
- return part_infos_.find(part) != part_infos_.end();
+ return overriden;
}
std::vector manifest::get_package_relationships() const
@@ -269,7 +247,7 @@ std::vector manifest::get_package_relationships() const
return package_relationships_;
}
-relationship manifest::get_package_relationship(const std::string &rel_id)
+relationship manifest::get_package_relationship(const std::string &rel_id) const
{
for (const auto rel : package_relationships_)
{
@@ -284,14 +262,12 @@ relationship manifest::get_package_relationship(const std::string &rel_id)
std::vector manifest::get_part_relationships(const path &part) const
{
- std::vector matches;
-
- for (const auto &rel : part_infos_.at(part).relationships)
+ if (part_infos_.find(part) == part_infos_.end())
{
- matches.push_back(rel);
+ throw key_not_found();
}
- return matches;
+ return part_infos_.at(part).relationships;
}
relationship manifest::get_part_relationship(const path &part, const std::string &rel_id) const
@@ -312,27 +288,30 @@ relationship manifest::get_part_relationship(const path &part, const std::string
throw key_not_found();
}
-std::string manifest::register_external_package_relationship(relationship::type type, const std::string &target_uri)
+std::vector manifest::get_parts_with_relationships() const
{
- return register_external_package_relationship(type, target_uri, next_package_relationship_id());
+ std::vector with_relationships;
+
+ for (const auto &info : part_infos_)
+ {
+ if (!info.second.relationships.empty())
+ {
+ with_relationships.push_back(info.first);
+ }
+ }
+
+ return with_relationships;
}
-std::string manifest::register_external_package_relationship(relationship::type type, const std::string &target_uri, const std::string &rel_id)
+std::string manifest::register_part_relationship(const path &source_uri, relationship::type type, const path &target_uri, target_mode mode)
{
- relationship rel(rel_id, type, path(target_uri), target_mode::external);
- package_relationships_.push_back(rel);
- return rel_id;
+ return register_part_relationship(source_uri, type, target_uri, mode, next_relationship_id(source_uri));
}
-std::string manifest::register_external_relationship(const path &source_part, relationship::type type, const std::string &target_uri)
+std::string manifest::register_part_relationship(const path &source_uri, relationship::type type, const path &target_uri, target_mode mode, const std::string &rel_id)
{
- return register_external_relationship(source_part, type, target_uri, next_relationship_id(source_part));
-}
-
-std::string manifest::register_external_relationship(const path &source_part, relationship::type type, const std::string &target_uri, const std::string &rel_id)
-{
- relationship rel(rel_id, type, path(target_uri), target_mode::external);
- part_infos_.at(source_part).relationships.push_back(rel);
+ relationship rel(rel_id, type, path(target_uri), mode);
+ part_infos_.at(source_uri).relationships.push_back(rel);
return rel_id;
}
diff --git a/source/packaging/tests/test_core.hpp b/source/packaging/tests/test_core.hpp
deleted file mode 100644
index 1410f6e8..00000000
--- a/source/packaging/tests/test_core.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#pragma once
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-class test_core : public CxxTest::TestSuite
-{
-public:
- void test_read_properties_core()
- {
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("genuine/empty.xlsx"));
-
- TS_ASSERT_EQUALS(wb.get_creator(), "*.*");
- TS_ASSERT_EQUALS(wb.get_last_modified_by(), "Charlie Clark");
- TS_ASSERT_EQUALS(wb.get_created(), xlnt::datetime(2010, 4, 9, 20, 43, 12));
- TS_ASSERT_EQUALS(wb.get_modified(), xlnt::datetime(2014, 1, 2, 14, 53, 6));
- }
-
- void test_read_sheets_titles()
- {
- const std::vector expected_titles = {"Sheet1 - Text", "Sheet2 - Numbers", "Sheet3 - Formulas", "Sheet4 - Dates"};
-
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("genuine/empty.xlsx"));
-
- TS_ASSERT_EQUALS(wb.get_sheet_titles(), expected_titles);
- }
-
- void test_read_properties_core_libre()
- {
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("genuine/empty_libre.xlsx"));
- TS_ASSERT_EQUALS(wb.get_base_date(), xlnt::calendar::windows_1900);
- }
-
- void test_read_sheets_titles_libre()
- {
- const std::vector expected_titles = {"Sheet1 - Text", "Sheet2 - Numbers", "Sheet3 - Formulas", "Sheet4 - Dates"};
-
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("genuine/empty_libre.xlsx"));
- auto title_iter = expected_titles.begin();
-
- for(auto ws : wb)
- {
- TS_ASSERT_EQUALS(ws.get_title(), *(title_iter++));
- }
- }
-
- void test_write_properties_core()
- {
- xlnt::workbook wb;
- wb.set_creator("TEST_USER");
- wb.set_last_modified_by("SOMEBODY");
- wb.set_created(xlnt::datetime(2010, 4, 1, 20, 30, 00));
- wb.set_modified(xlnt::datetime(2010, 4, 5, 14, 5, 30));
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/core.xml"),
- wb, xlnt::constants::part_core()));
- }
-
- void test_write_properties_app()
- {
- xlnt::workbook wb;
- wb.set_application("Microsoft Excel");
- wb.set_app_version("12.0000");
- wb.set_company("Company");
- wb.create_sheet();
- wb.create_sheet();
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/core.xml"),
- wb, xlnt::constants::part_core()));
- }
-};
diff --git a/source/packaging/tests/test_zip_file.hpp b/source/packaging/tests/test_zip_file.hpp
new file mode 100644
index 00000000..776d9aa5
--- /dev/null
+++ b/source/packaging/tests/test_zip_file.hpp
@@ -0,0 +1,225 @@
+#include
+#include
+#include
+
+#include
+#include "helpers/path_helper.hpp"
+#include "helpers/temporary_file.hpp"
+
+class test_zip_file : public CxxTest::TestSuite
+{
+public:
+ test_zip_file()
+ {
+ existing_file = path_helper::get_data_directory("xlsx/4_not-package.xlsx");
+ expected_string = "not-empty";
+ }
+
+ bool files_equal(const xlnt::path &left, const xlnt::path &right)
+ {
+ if(left.to_string() == right.to_string())
+ {
+ return true;
+ }
+
+ std::ifstream stream_left(left.to_string(), std::ios::binary);
+ std::ifstream stream_right(right.to_string(), std::ios::binary);
+
+ while(stream_left && stream_right)
+ {
+ if(stream_left.get() != stream_right.get())
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void test_load_file()
+ {
+ temporary_file temp_file;
+ xlnt::zip_file f(existing_file);
+ f.save(temp_file.get_path());
+ TS_ASSERT(files_equal(existing_file, temp_file.get_path()));
+ }
+
+ void test_load_stream()
+ {
+ temporary_file temp;
+
+ std::ifstream in_stream(existing_file.to_string(), std::ios::binary);
+ xlnt::zip_file f(in_stream);
+ std::ofstream out_stream(temp.get_path().to_string(), std::ios::binary);
+ f.save(out_stream);
+ out_stream.close();
+
+ TS_ASSERT(files_equal(existing_file, temp.get_path()));
+ }
+
+ void test_load_bytes()
+ {
+ temporary_file temp_file;
+
+ std::vector source_bytes;
+ std::ifstream in_stream(existing_file.to_string(), std::ios::binary);
+
+ while(in_stream)
+ {
+ source_bytes.push_back(static_cast(in_stream.get()));
+ }
+
+ xlnt::zip_file f(source_bytes);
+ f.save(temp_file.get_path());
+
+ xlnt::zip_file f2;
+ f2.load(temp_file.get_path());
+ std::vector result_bytes;
+ f2.save(result_bytes);
+
+ TS_ASSERT(source_bytes == result_bytes);
+ }
+
+ void test_reset()
+ {
+ xlnt::zip_file f(existing_file);
+
+ TS_ASSERT(!f.namelist().empty());
+
+ try
+ {
+ f.read(xlnt::path("text.txt"));
+ }
+ catch(std::exception e)
+ {
+ TS_ASSERT(false);
+ }
+
+ f.reset();
+
+ TS_ASSERT(f.namelist().empty());
+
+ try
+ {
+ f.read(xlnt::path("doesnt-exist.txt"));
+ TS_ASSERT(false);
+ }
+ catch(std::exception e)
+ {
+ }
+
+ f.write_string("b", xlnt::path("a"));
+ f.reset();
+
+ TS_ASSERT(f.namelist().empty());
+
+ f.write_string("b", xlnt::path("a"));
+
+ TS_ASSERT_DIFFERS(f.getinfo(xlnt::path("a")).file_size, 0);
+ }
+
+ void test_getinfo()
+ {
+ xlnt::zip_file f(existing_file);
+ auto info = f.getinfo(xlnt::path("text.txt"));
+ TS_ASSERT(info.filename.to_string() == "text.txt");
+ }
+
+ void test_infolist()
+ {
+ xlnt::zip_file f(existing_file);
+ TS_ASSERT_EQUALS(f.infolist().size(), 1);
+ }
+
+ void test_namelist()
+ {
+ xlnt::zip_file f(existing_file);
+ TS_ASSERT_EQUALS(f.namelist().size(), 1);
+ }
+
+ void test_open_by_name()
+ {
+ xlnt::zip_file f(existing_file);
+ std::stringstream ss;
+ ss << f.open(xlnt::path("text.txt")).rdbuf();
+ std::string result = ss.str();
+ TS_ASSERT(result == expected_string);
+ }
+
+ void test_open_by_info()
+ {
+ xlnt::zip_file f(existing_file);
+ std::stringstream ss;
+ ss << f.open(xlnt::path("text.txt")).rdbuf();
+ std::string result = ss.str();
+ TS_ASSERT(result == expected_string);
+ }
+
+
+ void test_read()
+ {
+ xlnt::zip_file f(existing_file);
+ TS_ASSERT(f.read(xlnt::path("text.txt")) == expected_string);
+ TS_ASSERT(f.read(f.getinfo(xlnt::path("text.txt"))) == expected_string);
+ }
+
+ void test_testzip()
+ {
+ xlnt::zip_file f(existing_file);
+ TS_ASSERT(!f.check_crc());
+ }
+
+ void test_write_file()
+ {
+ temporary_file temp_file;
+
+ xlnt::zip_file f;
+ auto text_file = path_helper::get_data_directory("xlsx/2_text.xlsx");
+ f.write_file(text_file);
+ f.write_file(text_file, xlnt::path("a.txt"));
+ f.save(temp_file.get_path());
+
+ xlnt::zip_file f2(temp_file.get_path());
+
+ for(auto &info : f2.infolist())
+ {
+ TS_ASSERT(f2.read(info) == expected_string);
+ }
+ }
+
+ void test_write_string()
+ {
+ xlnt::zip_file f;
+ f.write_string("a\na", xlnt::path("a.txt"));
+ xlnt::zip_info info;
+ info.filename = xlnt::path("b.txt");
+ info.date_time.year = 2014;
+ f.write_string("b\nb", info);
+
+ temporary_file temp_file;
+ f.save(temp_file.get_path());
+
+ xlnt::zip_file f2(temp_file.get_path());
+ TS_ASSERT(f2.read(xlnt::path("a.txt")) == "a\na");
+ TS_ASSERT(f2.read(f2.getinfo(xlnt::path("b.txt"))) == "b\nb");
+ }
+
+ void test_comment()
+ {
+ xlnt::zip_file f;
+ f.comment = "comment";
+ temporary_file temp_file;
+ f.save(temp_file.get_path());
+
+ xlnt::zip_file f2(temp_file.get_path());
+ TS_ASSERT(f2.comment == "comment");
+
+ xlnt::zip_file f3;
+ std::vector bytes { 1, 2, 3 };
+ TS_ASSERT_THROWS(f3.load(bytes), std::runtime_error);
+ }
+
+private:
+ xlnt::path existing_file;
+ std::string expected_string;
+};
diff --git a/source/packaging/zip_file.cpp b/source/packaging/zip_file.cpp
index f13fef1e..0b382886 100644
--- a/source/packaging/zip_file.cpp
+++ b/source/packaging/zip_file.cpp
@@ -31,6 +31,7 @@
#include
#include
+#include
namespace {
@@ -164,8 +165,19 @@ zip_file::~zip_file()
void zip_file::load(std::istream &stream)
{
+ if (!stream.good())
+ {
+ throw invalid_file("((std::istream))");
+ }
+
reset();
buffer_.assign(std::istreambuf_iterator(stream), std::istreambuf_iterator());
+
+ if (buffer_.empty())
+ {
+ throw invalid_file("((stream)) - empty file");
+ }
+
remove_comment();
start_read();
}
@@ -174,11 +186,31 @@ void zip_file::load(const path &filename)
{
filename_ = filename;
std::ifstream stream(filename.to_string(), std::ios::binary);
- load(stream);
+
+ if (!stream.good())
+ {
+ throw invalid_file(filename.to_string());
+ }
+
+ reset();
+ buffer_.assign(std::istreambuf_iterator(stream), std::istreambuf_iterator());
+
+ if (buffer_.empty())
+ {
+ throw invalid_file(filename.to_string() + " - empty file");
+ }
+
+ remove_comment();
+ start_read();
}
void zip_file::load(const std::vector &bytes)
{
+ if (bytes.empty())
+ {
+ throw invalid_file("((bytes))");
+ }
+
reset();
buffer_.assign(bytes.begin(), bytes.end());
remove_comment();
diff --git a/source/styles/tests/test_stylesheet.hpp b/source/styles/tests/test_stylesheet.hpp
deleted file mode 100644
index 23e3b3f1..00000000
--- a/source/styles/tests/test_stylesheet.hpp
+++ /dev/null
@@ -1,285 +0,0 @@
-#pragma once
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-class test_stylesheet : public CxxTest::TestSuite
-{
-public:
- void test_from_simple()
- {
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("reader/styles/simple-styles.xml"));
- }
-
- void test_from_complex()
- {
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("reader/styles/complex-styles.xml"));
- }
-
- void test_add_existing_style()
- {
- xlnt::workbook wb;
-
- auto &s = wb.create_style("test");
-
- wb.add_style(s);
-
- xlnt::style copy;
- copy = s;
-
- TS_ASSERT_EQUALS(s, copy);
- }
-
-/*
- void _test_unprotected_cell()
- {
- datadir.chdir();
- src = open ("worksheet_unprotected_style.xml");
- xml = src.read();
- node = fromstring(xml);
- stylesheet = Stylesheet.from_tree(node);
-
- styles = stylesheet.cell_styles;
- assert len(styles) == 3;
- // default is cells are locked
- assert styles[1] == StyleArray([4,0,0,0,0,0,0,0,0]);
- assert styles[2] == StyleArray([3,0,0,0,1,0,0,0,0]);
- }
-
- void _test_read_cell_style()
- {
- datadir.chdir();
- src = open("empty-workbook-styles.xml");
- xml = src.read();
- node = fromstring(xml);
- stylesheet = Stylesheet.from_tree(node);
-
- styles = stylesheet.cell_styles;
- assert len(styles) == 2;
- assert styles[1] == StyleArray([0,0,0,9,0,0,0,0,1];
- }
-
- void _test_read_xf_no_number_format()
- {
- datadir.chdir();
- src = open("no_number_format.xml");
- xml = src.read();
- node = fromstring(xml);
- stylesheet = Stylesheet.from_tree(node);
-
- styles = stylesheet.cell_styles;
- assert len(styles) == 3;
- assert styles[1] == StyleArray([1,0,1,0,0,0,0,0,0]);
- assert styles[2] == StyleArray([0,0,0,14,0,0,0,0,0]);
- }
-
- void _test_none_values()
- {
- datadir.chdir();
- src = open("none_value_styles.xml");
- xml = src.read();
- node = fromstring(xml);
- stylesheet = Stylesheet.from_tree(node);
-
- fonts = stylesheet.fonts;
- assert fonts[0].scheme is None;
- assert fonts[0].vertAlign is None;
- assert fonts[1].u is None;
- }
-
- void _test_alignment()
- {
- datadir.chdir();
- src = open("alignment_styles.xml");
- xml = src.read();
- node = fromstring(xml);
- stylesheet = Stylesheet.from_tree(node);
-
- styles = stylesheet.cell_styles;
- assert len(styles) == 3;
- assert styles[2] == StyleArray([0,0,0,0,0,2,0,0,0]);
-
- assert stylesheet.alignments == [
- Alignment(),
- Alignment(textRotation=180),
- Alignment(vertical='top', textRotation=255),
- ];
- }
-
- void _test_rgb_colors()
- {
- datadir.chdir();
- src = open("rgb_colors.xml");
- xml = src.read();
- node = fromstring(xml);
- stylesheet = Stylesheet.from_tree(node);
-
- assert len(stylesheet.colors.index) == 64;
- assert stylesheet.colors.index[0] == "00000000";
- assert stylesheet.colors.index[-1] == "00333333";
- }
-
-
- void _test_custom_number_formats()
- {
- datadir.chdir();
- src = open("styles_number_formats.xml", "rb");
- xml = src.read();
- node = fromstring(xml);
- stylesheet = Stylesheet.from_tree(node);
-
- assert stylesheet.number_formats == [
- '_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ ',
- "#,##0.00_ ",
- "yyyy/m/d;@",
- "0.00000_ "
- ];
- }
-
- void _test_assign_number_formats()
- {
- node = fromstring(
- ""
- ""
- " "
- ""
- ""
- ""
- " "
- ""
- ""
- "");
- stylesheet = Stylesheet.from_tree(node);
- styles = stylesheet.cell_styles;
-
- assert styles[0] == StyleArray([2, 0, 0, 164, 0, 1, 0, 0, 0]);
- }
-
-
- void _test_named_styles()
- {
- datadir.chdir();
- src = open("complex-styles.xml");
- xml = src.read();
- node = fromstring(xml);
- stylesheet = Stylesheet.from_tree(node);
-
- followed = stylesheet.named_styles['Followed Hyperlink'];
- assert followed.name == "Followed Hyperlink";
- assert followed.font == stylesheet.fonts[2];
- assert followed.fill == DEFAULT_EMPTY_FILL;
- assert followed.border == Border();
-
- link = stylesheet.named_styles['Hyperlink'];
- assert link.name == "Hyperlink";
- assert link.font == stylesheet.fonts[1];
- assert link.fill == DEFAULT_EMPTY_FILL;
- assert link.border == Border();
-
- normal = stylesheet.named_styles['Normal'];
- assert normal.name == "Normal";
- assert normal.font == stylesheet.fonts[0];
- assert normal.fill == DEFAULT_EMPTY_FILL;
- assert normal.border == Border();
- }
-
- void _test_no_styles()
- {
- wb1 = wb2 = Workbook();
- archive = ZipFile(BytesIO(), "a");
- apply_stylesheet(archive, wb1);
- assert wb1._cell_styles == wb2._cell_styles;
- assert wb2._named_styles == wb2._named_styles;
- }
-
- void _test_write_worksheet()
- {
- wb = Workbook()
- node = write_stylesheet(wb);
- xml = tostring(node);
-
- const std::string expected =
- ""
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- ""
- "";
-
- diff = compare_xml(xml, expected);
- assert diff is None, diff;
- }
-
- void _test_simple_styles() {
- wb = Workbook();
- wb.guess_types = True;
- ws = wb.active;
- now = datetime.date.today();
- for idx, v in enumerate(['12.34%', now, 'This is a test', '31.31415', None], 1)
- {
- ws.append([v]);
- _ = ws.cell(column=1, row=idx).style_id;
- }
-
- // set explicit formats
- ws['D9'].number_format = numbers.FORMAT_NUMBER_00;
- ws['D9'].protection = Protection(locked=True);
- ws['D9'].style_id;
- ws['E1'].protection = Protection(hidden=True);
- ws['E1'].style_id;
-
- assert len(wb._cell_styles) == 5;
- stylesheet = write_stylesheet(wb);
-
- datadir.chdir();
- reference_file = open('simple-styles.xml');
- expected = reference_file.read();
- xml = tostring(stylesheet);
- diff = compare_xml(xml, expected);
- assert diff is None, diff;
- }
- */
-};
diff --git a/source/utils/path.cpp b/source/utils/path.cpp
index 85735f6d..c9e092b1 100644
--- a/source/utils/path.cpp
+++ b/source/utils/path.cpp
@@ -187,6 +187,10 @@ path path::parent() const
{
result.parts_.pop_back();
}
+ else
+ {
+ return path("");
+ }
return result;
}
diff --git a/source/utils/tests/test_zip_file.hpp b/source/utils/tests/test_zip_file.hpp
deleted file mode 100644
index f5190625..00000000
--- a/source/utils/tests/test_zip_file.hpp
+++ /dev/null
@@ -1,254 +0,0 @@
-#include
-#include
-#include
-
-#include
-#include "helpers/path_helper.hpp"
-#include "helpers/temporary_file.hpp"
-
-class test_zip_file : public CxxTest::TestSuite
-{
-public:
- test_zip_file()
- {
- existing_file = path_helper::get_data_directory("genuine/empty.xlsx");
- expected_content_types_string = "\r\n";
- expected_atxt_string = "\nThis is cell A1 in Sheet 1This is cell G5";
- expected_printdir_string =
- " Length Date Time Name\n"
- "--------- ---------- ----- ----\n"
- " 1704 01/01/1980 00:00 [Content_Types].xml\n"
- " 588 01/01/1980 00:00 _rels/.rels\n"
- " 917 01/01/1980 00:00 docProps/app.xml\n"
- " 609 01/01/1980 00:00 docProps/core.xml\n"
- " 1254 01/01/1980 00:00 xl/_rels/workbook.xml.rels\n"
- " 169 01/01/1980 00:00 xl/calcChain.xml\n"
- " 233 01/01/1980 00:00 xl/sharedStrings.xml\n"
- " 1724 01/01/1980 00:00 xl/styles.xml\n"
- " 6995 01/01/1980 00:00 xl/theme/theme1.xml\n"
- " 898 01/01/1980 00:00 xl/workbook.xml\n"
- " 1068 07/21/2016 20:27 xl/worksheets/sheet1.xml\n"
- " 4427 01/01/1980 00:00 xl/worksheets/sheet2.xml\n"
- " 1032 01/01/1980 00:00 xl/worksheets/sheet3.xml\n"
- " 1231 01/01/1980 00:00 xl/worksheets/sheet4.xml\n"
- "--------- -------\n"
- " 22849 14 files\n";
- }
-
- bool files_equal(const xlnt::path &left, const xlnt::path &right)
- {
- if(left.to_string() == right.to_string())
- {
- return true;
- }
-
- std::ifstream stream_left(left.to_string(), std::ios::binary);
- std::ifstream stream_right(right.to_string(), std::ios::binary);
-
- while(stream_left && stream_right)
- {
- if(stream_left.get() != stream_right.get())
- {
- return false;
- }
- }
-
- return true;
- }
-
- void test_load_file()
- {
- temporary_file temp_file;
- xlnt::zip_file f(existing_file);
- f.save(temp_file.get_path());
- TS_ASSERT(files_equal(existing_file, temp_file.get_path()));
- }
-
- void test_load_stream()
- {
- temporary_file temp;
-
- std::ifstream in_stream(existing_file.to_string(), std::ios::binary);
- xlnt::zip_file f(in_stream);
- std::ofstream out_stream(temp.get_path().to_string(), std::ios::binary);
- f.save(out_stream);
- out_stream.close();
-
- TS_ASSERT(files_equal(existing_file, temp.get_path()));
- }
-
- void test_load_bytes()
- {
- temporary_file temp_file;
-
- std::vector source_bytes;
- std::ifstream in_stream(existing_file.to_string(), std::ios::binary);
-
- while(in_stream)
- {
- source_bytes.push_back(static_cast(in_stream.get()));
- }
-
- xlnt::zip_file f(source_bytes);
- f.save(temp_file.get_path());
-
- xlnt::zip_file f2;
- f2.load(temp_file.get_path());
- std::vector result_bytes;
- f2.save(result_bytes);
-
- TS_ASSERT(source_bytes == result_bytes);
- }
-
- void test_reset()
- {
- xlnt::zip_file f(existing_file);
-
- TS_ASSERT(!f.namelist().empty());
-
- try
- {
- f.read(xlnt::path("[Content_Types].xml"));
- }
- catch(std::exception e)
- {
- TS_ASSERT(false);
- }
-
- f.reset();
-
- TS_ASSERT(f.namelist().empty());
-
- try
- {
- f.read(xlnt::path("[Content_Types].xml"));
- TS_ASSERT(false);
- }
- catch(std::exception e)
- {
- }
-
- f.write_string("b", xlnt::path("a"));
- f.reset();
-
- TS_ASSERT(f.namelist().empty());
-
- f.write_string("b", xlnt::path("a"));
-
- TS_ASSERT_DIFFERS(f.getinfo(xlnt::path("a")).file_size, 0);
- }
-
- void test_getinfo()
- {
- xlnt::zip_file f(existing_file);
- auto info = f.getinfo(xlnt::path("[Content_Types].xml"));
- TS_ASSERT(info.filename.to_string() == "[Content_Types].xml");
- }
-
- void test_infolist()
- {
- xlnt::zip_file f(existing_file);
- TS_ASSERT_EQUALS(f.infolist().size(), 14);
- }
-
- void test_namelist()
- {
- xlnt::zip_file f(existing_file);
- TS_ASSERT_EQUALS(f.namelist().size(), 14);
- }
-
- void test_open_by_name()
- {
- xlnt::zip_file f(existing_file);
- std::stringstream ss;
- ss << f.open(xlnt::path("[Content_Types].xml")).rdbuf();
- std::string result = ss.str();
- TS_ASSERT(result == expected_content_types_string);
- }
-
- void test_open_by_info()
- {
- xlnt::zip_file f(existing_file);
- std::stringstream ss;
- ss << f.open(xlnt::path("[Content_Types].xml")).rdbuf();
- std::string result = ss.str();
- TS_ASSERT(result == expected_content_types_string);
- }
-
-
- void test_read()
- {
- xlnt::zip_file f(existing_file);
- TS_ASSERT(f.read(xlnt::path("[Content_Types].xml")) == expected_content_types_string);
- TS_ASSERT(f.read(f.getinfo(xlnt::path("[Content_Types].xml"))) == expected_content_types_string);
- }
-
- void test_testzip()
- {
- xlnt::zip_file f(existing_file);
- TS_ASSERT(!f.check_crc());
- }
-
- void test_write_file()
- {
- temporary_file temp_file;
-
- xlnt::zip_file f;
- auto text_file = path_helper::get_data_directory("reader/sharedStrings.xml");
- f.write_file(text_file);
- f.write_file(text_file, xlnt::path("sharedStrings2.xml"));
- f.save(temp_file.get_path());
-
- xlnt::zip_file f2(temp_file.get_path());
-
- for(auto &info : f2.infolist())
- {
- if(info.filename.to_string() == "sharedStrings2.xml")
- {
- TS_ASSERT(f2.read(info) == expected_atxt_string);
- }
- else if(info.filename.basename() == "sharedStrings.xml")
- {
- TS_ASSERT(f2.read(info) == expected_atxt_string);
- }
- }
- }
-
- void test_write_string()
- {
- xlnt::zip_file f;
- f.write_string("a\na", xlnt::path("a.txt"));
- xlnt::zip_info info;
- info.filename = xlnt::path("b.txt");
- info.date_time.year = 2014;
- f.write_string("b\nb", info);
-
- temporary_file temp_file;
- f.save(temp_file.get_path());
-
- xlnt::zip_file f2(temp_file.get_path());
- TS_ASSERT(f2.read(xlnt::path("a.txt")) == "a\na");
- TS_ASSERT(f2.read(f2.getinfo(xlnt::path("b.txt"))) == "b\nb");
- }
-
- void test_comment()
- {
- xlnt::zip_file f;
- f.comment = "comment";
- temporary_file temp_file;
- f.save(temp_file.get_path());
-
- xlnt::zip_file f2(temp_file.get_path());
- TS_ASSERT(f2.comment == "comment");
-
- xlnt::zip_file f3;
- std::vector bytes { 1, 2, 3 };
- TS_ASSERT_THROWS(f3.load(bytes), std::runtime_error);
- }
-
-private:
- xlnt::path existing_file;
- std::string expected_content_types_string;
- std::string expected_atxt_string;
- std::string expected_printdir_string;
-};
diff --git a/source/workbook/tests/test_consume_xlsx.hpp b/source/workbook/tests/test_consume_xlsx.hpp
new file mode 100644
index 00000000..6ab8db1e
--- /dev/null
+++ b/source/workbook/tests/test_consume_xlsx.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+class test_consume_xlsx : public CxxTest::TestSuite
+{
+};
diff --git a/source/workbook/tests/test_produce_xlsx.hpp b/source/workbook/tests/test_produce_xlsx.hpp
new file mode 100644
index 00000000..4a3352e1
--- /dev/null
+++ b/source/workbook/tests/test_produce_xlsx.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+class test_produce_xlsx : public CxxTest::TestSuite
+{
+public:
+ bool workbook_matches_file(xlnt::workbook &wb, const xlnt::path &file)
+ {
+ std::vector buffer;
+ wb.save(buffer);
+ wb.save(xlnt::path("C:\\Users\\Thomas\\Desktop\\a.xlsx"));
+ xlnt::zip_file wb_archive(buffer);
+
+ xlnt::zip_file file_archive(file);
+
+ return xml_helper::archives_match(wb_archive, file_archive);
+ }
+
+ void test_empty_excel()
+ {
+ xlnt::workbook wb = xlnt::workbook::empty_excel();
+ TS_ASSERT(workbook_matches_file(wb, path_helper::get_data_directory("xlsx/8_default-excel.xlsx")));
+ }
+};
diff --git a/source/workbook/tests/test_read.hpp b/source/workbook/tests/test_read.hpp
deleted file mode 100644
index 802bdb0f..00000000
--- a/source/workbook/tests/test_read.hpp
+++ /dev/null
@@ -1,438 +0,0 @@
-#pragma once
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-class test_read : public CxxTest::TestSuite
-{
-public:
-
- xlnt::workbook standard_workbook()
- {
- xlnt::workbook wb;
- auto path = path_helper::get_data_directory("genuine/empty.xlsx");
- wb.load(path);
-
- return wb;
- }
-
- void test_read_standard_workbook()
- {
- TS_ASSERT_THROWS_NOTHING(standard_workbook());
- }
-
- void test_read_standard_workbook_from_fileobj()
- {
- auto path = path_helper::get_data_directory("genuine/empty.xlsx");
- std::ifstream fo(path.to_string(), std::ios::binary);
-
- xlnt::workbook wb;
- wb.load(fo);
-
- TS_ASSERT(wb.get_sheet_titles().size() == 1);
- }
-
- void test_read_worksheet()
- {
- auto wb = standard_workbook();
- auto sheet2 = wb.get_sheet_by_title("Sheet2 - Numbers");
-
- TS_ASSERT_DIFFERS(sheet2, nullptr);
- TS_ASSERT_EQUALS("This is cell G5", sheet2.get_cell("G5").get_value());
- TS_ASSERT_EQUALS(18, sheet2.get_cell("D18").get_value());
- TS_ASSERT_EQUALS(true, sheet2.get_cell("G9").get_value());
- TS_ASSERT_EQUALS(false, sheet2.get_cell("G10").get_value());
- }
-
- void test_read_nostring_workbook()
- {
- auto path = path_helper::get_data_directory("genuine/empty-no-string.xlsx");
-
- xlnt::workbook wb;
- TS_ASSERT_THROWS_NOTHING(wb.load(path));
- }
-
- void test_read_empty_file()
- {
- xlnt::workbook wb;
- TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("reader/null_file.xlsx")), xlnt::invalid_file);
- }
-
- void test_read_empty_archive()
- {
- xlnt::workbook wb;
- TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("reader/null_archive.xlsx")), xlnt::invalid_file);
- }
-
- void test_read_workbook_with_no_properties()
- {
- xlnt::workbook wb;
- TS_ASSERT_THROWS_NOTHING(wb.load(path_helper::get_data_directory("genuine/empty_with_no_properties.xlsx")));
- }
-
- xlnt::workbook workbook_with_styles()
- {
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("genuine/empty-with-styles.xlsx"));
-
- return wb;
- }
-
- void test_read_workbook_with_styles_general()
- {
- auto wb = workbook_with_styles();
- auto ws = wb["Sheet1"];
- auto format = ws.get_cell("A1").get_number_format();
- auto expected = xlnt::number_format::general();
- TS_ASSERT_EQUALS(format, expected);
- }
-
- void test_read_workbook_with_styles_date()
- {
- auto wb = workbook_with_styles();
- auto ws = wb["Sheet1"];
- auto format = ws.get_cell("A2").get_number_format();
- auto expected = xlnt::number_format::date_xlsx14();
- TS_ASSERT_EQUALS(format, expected);
- }
-
- void test_read_workbook_with_styles_number()
- {
- auto wb = workbook_with_styles();
- auto ws = wb["Sheet1"];
- auto code = ws.get_cell("A3").get_number_format();
- auto expected = xlnt::number_format::number_00();
- TS_ASSERT_EQUALS(code, expected);
- }
-
- void test_read_workbook_with_styles_time()
- {
- auto wb = workbook_with_styles();
- auto ws = wb["Sheet1"];
- auto code = ws.get_cell("A4").get_number_format();
- auto expected = xlnt::number_format::date_time3();
- TS_ASSERT_EQUALS(code, expected);
- }
-
- void test_read_workbook_with_styles_percentage()
- {
- auto wb = workbook_with_styles();
- auto ws = wb["Sheet1"];
- auto code = ws.get_cell("A5").get_number_format();
- auto expected = xlnt::number_format::percentage_00();
- TS_ASSERT_EQUALS(code, expected);
- }
-
- void test_read_charset_excel()
- {
- xlnt::workbook wb;
- auto path = path_helper::get_data_directory("reader/charset-excel.xlsx");
- wb.load(path);
-
- auto ws = wb["Sheet1"];
- auto val = ws.get_cell("A1").get_value();
- TS_ASSERT_EQUALS(val, "Direnç");
- }
-
- void test_read_shared_strings_max_range()
- {
- xlnt::workbook wb;
- const auto path = path_helper::get_data_directory("reader/shared_strings-max_range.xlsx");
- wb.load(path);
-
- auto ws = wb["Sheet1"];
- auto val = ws.get_cell("A1").get_value();
- TS_ASSERT_EQUALS(val, "Donald");
- }
-
- void test_read_shared_strings_multiple_r_nodes()
- {
- auto path = path_helper::get_data_directory("reader/shared_strings-multiple_r_nodes.xlsx");
-
- xlnt::workbook wb;
- wb.load(path);
-
- auto ws = wb["Sheet1"];
- auto val = ws.get_cell("A1").get_value();
- TS_ASSERT_EQUALS(val, "abcdef");
- }
-
- xlnt::workbook date_mac_1904()
- {
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("reader/date_1904.xlsx"));
-
- return wb;
- }
-
- xlnt::workbook date_std_1900()
- {
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("reader/date_1900.xlsx"));
-
- return wb;
- }
-
- void test_read_win_base_date()
- {
- auto wb = date_std_1900();
- TS_ASSERT_EQUALS(wb.get_base_date(), xlnt::calendar::windows_1900);
- }
-
- void test_read_mac_base_date()
- {
- auto wb = date_mac_1904();
- TS_ASSERT_EQUALS(wb.get_base_date(), xlnt::calendar::mac_1904);
- }
-
- void test_read_date_style_win()
- {
- auto wb = date_std_1900();
- auto ws = wb["Sheet1"];
- TS_ASSERT_EQUALS(ws.get_cell("A1").get_number_format(), xlnt::number_format::date_xlsx14());
- }
-
- void test_read_date_style_mac()
- {
- auto wb = date_mac_1904();
- auto ws = wb["Sheet1"];
- TS_ASSERT_EQUALS(ws.get_cell("A1").get_number_format(), xlnt::number_format::date_xlsx14());
- }
-
- void test_read_compare_mac_win_dates()
- {
- auto wb_mac = date_mac_1904();
- auto ws_mac = wb_mac["Sheet1"];
- auto wb_win = date_std_1900();
- auto ws_win = wb_win["Sheet1"];
- xlnt::datetime dt(2011, 10, 31);
- TS_ASSERT_EQUALS(ws_mac.get_cell("A1").get_value(), dt);
- TS_ASSERT_EQUALS(ws_win.get_cell("A1").get_value(), dt);
- TS_ASSERT_EQUALS(ws_mac.get_cell("A1").get_value(), ws_win.get_cell("A1").get_value());
- }
-
- void test_read_no_theme()
- {
- auto path = path_helper::get_data_directory("genuine/libreoffice_nrt.xlsx");
-
- xlnt::workbook wb;
- TS_ASSERT_THROWS_NOTHING(wb.load(path));
- }
-
- void _test_read_complex_formulae()
- {
- /*
- auto path = PathHelper::GetDataDirectory("reader/formulae.xlsx");
- auto wb = xlnt::reader::load_workbook(path);
- auto ws = wb.get_active_sheet();
-
- // Test normal forumlae
- TS_ASSERT(!ws.get_cell("A1").has_formula());
- TS_ASSERT(!ws.get_cell("A2").has_formula());
- TS_ASSERT(ws.get_cell("A3").has_formula());
- TS_ASSERT(ws.get_formula_attributes().find("A3") == ws.get_formula_attributes().end());
- TS_ASSERT(ws.get_cell("A3").get_formula() == "12345");
- TS_ASSERT(ws.get_cell("A4").has_formula());
- TS_ASSERT(ws.get_formula_attributes().find("A3") == ws.get_formula_attributes().end());
- ws.get_cell("A4").set_formula("A2+A3");
- TS_ASSERT(ws.get_cell("A5").has_formula());
- TS_ASSERT(ws.get_formula_attributes().find("A5") == ws.get_formula_attributes().end());
- ws.get_cell("A5").set_formula("SUM(A2:A4)");
-
- // Test unicode
- std::string expected = "=IF(ISBLANK(B16), \"D\xFCsseldorf\", B16)";
- TS_ASSERT(ws.get_cell("A16").get_formula() == expected);
-
- // Test shared forumlae
- TS_ASSERT(ws.get_cell("B7").get_data_type() == "f");
- TS_ASSERT(ws.formula_attributes["B7"]["t"] == "shared");
- TS_ASSERT(ws.formula_attributes["B7"]["si"] == "0");
- TS_ASSERT(ws.formula_attributes["B7"]["ref"] == "B7:E7");
- TS_ASSERT(ws.get_cell("B7").value == "=B4*2");
- TS_ASSERT(ws.get_cell("C7").get_data_type() == "f");
- TS_ASSERT(ws.formula_attributes["C7"]["t"] == "shared");
- TS_ASSERT(ws.formula_attributes["C7"]["si"] == "0");
- TS_ASSERT("ref" not in ws.formula_attributes["C7"]);
- TS_ASSERT(ws.get_cell("C7").value == "=");
- TS_ASSERT(ws.get_cell("D7").get_data_type() == "f");
- TS_ASSERT(ws.formula_attributes["D7"]["t"] == "shared");
- TS_ASSERT(ws.formula_attributes["D7"]["si"] == "0");
- TS_ASSERT("ref" not in ws.formula_attributes["D7"]);
- TS_ASSERT(ws.get_cell("D7").value == "=");
- TS_ASSERT(ws.get_cell("E7").get_data_type() == "f");
- TS_ASSERT(ws.formula_attributes["E7"]["t"] == "shared");
- TS_ASSERT(ws.formula_attributes["E7"]["si"] == "0");
- TS_ASSERT("ref" not in ws.formula_attributes["E7"]);
- TS_ASSERT(ws.get_cell("E7").value == "=");
-
- // Test array forumlae
- TS_ASSERT(ws.get_cell("C10").get_data_type() == "f");
- TS_ASSERT("ref" not in ws.formula_attributes["C10"]["ref"]);
- TS_ASSERT(ws.formula_attributes["C10"]["t"] == "array");
- TS_ASSERT("si" not in ws.formula_attributes["C10"]);
- TS_ASSERT(ws.formula_attributes["C10"]["ref"] == "C10:C14");
- TS_ASSERT(ws.get_cell("C10").value == "=SUM(A10:A14*B10:B14)");
- TS_ASSERT(ws.get_cell("C11").get_data_type() != "f");
- */
- }
-
- void test_data_only()
- {
- auto path = path_helper::get_data_directory("reader/formulae.xlsx");
-
- xlnt::workbook wb;
- wb.set_data_only(true);
- wb.load(path);
-
- auto ws = wb.get_active_sheet();
-
- TS_ASSERT(ws.get_formula_attributes().empty());
- TS_ASSERT(ws.get_workbook().get_data_only());
- TS_ASSERT(ws.get_cell("A2").get_data_type() == xlnt::cell::type::numeric);
- TS_ASSERT(ws.get_cell("A2").get_value() == 12345);
- TS_ASSERT(!ws.get_cell("A2").has_formula());
- TS_ASSERT(ws.get_cell("A3").get_data_type() == xlnt::cell::type::numeric);
- TS_ASSERT(ws.get_cell("A3").get_value() == 12345);
- TS_ASSERT(!ws.get_cell("A3").has_formula());
- TS_ASSERT(ws.get_cell("A4").get_data_type() == xlnt::cell::type::numeric);
- TS_ASSERT(ws.get_cell("A4").get_value() == 24690);
- TS_ASSERT(!ws.get_cell("A4").has_formula());
- TS_ASSERT(ws.get_cell("A5").get_data_type() == xlnt::cell::type::numeric);
- TS_ASSERT(ws.get_cell("A5").get_value() == 49380);
- TS_ASSERT(!ws.get_cell("A5").has_formula());
- }
-
- void test_read_content_types()
- {
- std::vector> expected =
- {
- {"/xl/workbook.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"},
- {"/xl/worksheets/sheet1.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"},
- {"/xl/chartsheets/sheet1.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml"},
- {"/xl/worksheets/sheet2.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"},
- {"/xl/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml"},
- {"/xl/styles.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"},
- {"/xl/sharedStrings.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"},
- {"/xl/drawings/drawing1.xml", "application/vnd.openxmlformats-officedocument.drawing+xml"},
- {"/xl/charts/chart1.xml", "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"},
- {"/xl/drawings/drawing2.xml", "application/vnd.openxmlformats-officedocument.drawing+xml"},
- {"/xl/charts/chart2.xml", "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"},
- {"/xl/calcChain.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml"},
- {"/docProps/core.xml", "application/vnd.openxmlformats-package.core-properties+xml"},
- {"/docProps/app.xml", "application/vnd.openxmlformats-officedocument.extended-properties+xml"}
- };
-
- auto path = path_helper::get_data_directory("reader/contains_chartsheets.xlsx");
-
- xlnt::workbook wb;
- wb.load(path);
-
- auto &result = wb.get_manifest().get_parts();
-
- if(result.size() != expected.size())
- {
- TS_ASSERT_EQUALS(result.size(), expected.size());
- return;
- }
-
- for(std::size_t i = 0; i < expected.size(); i++)
- {
- TS_ASSERT(wb.get_manifest().has_part(xlnt::path(expected[i].first)));
- TS_ASSERT_EQUALS(wb.get_manifest().get_part_content_type_string(xlnt::path(expected[i].first)), expected[i].second);
- }
- }
-
- void test_guess_types()
- {
- bool guess;
- xlnt::cell::type dtype;
- std::vector> test_cases = {{true, xlnt::cell::type::numeric}, {false, xlnt::cell::type::string}};
-
- for(const auto &expected : test_cases)
- {
- std::tie(guess, dtype) = expected;
- auto path = path_helper::get_data_directory("genuine/guess_types.xlsx");
-
- xlnt::workbook wb;
- wb.set_guess_types(guess);
- wb.load(path);
-
- auto ws = wb.get_active_sheet();
- TS_ASSERT(ws.get_cell("D2").get_data_type() == dtype);
- }
- }
-
- void test_read_autofilter()
- {
- auto path = path_helper::get_data_directory("reader/bug275.xlsx");
-
- xlnt::workbook wb;
- wb.load(path);
-
- auto ws = wb.get_active_sheet();
- TS_ASSERT_EQUALS(ws.get_auto_filter().to_string(), "A1:B6");
- }
-
- void test_bad_formats_xlsb()
- {
- auto path = path_helper::get_data_directory("genuine/a.xlsb");
- xlnt::workbook wb;
- TS_ASSERT_THROWS(wb.load(path), xlnt::invalid_file);
- }
-
- void test_bad_formats_xls()
- {
- auto path = path_helper::get_data_directory("genuine/a.xls");
- xlnt::workbook wb;
- TS_ASSERT_THROWS(wb.load(path), xlnt::invalid_file);
- }
-
- void test_bad_formats_no()
- {
- auto path = path_helper::get_data_directory("genuine/a.no-format");
- xlnt::workbook wb;
- TS_ASSERT_THROWS(wb.load(path), xlnt::invalid_file);
- }
-
-
- void test_read_shared_strings_with_runs()
- {
- xlnt::workbook wb;
- wb.load("reader/genuine/a.xlsx");
-
- const auto &strings = wb.get_shared_strings();
-
- TS_ASSERT_EQUALS(strings.size(), 1);
- TS_ASSERT_EQUALS(strings.front().get_runs().size(), 1);
- TS_ASSERT_EQUALS(strings.front().get_runs().front().get_size(), 13);
- TS_ASSERT_EQUALS(strings.front().get_runs().front().get_color(), "color");
- TS_ASSERT_EQUALS(strings.front().get_runs().front().get_font(), "font");
- TS_ASSERT_EQUALS(strings.front().get_runs().front().get_family(), 12);
- TS_ASSERT_EQUALS(strings.front().get_runs().front().get_scheme(), "scheme");
- }
-
- void test_read_inlinestr()
- {
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("genuine/empty.xlsx"));
- TS_ASSERT_EQUALS(wb.get_sheet_by_index(0).get_cell("A1").get_value(), "This is cell A1 in Sheet 1");
- }
-
- void test_determine_document_type()
- {
- xlnt::workbook wb;
- TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("1_empty.txt")), xlnt::invalid_file);
- TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("2_not-empty.txt")), xlnt::invalid_file);
- TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("3_empty.zip")), xlnt::invalid_file);
- TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("4_not-package.zip")), xlnt::invalid_file);
- TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("5_visio.vsdx")), xlnt::invalid_file);
- TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("6_document.docx")), xlnt::invalid_file);
- TS_ASSERT_THROWS(wb.load(path_helper::get_data_directory("7_presentation.pptx")), xlnt::invalid_file);
- }
-};
diff --git a/source/workbook/tests/test_round_trip.hpp b/source/workbook/tests/test_round_trip.hpp
new file mode 100644
index 00000000..0d3dba15
--- /dev/null
+++ b/source/workbook/tests/test_round_trip.hpp
@@ -0,0 +1,82 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+class test_round_trip : public CxxTest::TestSuite
+{
+public:
+ bool round_trip_matches_wr(const xlnt::workbook &original)
+ {
+ std::vector serialized;
+ original.save(serialized);
+
+ xlnt::workbook deserialized;
+ deserialized.load(serialized);
+
+ return xml_helper::workbooks_match(original, deserialized);
+ }
+
+ bool round_trip_matches_rw(const xlnt::path &file)
+ {
+ xlnt::zip_file original_archive(file);
+
+ xlnt::workbook deserialized;
+ deserialized.load(file);
+
+ std::vector serialized;
+ deserialized.save(serialized);
+
+ xlnt::zip_file resulting_archive(serialized);
+
+ return xml_helper::archives_match(original_archive, resulting_archive);
+ }
+
+ void test_round_trip_minimal_wr()
+ {
+ TS_SKIP("");
+ xlnt::workbook wb = xlnt::workbook::minimal();
+ TS_ASSERT(round_trip_matches_wr(wb));
+ }
+
+ void test_round_trip_empty_excel_wr()
+ {
+ TS_SKIP("");
+ xlnt::workbook wb = xlnt::workbook::empty_excel();
+ TS_ASSERT(round_trip_matches_wr(wb));
+ }
+
+ void test_round_trip_empty_libre_office_wr()
+ {
+ TS_SKIP("");
+ xlnt::workbook wb = xlnt::workbook::empty_libre_office();
+ TS_ASSERT(round_trip_matches_wr(wb));
+ }
+
+ void test_round_trip_empty_pages_wr()
+ {
+ TS_SKIP("");
+ xlnt::workbook wb = xlnt::workbook::empty_numbers();
+ TS_ASSERT(round_trip_matches_wr(wb));
+ }
+
+ void test_round_trip_empty_excel_rw()
+ {
+ TS_SKIP("");
+ auto path = path_helper::get_data_directory("xlsx/8_default-excel.xlsx");
+ TS_ASSERT(round_trip_matches_rw(path));
+ }
+
+ void test_round_trip_empty_libre_rw()
+ {
+ TS_SKIP("");
+ auto path = path_helper::get_data_directory("xlsx/9_default-libre-office.xlsx");
+ TS_ASSERT(round_trip_matches_rw(path));
+ }
+};
diff --git a/source/workbook/tests/test_style_reader.hpp b/source/workbook/tests/test_style_reader.hpp
deleted file mode 100644
index 1f7d993e..00000000
--- a/source/workbook/tests/test_style_reader.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-
-#include
-#include
-
-#include
-#include
-
-class test_style_reader : public CxxTest::TestSuite
-{
-public:
- void test_complex_formatting()
- {
- xlnt::workbook wb;
- wb.load(path_helper::get_data_directory("reader/formatting.xlsx"));
-
- // border_style
- auto ws = wb.get_active_sheet();
- auto e30 = ws.get_cell("E30");
- TS_ASSERT_EQUALS(e30.get_border().get_side(xlnt::border::side::top).get_color().get_indexed().get_index(), 10);
- TS_ASSERT_EQUALS(e30.get_border().get_side(xlnt::border::side::top).get_style(), xlnt::border_style::thin);
-
- // underline_style
- auto f30 = ws.get_cell("F30");
- TS_ASSERT_EQUALS(e30.get_font().get_underline(), xlnt::font::underline_style::none);
- TS_ASSERT_EQUALS(f30.get_font().get_underline(), xlnt::font::underline_style::single);
-
- // gradient fill
- auto e21 = ws.get_cell("E21");
- TS_ASSERT_EQUALS(e21.get_fill().get_type(), xlnt::fill::type::gradient);
- TS_ASSERT_EQUALS(e21.get_fill().get_gradient_fill().get_type(), xlnt::gradient_fill::type::linear);
- TS_ASSERT_EQUALS(e21.get_fill().get_gradient_fill().get_stops().size(), 2);
- TS_ASSERT_EQUALS(e21.get_fill().get_gradient_fill().get_stops().at(0).get_rgb().get_hex_string(), "ffff0000");
- TS_ASSERT_EQUALS(e21.get_fill().get_gradient_fill().get_stops().at(1).get_rgb().get_hex_string(), "ff0000ff");
- }
-};
diff --git a/source/workbook/tests/test_style_writer.hpp b/source/workbook/tests/test_style_writer.hpp
deleted file mode 100644
index c616fe5b..00000000
--- a/source/workbook/tests/test_style_writer.hpp
+++ /dev/null
@@ -1,365 +0,0 @@
-#pragma once
-
-#include
-#include
-
-#include
-
-class test_style_writer : public CxxTest::TestSuite
-{
-public:
- bool style_xml_matches(const std::string &expected_string, xlnt::workbook &wb)
- {
- std::vector bytes;
- wb.save(bytes);
-
- xlnt::zip_file archive;
- archive.load(bytes);
-
- pugi::xml_document observed;
- observed.load(archive.read(xlnt::constants::part_styles()).c_str());
-
- return xml_helper::string_matches_document(expected_string, observed);
- }
-
- void test_write_custom_number_format()
- {
- xlnt::workbook wb;
- wb.get_active_sheet().get_cell("A1").set_number_format(xlnt::number_format("YYYY"));
- auto expected =
- ""
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- "";
- TS_ASSERT(style_xml_matches(expected, wb));
- }
-
- void test_simple_styles()
- {
- xlnt::workbook wb;
- wb.set_guess_types(true);
- auto ws = wb.get_active_sheet();
- ws.get_cell("A1").set_value("12.34%");
- auto now = xlnt::date::today();
- ws.get_cell("A2").set_value(now);
- ws.get_cell("A3").set_value("This is a test");
- ws.get_cell("A4").set_value("31.31415");
- ws.get_cell("A5");
-
- ws.get_cell("D9").set_number_format(xlnt::number_format::number_00());
- xlnt::protection locked(true, false);
- ws.get_cell("D9").set_protection(locked);
- xlnt::protection hidden(true, true);
- ws.get_cell("E1").set_protection(hidden);
-
- xlnt::border b;
- xlnt::border::border_property prop;
- prop.set_style(xlnt::border_style::dashdot);
- prop.set_color(xlnt::rgb_color("ffff0000"));
- b.set_side(xlnt::border::side::top, prop);
- ws.get_cell("D10").set_border(b);
-
- auto expected = path_helper::get_data_directory("writer/expected/simple-styles.xml");
- TS_ASSERT(style_xml_matches(expected.read_contents(), wb));
- }
-
- void test_empty_workbook()
- {
- xlnt::workbook wb;
- std::string expected =
- ""
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- "";
- TS_ASSERT(style_xml_matches(expected, wb));
- }
-
- void test_complex_font()
- {
- xlnt::font f;
- f.set_bold(true);
- f.set_color(xlnt::color::red());
- f.set_family(3);
- f.set_italic(true);
- f.set_name("Consolas");
- f.set_scheme("major");
- f.set_size(21);
- f.set_strikethrough(true);
- f.set_underline(xlnt::font::underline_style::double_accounting);
-
- xlnt::workbook wb;
- wb.get_active_sheet().get_cell("A1").set_font(f);
-
- std::string expected =
- ""
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- "";
-
- TS_ASSERT(style_xml_matches(expected, wb));
- }
-
- void test_alignment()
- {
- xlnt::workbook wb;
- xlnt::alignment a;
- a.set_horizontal(xlnt::horizontal_alignment::center_continuous);
- a.set_vertical(xlnt::vertical_alignment::justify);
- a.set_wrap_text(true);
- a.set_shrink_to_fit(true);
- wb.get_active_sheet().get_cell("A1").set_alignment(a);
-
- std::string expected =
- ""
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- "";
- TS_ASSERT(style_xml_matches(expected, wb));
- }
-
- void test_fill()
- {
- xlnt::workbook wb;
-
- xlnt::fill pattern_fill = xlnt::fill::pattern(xlnt::pattern_fill::type::solid);
- pattern_fill.get_pattern_fill().set_foreground_color(xlnt::color::red());
- pattern_fill.get_pattern_fill().set_background_color(xlnt::color::blue());
- wb.get_active_sheet().get_cell("A1").set_fill(pattern_fill);
-
- xlnt::fill gradient_fill_linear = xlnt::fill::gradient(xlnt::gradient_fill::type::linear);
- gradient_fill_linear.get_gradient_fill().set_degree(90);
- wb.get_active_sheet().get_cell("A1").set_fill(gradient_fill_linear);
-
- xlnt::fill gradient_fill_path = xlnt::fill::gradient(xlnt::gradient_fill::type::path);
- gradient_fill_path.get_gradient_fill().set_gradient_left(1);
- gradient_fill_path.get_gradient_fill().set_gradient_right(2);
- gradient_fill_path.get_gradient_fill().set_gradient_top(3);
- gradient_fill_path.get_gradient_fill().set_gradient_bottom(4);
- gradient_fill_path.get_gradient_fill().add_stop(0, xlnt::color::red());
- gradient_fill_path.get_gradient_fill().add_stop(1, xlnt::color::blue());
- wb.get_active_sheet().get_cell("A1").set_fill(gradient_fill_path);
-
- std::string expected =
- ""
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- "";
- TS_ASSERT(style_xml_matches(expected, wb));
- }
-};
diff --git a/source/workbook/tests/test_theme.hpp b/source/workbook/tests/test_theme.hpp
index e4eb7a04..46a70a34 100644
--- a/source/workbook/tests/test_theme.hpp
+++ b/source/workbook/tests/test_theme.hpp
@@ -9,14 +9,4 @@
class test_theme : public CxxTest::TestSuite
{
-public:
- void test_write_theme()
- {
- xlnt::workbook wb;
- wb.set_theme(xlnt::theme());
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/theme1.xml"),
- wb, xlnt::constants::part_theme()));
- }
};
diff --git a/source/workbook/tests/test_workbook.hpp b/source/workbook/tests/test_workbook.hpp
index 0947a4ca..34350505 100644
--- a/source/workbook/tests/test_workbook.hpp
+++ b/source/workbook/tests/test_workbook.hpp
@@ -173,40 +173,6 @@ public:
TS_ASSERT_THROWS(wb.remove_named_range("test_nr2"), std::runtime_error);
}
- void test_write_regular_date()
- {
- const xlnt::datetime today(2010, 1, 18, 14, 15, 20, 1600);
-
- xlnt::workbook book;
- auto sheet = book.get_active_sheet();
- sheet.get_cell("A1").set_value(today);
- temporary_file temp_file;
- book.save(temp_file.get_path());
-
- xlnt::workbook test_book;
- test_book.load(temp_file.get_path());
- auto test_sheet = test_book.get_active_sheet();
-
- TS_ASSERT_EQUALS(test_sheet.get_cell("A1").get_value(), today);
- }
-
- void test_write_regular_float()
- {
- long double float_value = 1.0L / 3.0L;
-
- xlnt::workbook book;
- auto sheet = book.get_active_sheet();
- sheet.get_cell("A1").set_value(float_value);
- temporary_file temp_file;
- book.save(temp_file.get_path());
-
- xlnt::workbook test_book;
- test_book.load(temp_file.get_path());
- auto test_sheet = test_book.get_active_sheet();
-
- TS_ASSERT_EQUALS(test_sheet.get_cell("A1").get_value(), float_value);
- }
-
void test_post_increment_iterator()
{
xlnt::workbook wb;
@@ -262,7 +228,7 @@ public:
xlnt::manifest m;
TS_ASSERT(!m.has_default_type("xml"));
TS_ASSERT_THROWS(m.get_default_type("xml"), xlnt::key_not_found);
- TS_ASSERT(!m.has_part(xlnt::path("xl/workbook.xml")));
+ TS_ASSERT(!m.has_package_relationship(xlnt::relationship::type::office_document));
TS_ASSERT_THROWS(m.get_part_relationships(xlnt::path("xl/workbook.xml")), xlnt::key_not_found);
}
diff --git a/source/workbook/tests/test_write.hpp b/source/workbook/tests/test_write.hpp
deleted file mode 100644
index 7ffff15c..00000000
--- a/source/workbook/tests/test_write.hpp
+++ /dev/null
@@ -1,327 +0,0 @@
-#pragma once
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-class test_write : public CxxTest::TestSuite
-{
-public:
- void test_write_empty_workbook()
- {
- xlnt::workbook wbk;
- wbk.get_active_sheet().get_cell("A2").set_value("xlnt");
- wbk.get_active_sheet().get_cell("B5").set_value(88);
- wbk.get_active_sheet().get_cell("B5").set_number_format(xlnt::number_format::percentage_00());
- wbk.save(temp_file.get_path());
-
- if(temp_file.get_path().exists())
- {
- path_helper::delete_file(temp_file.get_path());
- }
-
- TS_ASSERT(!temp_file.get_path().exists());
- wb_.save(temp_file.get_path());
- TS_ASSERT(temp_file.get_path().exists());
- }
-
- void test_write_virtual_workbook()
- {
- xlnt::workbook old_wb;
- std::vector saved_wb;
- old_wb.save(saved_wb);
- xlnt::workbook new_wb;
- new_wb.load(saved_wb);
- TS_ASSERT_EQUALS(old_wb, new_wb);
- }
-
- void test_write_workbook_rels()
- {
- xlnt::workbook wb;
- wb.add_shared_string(xlnt::text());
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/workbook.xml.rels"),
- wb, xlnt::path("xl/_rels/workbook.xml.rels")));
- }
-
- void test_write_workbook()
- {
- xlnt::workbook wb;
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/workbook.xml"),
- wb, xlnt::path("xl/workbook.xml")));
- }
-
- void test_write_string_table()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("A1").set_value("hello");
- ws.get_cell("A2").set_value("world");
- ws.get_cell("A3").set_value("nice");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sharedStrings.xml"),
- wb, xlnt::path("xl/sharedStrings.xml")));
- }
-
- void test_write_worksheet()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("F42").set_value("hello");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1.xml"),
- wb, xlnt::path("xl/worksheets/sheet1.xml")));
- }
-
- void test_write_hidden_worksheet()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_page_setup().set_sheet_state(xlnt::sheet_state::hidden);
- ws.get_cell("F42").set_value("hello");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1.xml"),
- wb, xlnt::path("xl/worksheets/sheet1.xml")));
- }
-
- void test_write_bool()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("F42").set_value(false);
- ws.get_cell("F43").set_value(true);
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1_bool.xml"),
- wb, xlnt::path("xl/worksheets/sheet1.xml")));
- }
-
- void test_write_formula()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("F1").set_value(10);
- ws.get_cell("F2").set_value(32);
- ws.get_cell("F3").set_formula("F1+F2");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1_bool.xml"),
- wb, xlnt::path("writer/expected/sheet1_formula.xml")));
- }
-
- void test_write_height()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("F1").set_value(10);
- ws.get_row_properties(ws.get_cell("F1").get_row()).height = 30;
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1_height.xml"),
- wb, xlnt::path("xl/worksheets/sheet1.xml")));
- }
-
- void test_write_hyperlink()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("A1").set_value("test");
- ws.get_cell("A1").set_hyperlink("http://test.com");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1_hyperlink.xml"),
- wb, xlnt::path("xl/worksheets/sheet1.xml")));
- }
-
- void test_write_hyperlink_rels()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("A1").set_value("test");
- ws.get_cell("A1").set_hyperlink("http://test.com/");
- ws.get_cell("A2").set_value("test");
- ws.get_cell("A2").set_hyperlink("http://test2.com/");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1_hyperlink.xml.rels"),
- wb, xlnt::path("xl/worksheets/_rels/sheet1.xml.rels")));
- }
-
- void _test_write_hyperlink_image_rels()
- {
- TS_SKIP("not implemented");
- }
-
- void test_hyperlink_value()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("A1").set_hyperlink("http://test.com");
- TS_ASSERT_EQUALS("http://test.com", ws.get_cell("A1").get_value());
- ws.get_cell("A1").set_value("test");
- TS_ASSERT_EQUALS("test", ws.get_cell("A1").get_value());
- }
-
- void test_write_auto_filter()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("F42").set_value("hello");
- ws.auto_filter("A1:F1");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1_auto_filter.xml"),
- wb, xlnt::path("xl/worksheets/sheet1.xml")));
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/workbook_auto_filter.xml"),
- wb, xlnt::path("xl/workbook.xml")));
- }
-
- void test_write_auto_filter_filter_column()
- {
-
- }
-
- void test_write_auto_filter_sort_condition()
- {
-
- }
-
- void test_freeze_panes_horiz()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("F42").set_value("hello");
- ws.freeze_panes("A4");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1_freeze_panes_horiz.xml"),
- wb, xlnt::path("xl/worksheets/sheet1.xml")));
- }
-
- void test_freeze_panes_vert()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("F42").set_value("hello");
- ws.freeze_panes("D1");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1_freeze_panes_vert.xml"),
- wb, xlnt::path("xl/worksheets/sheet1.xml")));
- }
-
- void test_freeze_panes_both()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
- ws.get_cell("F42").set_value("hello");
- ws.freeze_panes("D4");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/sheet1_freeze_panes_both.xml"),
- wb, xlnt::path("xl/worksheets/sheet1.xml")));
- }
-
- void test_long_number()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
- ws.get_cell("A1").set_value(9781231231230LL);
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/long_number.xml"),
- wb, xlnt::path("xl/worksheets/sheet1.xml")));
- }
-
- void test_short_number()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
- ws.get_cell("A1").set_value(1234567890);
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/short_number.xml"),
- wb_, xlnt::path("xl/worksheets/sheet1.xml")));
- }
-
- void test_write_page_setup()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- auto &page_setup = ws.get_page_setup();
- TS_ASSERT(page_setup.is_default());
-
- page_setup.set_break(xlnt::page_break::column);
- page_setup.set_fit_to_height(true);
- page_setup.set_fit_to_page(true);
- page_setup.set_fit_to_width(true);
- page_setup.set_horizontal_centered(true);
- page_setup.set_orientation(xlnt::orientation::landscape);
- page_setup.set_paper_size(xlnt::paper_size::a5);
- page_setup.set_scale(4.0);
- page_setup.set_sheet_state(xlnt::sheet_state::visible);
- page_setup.set_vertical_centered(true);
-
- TS_ASSERT(!page_setup.is_default());
-
- std::vector bytes;
- wb.save(bytes);
-
- xlnt::zip_file archive;
- archive.load(bytes);
- auto worksheet_xml_string = archive.read(xlnt::path("xl/worksheets/sheet1.xml"));
-
- pugi::xml_document worksheet_xml;
- worksheet_xml.load(worksheet_xml_string.c_str());
-
- std::string expected =
- ""
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- "";
-
- TS_ASSERT(xml_helper::string_matches_document(expected, worksheet_xml));
- }
-
- private:
- temporary_file temp_file;
- xlnt::workbook wb_;
-};
diff --git a/source/workbook/tests/test_write_workbook.hpp b/source/workbook/tests/test_write_workbook.hpp
deleted file mode 100644
index ff0d4934..00000000
--- a/source/workbook/tests/test_write_workbook.hpp
+++ /dev/null
@@ -1,219 +0,0 @@
-#pragma once
-
-#include
-#include
-
-#include
-#include
-#include
-
-class test_write_workbook : public CxxTest::TestSuite
-{
-public:
- void test_write_auto_filter()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.get_cell("F42").set_value("hello");
- ws.auto_filter("A1:F1");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/workbook_auto_filter.xml"),
- wb, xlnt::path("xl/workbook.xml")));
- }
-
- void test_write_hidden_worksheet()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
-
- ws.set_sheet_state(xlnt::sheet_state::hidden);
- wb.create_sheet();
-
- std::string expected_string =
- ""
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- "";
-
- TS_ASSERT(xml_helper::string_matches_workbook_part(expected_string,
- wb, xlnt::path("xl/workbook.xml")));
- }
-
- void test_write_hidden_single_worksheet()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
- ws.set_sheet_state(xlnt::sheet_state::hidden);
- std::vector trash;
- TS_ASSERT_THROWS(wb.save(trash), xlnt::no_visible_worksheets);
- }
-
- void test_write_empty_workbook()
- {
- xlnt::workbook wb;
- temporary_file file;
-
- TS_ASSERT(!file.get_path().exists())
- wb.save(file.get_path());
- TS_ASSERT(file.get_path().exists());
- }
-
- void test_write_virtual_workbook()
- {
- xlnt::workbook old_wb, new_wb;
-
- std::vector wb_bytes;
- old_wb.save(wb_bytes);
- new_wb.load(wb_bytes);
-
- // TODO more tests!
- }
-
- void test_write_workbook_rels()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
- ws.get_cell("A1").set_value("string");
-
- TS_ASSERT(xml_helper::file_matches_workbook_part(
- path_helper::get_data_directory("writer/expected/workbook.xml.rels"),
- wb, xlnt::path("xl/_rels/workbook.xml.rels")));
- }
-
- void test_write_workbook_part()
- {
- xlnt::workbook wb;
-
- auto filename = path_helper::get_data_directory("writer/expected/workbook.xml");
- TS_ASSERT(xml_helper::file_matches_workbook_part(filename, wb, xlnt::path("xl/_rels/workbook.xml.rels")));
- }
-
- void _test_write_named_range()
- {
- /*
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
- wb.create_named_range("test_range", ws, "$A$1:$B$5");
- xlnt::workbook_serializer serializer(wb);
- pugi::xml_document xml;
- auto root = xml.root().append_child("root");
- serializer.write_named_ranges(root);
- std::string expected =
- ""
- "'Sheet'!$A$1:$B$5"
- "";
-
- TS_ASSERT(xml_helper::string_matches_document(expected, xml));
- */
- }
-
- void test_read_workbook_code_name()
- {
-// with open(tmpl, "rb") as expected:
-// TS_ASSERT(read_workbook_code_name(expected.read()) == code_name
- }
-
- void test_write_workbook_code_name()
- {
- xlnt::workbook wb;
- wb.set_code_name("MyWB");
-
- std::string expected =
- ""
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- "";
-
- TS_ASSERT(xml_helper::string_matches_workbook_part(expected, wb, xlnt::path("xl/workbook.xml")));
- }
-
- void test_write_root_rels()
- {
- xlnt::workbook wb;
-
- std::string expected =
- ""
- " "
- " "
- " "
- "";
-
- TS_ASSERT(xml_helper::string_matches_workbook_part(expected, wb, xlnt::path("_rels/.rels")));
- }
-
- void test_write_shared_strings_with_runs()
- {
- xlnt::workbook wb;
- auto ws = wb.get_active_sheet();
- auto cell = ws.get_cell("A1");
- xlnt::text_run run;
- run.set_color("color");
- run.set_family(12);
- run.set_font("font");
- run.set_scheme("scheme");
- run.set_size(13);
- run.set_string("string");
- xlnt::text text;
- text.add_run(run);
- cell.set_value(text);
-
- std::string expected =
- ""
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " "
- " string"
- " "
- " "
- "";
-
- TS_ASSERT(xml_helper::string_matches_workbook_part(expected, wb,
- xlnt::constants::part_shared_strings()));
- }
-
- void test_write_worksheet_order()
- {
- auto path = path_helper::get_data_directory("genuine/tab_order.xlsx");
-
- // Load an original workbook produced by Excel
- xlnt::workbook wb_src;
- wb_src.load(path);
-
- // Save it to a new file, unmodified
- temporary_file file;
- wb_src.save(file.get_path());
- TS_ASSERT(file.get_path().exists());
-
- // Load it again
- xlnt::workbook wb_dst;
- wb_dst.load(file.get_path());
-
- TS_ASSERT_EQUALS(wb_src.get_sheet_titles(), wb_dst.get_sheet_titles());
- }
-
-private:
- xlnt::workbook wb_;
-};
diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp
index bd1c8fb3..6584f735 100644
--- a/source/workbook/workbook.cpp
+++ b/source/workbook/workbook.cpp
@@ -63,13 +63,22 @@ workbook workbook::minimal()
auto impl = new detail::workbook_impl();
workbook wb(impl);
- wb.d_->worksheets_.push_back(detail::worksheet_impl(&wb, 1, "Sheet"));
+ wb.d_->manifest_.register_default_type("rels",
+ "application/vnd.openxmlformats-package.relationships+xml");
- wb.d_->manifest_.register_package_part(path("workbook.xml"),
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
- relationship::type::workbook);
- wb.d_->manifest_.register_part(path("sheet1.xml"), path("workbook.xml"),
- "worksheet", relationship::type::worksheet);
+ wb.d_->manifest_.register_override_type(path("workbook.xml"),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml");
+ wb.d_->manifest_.register_package_relationship(relationship::type::office_document,
+ path("workbook.xml"), target_mode::internal);
+
+ std::string title("Sheet");
+ wb.d_->worksheets_.push_back(detail::worksheet_impl(&wb, 1, title));
+
+ wb.d_->manifest_.register_override_type(path("sheet1.xml"),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml");
+ auto ws_rel = wb.d_->manifest_.register_part_relationship(path("workbook.xml"),
+ relationship::type::worksheet, path("sheet1.xml"), target_mode::internal);
+ wb.d_->sheet_title_rel_id_map_[title] = ws_rel;
return wb;
}
@@ -79,15 +88,52 @@ workbook workbook::empty_excel()
auto impl = new detail::workbook_impl();
xlnt::workbook wb(impl);
- wb.d_->manifest_.register_package_part(path("docProps/core.xml"),
- "application/vnd.openxmlformats-package.coreproperties+xml",
- relationship::type::core_properties);
- wb.d_->manifest_.register_package_part(path("docProps/app.xml"),
- "application/vnd.openxmlformats-officedocument.extended-properties+xml",
- relationship::type::extended_properties);
- wb.d_->manifest_.register_package_part(path("xl/workbook.xml"),
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
- relationship::type::workbook);
+ wb.d_->manifest_.register_override_type(path("xl/workbook.xml"),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml");
+ wb.d_->manifest_.register_package_relationship(relationship::type::office_document,
+ path("xl/workbook.xml"), target_mode::internal);
+
+ wb.d_->manifest_.register_default_type("rels",
+ "application/vnd.openxmlformats-package.relationships+xml");
+ wb.d_->manifest_.register_default_type("xml", "application/xml");
+
+ const std::vector thumbnail = {
+ 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,
+ 0x00,0x60,0x00,0x60,0x00,0x00,0xff,0xe1,0x00,0x16,0x45,0x78,0x69,0x66,
+ 0x00,0x00,0x49,0x49,0x2a,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0xff,0xdb,0x00,0x43,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0xff,0xc0,0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,
+ 0x11,0x01,0x03,0x11,0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,
+ 0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x01,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,
+ 0x03,0x01,0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xbf,0x80,0x01,0xff,
+ 0xd9
+ };
+
+ wb.set_thumbnail(thumbnail, "jpeg", "image/jpeg");
+
+ wb.d_->manifest_.register_override_type(path("docProps/core.xml"),
+ "application/vnd.openxmlformats-package.coreproperties+xml");
+ wb.d_->manifest_.register_package_relationship(relationship::type::core_properties,
+ path("docProps/core.xml"), target_mode::internal);
+
+ wb.d_->manifest_.register_override_type(path("docProps/app.xml"),
+ "application/vnd.openxmlformats-officedocument.extended-properties+xml");
+ wb.d_->manifest_.register_package_relationship(relationship::type::extended_properties,
+ path("docProps/app.xml"), target_mode::internal);
wb.set_application("Microsoft Excel");
wb.create_sheet();
@@ -236,10 +282,12 @@ worksheet workbook::create_sheet()
d_->worksheets_.push_back(detail::worksheet_impl(this, sheet_id, title));
- auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::workbook);
- d_->manifest_.register_part(sheet_path, workbook_rel.get_target_uri(),
- "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
- relationship::type::worksheet);
+ auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document);
+ d_->manifest_.register_override_type(sheet_path,
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml");
+ auto ws_rel = d_->manifest_.register_part_relationship(workbook_rel.get_target_uri(),
+ relationship::type::worksheet, sheet_path, target_mode::internal);
+ d_->sheet_title_rel_id_map_[title] = ws_rel;
return worksheet(&d_->worksheets_.back());
}
@@ -343,24 +391,24 @@ void workbook::load(const path &filename)
consumer.read(filename);
}
-void workbook::save(std::vector &data)
+void workbook::save(std::vector &data) const
{
detail::xlsx_producer producer(*this);
producer.write(data);
}
-void workbook::save(const std::string &filename)
+void workbook::save(const std::string &filename) const
{
return save(path(filename));
}
-void workbook::save(const path &filename)
+void workbook::save(const path &filename) const
{
detail::xlsx_producer producer(*this);
producer.write(filename);
}
-void workbook::save(std::ostream &stream)
+void workbook::save(std::ostream &stream) const
{
detail::xlsx_producer producer(*this);
producer.write(stream);
@@ -563,11 +611,14 @@ const theme &workbook::get_theme() const
void workbook::set_theme(const theme &value)
{
- if (!d_->manifest_.has_part(constants::part_theme()))
+ auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document);
+
+ if (!d_->manifest_.has_part_relationship(workbook_rel.get_target_uri(), relationship::type::theme))
{
- auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::workbook);
- d_->manifest_.register_part(constants::part_theme(), workbook_rel.get_target_uri(),
- "theme", relationship::type::theme);
+ d_->manifest_.register_override_type(constants::part_theme(),
+ "application/vnd.openxmlformats-officedocument.theme+xml");
+ d_->manifest_.register_part_relationship(workbook_rel.get_target_uri(),
+ relationship::type::theme, constants::part_theme(), target_mode::internal);
}
d_->has_theme_ = true;
@@ -591,12 +642,14 @@ std::vector workbook::get_named_ranges() const
std::size_t workbook::add_format(const format &to_add)
{
- if (!d_->manifest_.has_part(constants::part_styles()))
+ auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document);
+
+ if (!d_->manifest_.has_part_relationship(workbook_rel.get_target_uri(), relationship::type::styles))
{
- auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::workbook);
- d_->manifest_.register_part(constants::part_styles(), workbook_rel.get_target_uri(),
- "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
- relationship::type::styles);
+ d_->manifest_.register_override_type(constants::part_styles(),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml");
+ d_->manifest_.register_part_relationship(workbook_rel.get_target_uri(),
+ relationship::type::styles, constants::part_styles(), target_mode::internal);
}
return d_->stylesheet_.add_format(to_add);
@@ -604,12 +657,14 @@ std::size_t workbook::add_format(const format &to_add)
std::size_t workbook::add_style(const style &to_add)
{
- if (!d_->manifest_.has_part(constants::part_styles()))
+ auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document);
+
+ if (!d_->manifest_.has_part_relationship(workbook_rel.get_target_uri(), relationship::type::styles))
{
- auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::workbook);
- d_->manifest_.register_part(constants::part_styles(), workbook_rel.get_target_uri(),
- "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
- relationship::type::styles);
+ d_->manifest_.register_override_type(constants::part_styles(),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml");
+ d_->manifest_.register_part_relationship(workbook_rel.get_target_uri(),
+ relationship::type::styles, constants::part_styles(), target_mode::internal);
}
return d_->stylesheet_.add_style(to_add);
@@ -686,12 +741,14 @@ const std::vector &workbook::get_shared_strings() const
void workbook::add_shared_string(const text &shared, bool allow_duplicates)
{
- if (!d_->manifest_.has_part(constants::part_shared_strings()))
+ auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document);
+
+ if (!d_->manifest_.has_part_relationship(workbook_rel.get_target_uri(), relationship::type::shared_string_table))
{
- auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::workbook);
- d_->manifest_.register_part(constants::part_shared_strings(), workbook_rel.get_target_uri(),
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
- relationship::type::shared_string_table);
+ d_->manifest_.register_override_type(constants::part_shared_strings(),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml");
+ d_->manifest_.register_part_relationship(workbook_rel.get_target_uri(),
+ relationship::type::shared_string_table, constants::part_shared_strings(), target_mode::internal);
}
if (!allow_duplicates)
@@ -716,8 +773,13 @@ bool workbook::contains(const std::string &sheet_title) const
return false;
}
-void workbook::set_thumbnail(const std::vector &thumbnail)
+void workbook::set_thumbnail(const std::vector &thumbnail,
+ const std::string &extension, const std::string &content_type)
{
+ d_->manifest_.register_default_type(extension, content_type);
+ d_->manifest_.register_package_relationship(relationship::type::thumbnail,
+ path("docProps/thumbnail.jpeg"), target_mode::internal);
+
d_->thumbnail_.assign(thumbnail.begin(), thumbnail.end());
}
diff --git a/source/worksheet/tests/test_worksheet.hpp b/source/worksheet/tests/test_worksheet.hpp
index 9c18b116..7dbb756c 100644
--- a/source/worksheet/tests/test_worksheet.hpp
+++ b/source/worksheet/tests/test_worksheet.hpp
@@ -520,47 +520,32 @@ public:
void test_print_titles_old()
{
xlnt::workbook wb;
+
+ auto ws = wb.create_sheet();
+ ws.add_print_title(3);
+ TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet1!1:3");
- {
- wb.clear();
- auto ws = wb.create_sheet();
- ws.add_print_title(3);
- TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet!1:3");
- }
-
- {
- wb.clear();
- auto ws = wb.create_sheet();
- ws.add_print_title(4, "cols");
- TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet!A:D");
- }
+ auto ws2 = wb.create_sheet();
+ ws2.add_print_title(4, "cols");
+ TS_ASSERT_EQUALS(ws2.get_print_titles(), "Sheet2!A:D");
}
void test_print_titles_new()
{
xlnt::workbook wb;
- {
- wb.clear();
- auto ws = wb.create_sheet();
- ws.set_print_title_rows("1:4");
- TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet!1:4");
- }
-
- {
- wb.clear();
- auto ws = wb.create_sheet();
- ws.set_print_title_cols("A:F");
- TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet!A:F");
- }
+ auto ws = wb.create_sheet();
+ ws.set_print_title_rows("1:4");
+ TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet1!1:4");
- {
- wb.clear();
- auto ws = wb.create_sheet();
- ws.set_print_title_rows("1:2");
- ws.set_print_title_cols("C:D");
- TS_ASSERT_EQUALS(ws.get_print_titles(), "Sheet!1:2,Sheet!C:D");
- }
+ auto ws2 = wb.create_sheet();
+ ws2.set_print_title_cols("A:F");
+ TS_ASSERT_EQUALS(ws2.get_print_titles(), "Sheet2!A:F");
+
+ auto ws3 = wb.create_sheet();
+ ws3.set_print_title_rows("1:2");
+ ws3.set_print_title_cols("C:D");
+ TS_ASSERT_EQUALS(ws3.get_print_titles(), "Sheet3!1:2,Sheet3!C:D");
}
void test_print_area()
diff --git a/tests/data/2_not-empty.txt b/tests/data/2_not-empty.txt
deleted file mode 100644
index 041ecf26..00000000
--- a/tests/data/2_not-empty.txt
+++ /dev/null
@@ -1 +0,0 @@
-not-empty
diff --git a/tests/data/4_not-package.zip b/tests/data/4_not-package.zip
deleted file mode 100644
index d80e9910..00000000
Binary files a/tests/data/4_not-package.zip and /dev/null differ
diff --git a/tests/data/5_visio.zip b/tests/data/5_visio.zip
deleted file mode 100644
index 32b6589e..00000000
Binary files a/tests/data/5_visio.zip and /dev/null differ
diff --git a/tests/data/complex-styles.xlsx b/tests/data/complex-styles.xlsx
deleted file mode 100644
index 0d43e28d..00000000
Binary files a/tests/data/complex-styles.xlsx and /dev/null differ
diff --git a/tests/data/writer/expected/Content_types_vba.xml b/tests/data/content_types/Content_types_vba.xml
similarity index 100%
rename from tests/data/writer/expected/Content_types_vba.xml
rename to tests/data/content_types/Content_types_vba.xml
diff --git a/tests/data/writer/expected/[Content_Types].xml b/tests/data/content_types/[Content_Types].xml
similarity index 100%
rename from tests/data/writer/expected/[Content_Types].xml
rename to tests/data/content_types/[Content_Types].xml
diff --git a/tests/data/writer/expected/core.xml b/tests/data/core_properties/core.xml
similarity index 100%
rename from tests/data/writer/expected/core.xml
rename to tests/data/core_properties/core.xml
diff --git a/tests/data/writer/app.xml b/tests/data/extended_properties/app.xml
similarity index 100%
rename from tests/data/writer/app.xml
rename to tests/data/extended_properties/app.xml
diff --git a/tests/data/genuine/NameWithValueBug.xlsx b/tests/data/genuine/NameWithValueBug.xlsx
deleted file mode 100644
index 0f8a5dc3..00000000
Binary files a/tests/data/genuine/NameWithValueBug.xlsx and /dev/null differ
diff --git a/tests/data/genuine/empty-no-string.xlsx b/tests/data/genuine/empty-no-string.xlsx
deleted file mode 100644
index 39490ac3..00000000
Binary files a/tests/data/genuine/empty-no-string.xlsx and /dev/null differ
diff --git a/tests/data/genuine/empty-with-styles.xlsx b/tests/data/genuine/empty-with-styles.xlsx
deleted file mode 100644
index 250e9b43..00000000
Binary files a/tests/data/genuine/empty-with-styles.xlsx and /dev/null differ
diff --git a/tests/data/genuine/empty.xlsx b/tests/data/genuine/empty.xlsx
deleted file mode 100644
index 1b9e826b..00000000
Binary files a/tests/data/genuine/empty.xlsx and /dev/null differ
diff --git a/tests/data/genuine/empty_libre.xlsx b/tests/data/genuine/empty_libre.xlsx
deleted file mode 100644
index 9b66aa08..00000000
Binary files a/tests/data/genuine/empty_libre.xlsx and /dev/null differ
diff --git a/tests/data/genuine/empty_no_dimensions.xlsx b/tests/data/genuine/empty_no_dimensions.xlsx
deleted file mode 100644
index e402883c..00000000
Binary files a/tests/data/genuine/empty_no_dimensions.xlsx and /dev/null differ
diff --git a/tests/data/genuine/empty_with_no_properties.xlsx b/tests/data/genuine/empty_with_no_properties.xlsx
deleted file mode 100644
index 8eaa8729..00000000
Binary files a/tests/data/genuine/empty_with_no_properties.xlsx and /dev/null differ
diff --git a/tests/data/genuine/guess_types.xlsx b/tests/data/genuine/guess_types.xlsx
deleted file mode 100644
index 5cfa19ff..00000000
Binary files a/tests/data/genuine/guess_types.xlsx and /dev/null differ
diff --git a/tests/data/genuine/libreoffice_nrt.xlsx b/tests/data/genuine/libreoffice_nrt.xlsx
deleted file mode 100644
index cdf0724d..00000000
Binary files a/tests/data/genuine/libreoffice_nrt.xlsx and /dev/null differ
diff --git a/tests/data/genuine/number_empty_shared_strings.xlsx b/tests/data/genuine/number_empty_shared_strings.xlsx
deleted file mode 100644
index 4caadb75..00000000
Binary files a/tests/data/genuine/number_empty_shared_strings.xlsx and /dev/null differ
diff --git a/tests/data/genuine/tab_order.xlsx b/tests/data/genuine/tab_order.xlsx
deleted file mode 100644
index f84e1b2a..00000000
Binary files a/tests/data/genuine/tab_order.xlsx and /dev/null differ
diff --git a/tests/data/writer/expected/.rels b/tests/data/package_rels/.rels
similarity index 100%
rename from tests/data/writer/expected/.rels
rename to tests/data/package_rels/.rels
diff --git a/tests/data/reader/bigfoot.xlsx b/tests/data/reader/bigfoot.xlsx
deleted file mode 100644
index 799fcb42..00000000
Binary files a/tests/data/reader/bigfoot.xlsx and /dev/null differ
diff --git a/tests/data/reader/bug137.xlsx b/tests/data/reader/bug137.xlsx
deleted file mode 100644
index cde2874a..00000000
Binary files a/tests/data/reader/bug137.xlsx and /dev/null differ
diff --git a/tests/data/reader/bug275.xlsx b/tests/data/reader/bug275.xlsx
deleted file mode 100644
index 0c4e5f0a..00000000
Binary files a/tests/data/reader/bug275.xlsx and /dev/null differ
diff --git a/tests/data/reader/bug304.xlsx b/tests/data/reader/bug304.xlsx
deleted file mode 100644
index a0747277..00000000
Binary files a/tests/data/reader/bug304.xlsx and /dev/null differ
diff --git a/tests/data/reader/charset-excel.xlsx b/tests/data/reader/charset-excel.xlsx
deleted file mode 100644
index fb0d7060..00000000
Binary files a/tests/data/reader/charset-excel.xlsx and /dev/null differ
diff --git a/tests/data/reader/contains_chartsheets.xlsx b/tests/data/reader/contains_chartsheets.xlsx
deleted file mode 100644
index 985ebef6..00000000
Binary files a/tests/data/reader/contains_chartsheets.xlsx and /dev/null differ
diff --git a/tests/data/reader/date_1900.xlsx b/tests/data/reader/date_1900.xlsx
deleted file mode 100644
index d4f94621..00000000
Binary files a/tests/data/reader/date_1900.xlsx and /dev/null differ
diff --git a/tests/data/reader/date_1904.xlsx b/tests/data/reader/date_1904.xlsx
deleted file mode 100644
index d18e7c48..00000000
Binary files a/tests/data/reader/date_1904.xlsx and /dev/null differ
diff --git a/tests/data/reader/formatting.xlsx b/tests/data/reader/formatting.xlsx
deleted file mode 100644
index 25a41c57..00000000
Binary files a/tests/data/reader/formatting.xlsx and /dev/null differ
diff --git a/tests/data/reader/formulae.xlsx b/tests/data/reader/formulae.xlsx
deleted file mode 100644
index f1195eec..00000000
Binary files a/tests/data/reader/formulae.xlsx and /dev/null differ
diff --git a/tests/data/reader/null_archive.xlsx b/tests/data/reader/null_archive.xlsx
deleted file mode 100644
index 967263ab..00000000
Binary files a/tests/data/reader/null_archive.xlsx and /dev/null differ
diff --git a/tests/data/reader/sharedStrings.xml b/tests/data/reader/sharedStrings.xml
deleted file mode 100644
index 32bb79f1..00000000
--- a/tests/data/reader/sharedStrings.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-This is cell A1 in Sheet 1This is cell G5
\ No newline at end of file
diff --git a/tests/data/reader/shared_strings-max_range.xlsx b/tests/data/reader/shared_strings-max_range.xlsx
deleted file mode 100644
index 314f78d8..00000000
Binary files a/tests/data/reader/shared_strings-max_range.xlsx and /dev/null differ
diff --git a/tests/data/reader/shared_strings-multiple_r_nodes.xlsx b/tests/data/reader/shared_strings-multiple_r_nodes.xlsx
deleted file mode 100644
index d35130e5..00000000
Binary files a/tests/data/reader/shared_strings-multiple_r_nodes.xlsx and /dev/null differ
diff --git a/tests/data/reader/styles/simple-styles.xml b/tests/data/reader/styles/simple-styles.xml
deleted file mode 100644
index aced6d79..00000000
--- a/tests/data/reader/styles/simple-styles.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/data/reader/vba+comments.xlsm b/tests/data/reader/vba+comments.xlsm
deleted file mode 100644
index e8bc9b84..00000000
Binary files a/tests/data/reader/vba+comments.xlsm and /dev/null differ
diff --git a/tests/data/reader/vba-comments-saved.xlsm b/tests/data/reader/vba-comments-saved.xlsm
deleted file mode 100644
index 94a9496f..00000000
Binary files a/tests/data/reader/vba-comments-saved.xlsm and /dev/null differ
diff --git a/tests/data/reader/vba-test.xlsm b/tests/data/reader/vba-test.xlsm
deleted file mode 100644
index 13db7974..00000000
Binary files a/tests/data/reader/vba-test.xlsm and /dev/null differ
diff --git a/tests/data/writer/expected/sharedStrings.xml b/tests/data/shared_strings/sharedStrings.xml
similarity index 100%
rename from tests/data/writer/expected/sharedStrings.xml
rename to tests/data/shared_strings/sharedStrings.xml
diff --git a/tests/data/reader/styles/alignment_styles.xml b/tests/data/styles/alignment_styles.xml
similarity index 100%
rename from tests/data/reader/styles/alignment_styles.xml
rename to tests/data/styles/alignment_styles.xml
diff --git a/tests/data/reader/styles/complex-styles.xml b/tests/data/styles/complex-styles.xml
similarity index 100%
rename from tests/data/reader/styles/complex-styles.xml
rename to tests/data/styles/complex-styles.xml
diff --git a/tests/data/reader/styles/dxf_style.xml b/tests/data/styles/dxf_style.xml
similarity index 100%
rename from tests/data/reader/styles/dxf_style.xml
rename to tests/data/styles/dxf_style.xml
diff --git a/tests/data/reader/styles/empty-workbook-styles.xml b/tests/data/styles/empty-workbook-styles.xml
similarity index 100%
rename from tests/data/reader/styles/empty-workbook-styles.xml
rename to tests/data/styles/empty-workbook-styles.xml
diff --git a/tests/data/reader/styles/no_number_format.xml b/tests/data/styles/no_number_format.xml
similarity index 100%
rename from tests/data/reader/styles/no_number_format.xml
rename to tests/data/styles/no_number_format.xml
diff --git a/tests/data/reader/styles/none_value_styles.xml b/tests/data/styles/none_value_styles.xml
similarity index 100%
rename from tests/data/reader/styles/none_value_styles.xml
rename to tests/data/styles/none_value_styles.xml
diff --git a/tests/data/reader/styles/rgb_colors.xml b/tests/data/styles/rgb_colors.xml
old mode 100755
new mode 100644
similarity index 100%
rename from tests/data/reader/styles/rgb_colors.xml
rename to tests/data/styles/rgb_colors.xml
diff --git a/tests/data/writer/expected/simple-styles.xml b/tests/data/styles/simple-styles.xml
similarity index 100%
rename from tests/data/writer/expected/simple-styles.xml
rename to tests/data/styles/simple-styles.xml
diff --git a/tests/data/writer/expected/styles.xml b/tests/data/styles/styles.xml
similarity index 100%
rename from tests/data/writer/expected/styles.xml
rename to tests/data/styles/styles.xml
diff --git a/tests/data/reader/styles/styles_number_formats.xml b/tests/data/styles/styles_number_formats.xml
similarity index 100%
rename from tests/data/reader/styles/styles_number_formats.xml
rename to tests/data/styles/styles_number_formats.xml
diff --git a/tests/data/writer/expected/theme1.xml b/tests/data/theme/theme1.xml
similarity index 100%
rename from tests/data/writer/expected/theme1.xml
rename to tests/data/theme/theme1.xml
diff --git a/tests/data/reader/bug328_hyperlinks.xml b/tests/data/workbook/bug328_hyperlinks.xml
similarity index 100%
rename from tests/data/reader/bug328_hyperlinks.xml
rename to tests/data/workbook/bug328_hyperlinks.xml
diff --git a/tests/data/writer/expected/workbook.xml b/tests/data/workbook/workbook.xml
similarity index 100%
rename from tests/data/writer/expected/workbook.xml
rename to tests/data/workbook/workbook.xml
diff --git a/tests/data/writer/expected/workbook_auto_filter.xml b/tests/data/workbook/workbook_auto_filter.xml
similarity index 100%
rename from tests/data/writer/expected/workbook_auto_filter.xml
rename to tests/data/workbook/workbook_auto_filter.xml
diff --git a/tests/data/writer/expected/workbook.xml.rels b/tests/data/workbook_rels/workbook.xml.rels
similarity index 100%
rename from tests/data/writer/expected/workbook.xml.rels
rename to tests/data/workbook_rels/workbook.xml.rels
diff --git a/tests/data/reader/bug393-worksheet.xml b/tests/data/worksheets/bug393-worksheet.xml
similarity index 100%
rename from tests/data/reader/bug393-worksheet.xml
rename to tests/data/worksheets/bug393-worksheet.xml
diff --git a/tests/data/writer/expected/decimal.xml b/tests/data/worksheets/decimal.xml
similarity index 100%
rename from tests/data/writer/expected/decimal.xml
rename to tests/data/worksheets/decimal.xml
diff --git a/tests/data/reader/empty_rows.xml b/tests/data/worksheets/empty_rows.xml
similarity index 100%
rename from tests/data/reader/empty_rows.xml
rename to tests/data/worksheets/empty_rows.xml
diff --git a/tests/data/writer/expected/long_number.xml b/tests/data/worksheets/long_number.xml
similarity index 100%
rename from tests/data/writer/expected/long_number.xml
rename to tests/data/worksheets/long_number.xml
diff --git a/tests/data/reader/merged-ranges.xml b/tests/data/worksheets/merged-ranges.xml
similarity index 100%
rename from tests/data/reader/merged-ranges.xml
rename to tests/data/worksheets/merged-ranges.xml
diff --git a/tests/data/writer/expected/sheet1.xml b/tests/data/worksheets/sheet1.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1.xml
rename to tests/data/worksheets/sheet1.xml
diff --git a/tests/data/writer/expected/sheet1_auto_filter.xml b/tests/data/worksheets/sheet1_auto_filter.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_auto_filter.xml
rename to tests/data/worksheets/sheet1_auto_filter.xml
diff --git a/tests/data/writer/expected/sheet1_auto_filter_filter_column.xml b/tests/data/worksheets/sheet1_auto_filter_filter_column.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_auto_filter_filter_column.xml
rename to tests/data/worksheets/sheet1_auto_filter_filter_column.xml
diff --git a/tests/data/writer/expected/sheet1_auto_filter_sort_condition.xml b/tests/data/worksheets/sheet1_auto_filter_sort_condition.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_auto_filter_sort_condition.xml
rename to tests/data/worksheets/sheet1_auto_filter_sort_condition.xml
diff --git a/tests/data/writer/expected/sheet1_bool.xml b/tests/data/worksheets/sheet1_bool.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_bool.xml
rename to tests/data/worksheets/sheet1_bool.xml
diff --git a/tests/data/writer/expected/sheet1_formula.xml b/tests/data/worksheets/sheet1_formula.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_formula.xml
rename to tests/data/worksheets/sheet1_formula.xml
diff --git a/tests/data/writer/expected/sheet1_freeze_panes_both.xml b/tests/data/worksheets/sheet1_freeze_panes_both.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_freeze_panes_both.xml
rename to tests/data/worksheets/sheet1_freeze_panes_both.xml
diff --git a/tests/data/writer/expected/sheet1_freeze_panes_horiz.xml b/tests/data/worksheets/sheet1_freeze_panes_horiz.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_freeze_panes_horiz.xml
rename to tests/data/worksheets/sheet1_freeze_panes_horiz.xml
diff --git a/tests/data/writer/expected/sheet1_freeze_panes_vert.xml b/tests/data/worksheets/sheet1_freeze_panes_vert.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_freeze_panes_vert.xml
rename to tests/data/worksheets/sheet1_freeze_panes_vert.xml
diff --git a/tests/data/writer/expected/sheet1_height.xml b/tests/data/worksheets/sheet1_height.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_height.xml
rename to tests/data/worksheets/sheet1_height.xml
diff --git a/tests/data/writer/expected/sheet1_hyperlink.xml b/tests/data/worksheets/sheet1_hyperlink.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_hyperlink.xml
rename to tests/data/worksheets/sheet1_hyperlink.xml
diff --git a/tests/data/writer/expected/sheet1_hyperlink.xml.rels b/tests/data/worksheets/sheet1_hyperlink.xml.rels
similarity index 100%
rename from tests/data/writer/expected/sheet1_hyperlink.xml.rels
rename to tests/data/worksheets/sheet1_hyperlink.xml.rels
diff --git a/tests/data/writer/expected/sheet1_style.xml b/tests/data/worksheets/sheet1_style.xml
similarity index 100%
rename from tests/data/writer/expected/sheet1_style.xml
rename to tests/data/worksheets/sheet1_style.xml
diff --git a/tests/data/reader/sheet2.xml b/tests/data/worksheets/sheet2.xml
similarity index 100%
rename from tests/data/reader/sheet2.xml
rename to tests/data/worksheets/sheet2.xml
diff --git a/tests/data/reader/sheet2_invalid_dimension.xml b/tests/data/worksheets/sheet2_invalid_dimension.xml
similarity index 100%
rename from tests/data/reader/sheet2_invalid_dimension.xml
rename to tests/data/worksheets/sheet2_invalid_dimension.xml
diff --git a/tests/data/reader/sheet2_no_dimension.xml b/tests/data/worksheets/sheet2_no_dimension.xml
similarity index 100%
rename from tests/data/reader/sheet2_no_dimension.xml
rename to tests/data/worksheets/sheet2_no_dimension.xml
diff --git a/tests/data/reader/sheet2_no_span.xml b/tests/data/worksheets/sheet2_no_span.xml
similarity index 100%
rename from tests/data/reader/sheet2_no_span.xml
rename to tests/data/worksheets/sheet2_no_span.xml
diff --git a/tests/data/writer/expected/short_number.xml b/tests/data/worksheets/short_number.xml
similarity index 100%
rename from tests/data/writer/expected/short_number.xml
rename to tests/data/worksheets/short_number.xml
diff --git a/tests/data/reader/worksheet_formula.xml b/tests/data/worksheets/worksheet_formula.xml
similarity index 100%
rename from tests/data/reader/worksheet_formula.xml
rename to tests/data/worksheets/worksheet_formula.xml
diff --git a/tests/data/reader/styles/worksheet_unprotected_style.xml b/tests/data/worksheets/worksheet_unprotected_style.xml
similarity index 100%
rename from tests/data/reader/styles/worksheet_unprotected_style.xml
rename to tests/data/worksheets/worksheet_unprotected_style.xml
diff --git a/tests/data/writer/Content_types_vba.xml b/tests/data/writer/Content_types_vba.xml
deleted file mode 100644
index da731852..00000000
--- a/tests/data/writer/Content_types_vba.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/data/writer/expected/app.xml b/tests/data/writer/expected/app.xml
deleted file mode 100644
index 856f8466..00000000
--- a/tests/data/writer/expected/app.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-Microsoft Excel0falseCompanyfalsefalsefalse12.0000Worksheets3SheetSheet1Sheet2
\ No newline at end of file
diff --git a/tests/data/writer/expected/font.xml b/tests/data/writer/expected/font.xml
deleted file mode 100644
index 00beff8a..00000000
--- a/tests/data/writer/expected/font.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tests/data/writer/font.xml b/tests/data/writer/font.xml
deleted file mode 100644
index 00beff8a..00000000
--- a/tests/data/writer/font.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tests/data/writer/styles.xml b/tests/data/writer/styles.xml
deleted file mode 100644
index c3a69218..00000000
--- a/tests/data/writer/styles.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/data/1_empty.txt b/tests/data/xlsx/1_blank.xlsx
similarity index 100%
rename from tests/data/1_empty.txt
rename to tests/data/xlsx/1_blank.xlsx
diff --git a/tests/data/xlsx/2_text.xlsx b/tests/data/xlsx/2_text.xlsx
new file mode 100644
index 00000000..be394c40
--- /dev/null
+++ b/tests/data/xlsx/2_text.xlsx
@@ -0,0 +1 @@
+not-empty
\ No newline at end of file
diff --git a/tests/data/3_empty.zip b/tests/data/xlsx/3_empty-zip.xlsx
similarity index 100%
rename from tests/data/3_empty.zip
rename to tests/data/xlsx/3_empty-zip.xlsx
diff --git a/tests/data/xlsx/4_not-package.xlsx b/tests/data/xlsx/4_not-package.xlsx
new file mode 100644
index 00000000..909c7b62
Binary files /dev/null and b/tests/data/xlsx/4_not-package.xlsx differ
diff --git a/tests/data/5_visio.vsdx b/tests/data/xlsx/5_visio.xlsx
similarity index 100%
rename from tests/data/5_visio.vsdx
rename to tests/data/xlsx/5_visio.xlsx
diff --git a/tests/data/6_document.docx b/tests/data/xlsx/6_document.xlsx
similarity index 100%
rename from tests/data/6_document.docx
rename to tests/data/xlsx/6_document.xlsx
diff --git a/tests/data/7_presentation.pptx b/tests/data/xlsx/7_presentation.xlsx
similarity index 100%
rename from tests/data/7_presentation.pptx
rename to tests/data/xlsx/7_presentation.xlsx
diff --git a/tests/data/8_excel-empty.xlsx b/tests/data/xlsx/8_default-excel.xlsx
similarity index 100%
rename from tests/data/8_excel-empty.xlsx
rename to tests/data/xlsx/8_default-excel.xlsx
diff --git a/tests/data/xlsx/9_default-libre-office.xlsx b/tests/data/xlsx/9_default-libre-office.xlsx
new file mode 100644
index 00000000..64c70e5a
Binary files /dev/null and b/tests/data/xlsx/9_default-libre-office.xlsx differ
diff --git a/tests/helpers/xml_helper.hpp b/tests/helpers/xml_helper.hpp
index ae28da10..3ffb9d2d 100644
--- a/tests/helpers/xml_helper.hpp
+++ b/tests/helpers/xml_helper.hpp
@@ -129,6 +129,45 @@ public:
return documents_match(left_xml, right_xml);
}
+
+ static bool archives_match(xlnt::zip_file &left_archive, xlnt::zip_file &right_archive)
+ {
+ auto left_info = left_archive.infolist();
+ auto right_info = right_archive.infolist();
+
+ if (left_info.size() != right_info.size()) return false;
+
+ for (auto left_member : left_info)
+ {
+ if (!right_archive.has_file(left_member)) return false;
+
+ auto left_member_contents = left_archive.read(left_member);
+ auto right_member_contents = right_archive.read(left_member.filename);
+
+ if (!strings_match(left_member_contents, right_member_contents))
+ {
+ std::cout << left_member.filename.to_string() << std::endl;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ static bool workbooks_match(const xlnt::workbook &left, const xlnt::workbook &right)
+ {
+ std::vector buffer;
+
+ left.save(buffer);
+ xlnt::zip_file left_archive(buffer);
+
+ buffer.clear();
+
+ right.save(buffer);
+ xlnt::zip_file right_archive(buffer);
+
+ return archives_match(left_archive, right_archive);
+ }
static comparison_result compare_xml_nodes(const pugi::xml_node &left, const pugi::xml_node &right)
{