improve manifest interface, work on round-tripping

This commit is contained in:
Thomas Fussell 2016-08-12 00:22:14 -04:00
parent ed591e1559
commit 1b5bdbeb18
24 changed files with 615 additions and 922 deletions

View File

@ -32,42 +32,6 @@
namespace xlnt {
enum class content_type
{
core_properties,
extended_properties,
custom_properties,
calculation_chain,
chartsheet,
comments,
connections,
custom_property,
custom_xml_mappings,
dialogsheet,
drawings,
external_workbook_references,
metadata,
pivot_table,
pivot_table_cache_definition,
pivot_table_cache_records,
query_table,
shared_string_table,
shared_workbook_revision_headers,
shared_workbook,
revision_log,
shared_workbook_user_data,
single_cell_table_definitions,
styles,
table_definition,
theme,
volatile_dependencies,
workbook,
worksheet,
unknown
};
/// <summary>
/// The manifest keeps track of all files in the OOXML package and
/// their type and relationships.
@ -76,122 +40,69 @@ class XLNT_CLASS manifest
{
public:
/// <summary>
/// Convenience method for clear_types() and clear_relationships()
/// Unregisters all default and override type and all relationships and known parts.
/// </summary>
void clear();
/// <summary>
/// Returns the path to all internal package parts registered as a source
/// or target of a relationship.
/// </summary>
std::vector<path> get_parts() const;
// Relationships
/// <summary>
/// Convenince method for clear_default_types() and clear_override_types()
/// Returns true if the manifest contains a relationship with the given type with part as the source.
/// </summary>
void clear_types();
/// <summary>
/// Unregisters every default content type (i.e. type based on part extension).
/// </summary>
void clear_default_types();
/// <summary>
/// Unregisters every content type for every part except default types.
/// </summary>
void clear_override_types();
/// <summary>
/// Convenince method for clear_package_relationships() and clear_part_relationships()
/// </summary>
void clear_relationships();
/// <summary>
/// Unregisters every relationship with the package root as the source.
/// </summary>
void clear_package_relationships();
/// <summary>
/// Unregisters every relationship except those with the package root as the source.
/// </summary>
void clear_part_relationships();
/// <summary>
/// Returns true if the manifest contains a package relationship with the given type.
/// </summary>
bool has_package_relationship(relationship::type type) const;
/// <summary>
/// Returns true if the manifest contains a package relationship with the given id.
/// </summary>
bool has_package_relationship(const std::string &rel_id) const;
bool has_relationship(const path &source, relationship::type type) const;
/// <summary>
/// Returns true if the manifest contains a relationship with the given type with part as the source.
/// </summary>
bool has_part_relationship(const path &part, relationship::type type) const;
bool has_relationship(const path &source, const std::string &rel_id) const;
/// <summary>
/// Returns the relationship with "source" as the source and with a type of "type".
/// Throws a key_not_found exception if no such relationship is found.
/// </summary>
relationship get_relationship(const path &source, relationship::type type) const;
/// <summary>
/// Returns the relationship with "source" as the source and with an ID of "rel_id".
/// Throws a key_not_found exception if no such relationship is found.
/// </summary>
relationship get_relationship(const path &source, const std::string &rel_id) const;
/// <summary>
/// Returns all relationship with "source" as the source.
/// </summary>
std::vector<relationship> get_relationships(const path &source) const;
/// <summary>
/// Returns all relationships with "source" as the source and with a type of "type".
/// </summary>
std::vector<relationship> get_relationships(const path &source, relationship::type type) const;
/// <summary>
///
/// </summary>
std::string register_relationship(const uri &source, relationship::type type, const uri &target, target_mode mode);
/// <summary>
/// Returns true if the manifest contains a relationship with the given type with part as the source.
///
/// </summary>
bool has_part_relationship(const path &part, const std::string &rel_id) const;
std::string register_relationship(const uri &source, relationship::type type, const uri &target, target_mode mode, const std::string &rel_id);
relationship get_package_relationship(relationship::type type) const;
relationship get_package_relationship(const std::string &rel_id) const;
std::vector<relationship> get_package_relationships() const;
std::vector<relationship> 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<relationship> get_part_relationships(const path &part) const;
std::vector<relationship> get_part_relationships(const path &part, relationship::type type) const;
/// <summary>
/// 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.
/// </summary>
content_type get_content_type(const path &part) const;
// Content Types
/// <summary>
/// Given the path to a part, returns the content type of the part as a string.
/// </summary>
std::string get_content_type_string(const path &part) const;
void register_override_type(const path &part, const std::string &content_type);
/// <summary>
/// Unregisters the path of the part of the given type and removes all relationships
/// with the part as a source or target.
/// </summary>
void unregister_override_type(const path &part);
/// <summary>
/// Returns true if the part at the given path has been registered in this manifest.
/// </summary>
bool has_override_type(const path &part) const;
std::vector<path> get_overriden_parts() const;
/// <summary>
///
/// </summary>
std::string register_package_relationship(relationship::type type, const path &target_uri, target_mode mode);
/// <summary>
///
/// </summary>
std::string register_package_relationship(relationship::type type, const path &target_uri, target_mode mode, const std::string &rel_id);
/// <summary>
///
/// </summary>
std::string register_part_relationship(const path &source_uri, relationship::type type, const path &target_uri, target_mode mode);
/// <summary>
///
/// </summary>
std::string register_part_relationship(const path &source_uri, relationship::type type, const path &target_uri, target_mode mode, const std::string &rel_id);
std::string get_content_type(const path &part) const;
// Default Content Types
/// <summary>
/// Returns true if a default content type for the extension has been registered.
/// </summary>
@ -200,9 +111,7 @@ public:
/// <summary>
/// Returns a vector of all extensions with registered default content types.
/// </summary>
std::vector<std::string> get_default_type_extensions() const;
std::vector<path> get_parts_with_relationships() const;
std::vector<std::string> get_extensions_with_default_types() const;
/// <summary>
/// Returns the registered default content type for parts of the given extension.
@ -212,29 +121,50 @@ public:
/// <summary>
/// Associates the given extension with the given content type.
/// </summary>
void register_default_type(const std::string &extension, const std::string &content_type);
void register_default_type(const std::string &extension, const std::string &type);
/// <summary>
/// Unregisters the default content type for the given extension.
/// </summary>
void unregister_default_type(const std::string &extension);
// Override Content Types
/// <summary>
/// Returns true if a content type overriding the default content type has been registered
/// for the given part.
/// </summary>
bool has_override_type(const path &part) const;
/// <summary>
/// Returns the override content type registered for the given part.
/// Throws key_not_found exception if no override type was found.
/// </summary>
std::string get_override_type(const path &part) const;
/// <summary>
/// Returns the path of every part in this manifest with an overriden content type.
/// </summary>
std::vector<path> get_parts_with_overriden_types() const;
/// <summary>
/// Overrides any default type registered for the part's extension with the given content type.
/// </summary>
void register_override_type(const path &part, const std::string &type);
/// <summary>
/// Unregisters the overriding content type of the given part.
/// </summary>
void unregister_override_type(const path &part);
private:
struct part_info
{
std::string content_type;
std::vector<relationship> relationships;
};
std::string next_package_relationship_id() const;
std::string next_relationship_id(const path &part) const;
std::unordered_map<path, part_info> part_infos_;
std::vector<relationship> package_relationships_;
std::unordered_map<std::string, std::string> extension_content_type_map_;
std::unordered_map<std::string, std::string> default_content_types_;
std::unordered_map<path, std::string> override_content_types_;
std::unordered_map<path, std::unordered_map<std::string, relationship>> relationships_;
};
} // namespace xlnt

View File

@ -63,6 +63,8 @@ public:
uri make_absolute(const uri &base);
uri make_reference(const uri &base);
friend XLNT_FUNCTION bool operator==(const uri &left, const uri &right);
private:
bool absolute_;
std::string scheme_;

View File

@ -104,8 +104,10 @@ protected:
private:
std::unordered_map<side, border_property> sides_;
/*
bool outline_ = true;
diagonal_direction diagonal_direction_ = diagonal_direction::neither;
*/
};
} // namespace xlnt

View File

@ -154,6 +154,8 @@ public:
/// Append the provided part to this path and return the result.
/// </summary>
path append(const path &to_append) const;
friend XLNT_FUNCTION bool operator==(const path &left, const path &right);
private:
/// <summary>

View File

@ -71,9 +71,9 @@ struct workbook_impl
guess_types_(other.guess_types_),
data_only_(other.data_only_),
stylesheet_(other.stylesheet_),
manifest_(other.manifest_),
has_theme_(other.has_theme_),
theme_(other.theme_),
manifest_(other.manifest_),
write_core_properties_(other.write_core_properties_),
creator_(other.creator_),
last_modified_by_(other.last_modified_by_),

View File

@ -19,11 +19,6 @@ bool is_true(const std::string &bool_string)
return bool_string == "1" || bool_string == "true";
}
bool is_false(const std::string &bool_string)
{
return bool_string == "0" || bool_string == "false";
}
std::size_t string_to_size_t(const std::string &s)
{
#if ULLONG_MAX == SIZE_MAX
@ -59,16 +54,6 @@ struct EnumClassHash
}
};
std::string string_lower(std::string str)
{
for (std::size_t i = 0; i < str.size(); i++)
{
str[i] = std::tolower(str[i]);
}
return str;
}
template<typename T>
T from_string(const std::string &string);
@ -649,45 +634,21 @@ std::vector<xlnt::relationship> read_relationships(const xlnt::path &part, xlnt:
document.load_string(archive.read(part).c_str());
auto root_node = document.child("Relationships");
xlnt::uri source(part.string());
for (auto relationship_node : root_node.children("Relationship"))
{
std::string id(relationship_node.attribute("Id").value());
std::string type_string(relationship_node.attribute("Type").value());
auto type = from_string<xlnt::relationship::type>(type_string);
xlnt::path rel_target(relationship_node.attribute("Target").value());
xlnt::uri target(relationship_node.attribute("Target").value());
relationships.push_back(xlnt::relationship(id, type, rel_target, xlnt::target_mode::internal));
relationships.push_back(xlnt::relationship(id, type, source, target, xlnt::target_mode::internal));
}
return relationships;
}
std::string::size_type find_string_in_string(const std::string &string, const std::string &substring)
{
std::string::size_type possible_match_index = string.find(substring.at(0));
while (possible_match_index != std::string::npos)
{
if (string.substr(possible_match_index, substring.size()) == substring)
{
return possible_match_index;
}
possible_match_index = string.find(substring.at(0), possible_match_index + 1);
}
return possible_match_index;
}
/// <summary>
/// Returns true if d is exactly equal to an integer.
/// </summary>
bool is_integral(long double d)
{
return d == static_cast<long long int>(d);
}
void check_document_type(const std::string &document_content_type)
{
if (document_content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"
@ -733,12 +694,11 @@ void xlsx_consumer::populate_workbook()
{
auto &manifest = destination_.get_manifest();
read_manifest();
path workbook_part;
for (const auto &rel : manifest.get_package_relationships())
for (const auto &rel : manifest.get_relationships(path("/")))
{
pugi::xml_document document;
document.load_string(source_.read(path(rel.get_target_uri())).c_str());
document.load_string(source_.read(rel.get_target().get_path()).c_str());
switch (rel.get_type())
{
@ -752,20 +712,9 @@ void xlsx_consumer::populate_workbook()
read_custom_property(document.root());
break;
case relationship::type::office_document:
check_document_type(manifest.get_content_type_string(rel.get_target_uri()));
workbook_part = rel.get_target_uri();
check_document_type(manifest.get_content_type(rel.get_target().get_path()));
read_workbook(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::calculation_chain:
read_calculation_chain(document.root());
break;
@ -799,13 +748,17 @@ void xlsx_consumer::populate_workbook()
case relationship::type::volatile_dependencies:
read_volatile_dependencies(document.root());
break;
default:
break;
}
}
for (const auto &rel : manifest.get_part_relationships(workbook_part))
const auto workbook_rel = manifest.get_relationship(path("/"), relationship::type::office_document);
for (const auto &rel : manifest.get_relationships(workbook_rel.get_target().get_path()))
{
pugi::xml_document document;
document.load_string(source_.read(path(rel.get_target_uri())).c_str());
document.load_string(source_.read(path(rel.get_target().get_path())).c_str());
switch (rel.get_type())
{
@ -818,6 +771,8 @@ void xlsx_consumer::populate_workbook()
case relationship::type::worksheet:
read_worksheet(document.root(), rel.get_id());
break;
default:
break;
}
}
@ -846,18 +801,6 @@ void xlsx_consumer::read_manifest()
const auto root_node = document.child("Types");
auto &manifest = destination_.get_manifest();
auto make_relative = [](const path &p)
{
path copy;
for (const auto &part : std::vector<std::string>(p.begin() + 1, p.end()))
{
copy.append(part);
}
return copy;
};
for (const auto child : root_node.children())
{
if (child.name() == std::string("Default"))
@ -874,8 +817,9 @@ void xlsx_consumer::read_manifest()
for (const auto &package_rel : package_rels)
{
manifest.register_package_relationship(package_rel.get_type(),
package_rel.get_target_uri(),
manifest.register_relationship(uri("/"),
package_rel.get_type(),
package_rel.get_target(),
package_rel.get_target_mode(),
package_rel.get_id());
}
@ -886,14 +830,13 @@ void xlsx_consumer::read_manifest()
|| relationship_source.filename.extension() != ".rels") continue;
auto part_rels = read_relationships(relationship_source.filename, source_);
auto source_uri = relationship_source.filename.parent().parent()
.append(relationship_source.filename.basename());
uri source(relationship_source.filename.parent().parent()
.append(relationship_source.filename.filename()).string());
for (const auto part_rel : part_rels)
{
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());
manifest.register_relationship(source, part_rel.get_type(),
part_rel.get_target(), part_rel.get_target_mode(), part_rel.get_id());
}
}
}
@ -934,7 +877,7 @@ void xlsx_consumer::read_custom_file_properties(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("customFileProperties");
/*auto root_node = */document.append_child("customFileProperties");
}
// Write SpreadsheetML-Specific Package Parts
@ -977,56 +920,56 @@ void xlsx_consumer::read_chartsheet(const pugi::xml_node root, const std::string
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("chartsheet");
/*auto root_node = */ document.append_child("chartsheet");
}
void xlsx_consumer::read_connections(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("connections");
/*auto root_node = */ document.append_child("connections");
}
void xlsx_consumer::read_custom_property(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("customProperty");
/*auto root_node = */ document.append_child("customProperty");
}
void xlsx_consumer::read_custom_xml_mappings(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("connections");
/*auto root_node = */ document.append_child("connections");
}
void xlsx_consumer::read_dialogsheet(const pugi::xml_node root, const std::string &title)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("dialogsheet");
/*auto root_node = */ document.append_child("dialogsheet");
}
void xlsx_consumer::read_external_workbook_references(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("externalLink");
/*auto root_node = */ document.append_child("externalLink");
}
void xlsx_consumer::read_metadata(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("metadata");
/*auto root_node = */ document.append_child("metadata");
}
void xlsx_consumer::read_pivot_table(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("pivotTableDefinition");
/*auto root_node = */ document.append_child("pivotTableDefinition");
}
void xlsx_consumer::read_shared_string_table(const pugi::xml_node root)
@ -1109,21 +1052,21 @@ void xlsx_consumer::read_shared_workbook_revision_headers(const pugi::xml_node r
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("headers");
/*auto root_node = */ document.append_child("headers");
}
void xlsx_consumer::read_shared_workbook(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("revisions");
/*auto root_node = */ document.append_child("revisions");
}
void xlsx_consumer::read_shared_workbook_user_data(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("users");
/*auto root_node = */ document.append_child("users");
}
void xlsx_consumer::read_stylesheet(const pugi::xml_node root)
@ -1150,7 +1093,7 @@ void xlsx_consumer::read_volatile_dependencies(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("volTypes");
/*auto root_node = */ document.append_child("volTypes");
}
void xlsx_consumer::read_worksheet(const pugi::xml_node root, const std::string &rel_id)
@ -1344,14 +1287,14 @@ void xlsx_consumer::read_comments(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("comments");
/*auto root_node = */ document.append_child("comments");
}
void xlsx_consumer::read_drawings(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("wsDr");
/*auto root_node = */ document.append_child("wsDr");
}
// Unknown Parts
@ -1360,14 +1303,14 @@ void xlsx_consumer::read_unknown_parts(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("Hmm");
/*auto root_node = */ document.append_child("Hmm");
}
void xlsx_consumer::read_unknown_relationships(const pugi::xml_node root)
{
pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str());
auto root_node = document.append_child("Relationships");
/*auto root_node = */ document.append_child("Relationships");
}
} // namespace detail

View File

@ -191,7 +191,7 @@ void write_relationships(const std::vector<xlnt::relationship> &relationships, p
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());
relationship_node.append_attribute("Target").set_value(relationship.get_target().get_path().string().c_str());
if (relationship.get_target_mode() == xlnt::target_mode::external)
{
@ -586,90 +586,43 @@ void xlsx_producer::write(std::vector<std::uint8_t> &destination)
void xlsx_producer::populate_archive()
{
write_manifest();
path workbook_part;
for (auto &rel : source_.impl().manifest_.get_package_relationships())
for (auto &rel : source_.impl().manifest_.get_relationships(path("/")))
{
pugi::xml_document document;
bool write_document = true;
switch (rel.get_type())
{
case relationship::type::core_properties:
write_core_properties(document.root());
write_core_properties(rel, document.root());
break;
case relationship::type::extended_properties:
write_extended_properties(document.root());
write_extended_properties(rel, document.root());
break;
case relationship::type::custom_properties:
write_custom_properties(document.root());
write_custom_properties(rel, document.root());
break;
case relationship::type::office_document:
write_workbook(document.root());
workbook_part = rel.get_target_uri();
write_workbook(rel, document.root());
break;
case relationship::type::thumbnail:
destination_.write_string(
std::string(source_.get_thumbnail().begin(), source_.get_thumbnail().end()),
rel.get_target_uri());
continue;
}
write_thumbnail(rel);
write_document = false;
break;
default:
break;
}
write_document_to_archive(document, rel.get_target_uri(), destination_);
}
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(document.root());
break;
case relationship::type::chartsheet:
write_chartsheet(document.root(), rel);
break;
case relationship::type::connections:
write_connections(document.root());
break;
case relationship::type::custom_xml_mappings:
write_custom_xml_mappings(document.root());
break;
case relationship::type::dialogsheet:
write_dialogsheet(document.root(), rel);
break;
case relationship::type::external_workbook_references:
write_external_workbook_references(document.root());
break;
case relationship::type::metadata:
write_metadata(document.root());
break;
case relationship::type::pivot_table:
write_pivot_table(document.root());
break;
case relationship::type::shared_string_table:
write_shared_string_table(document.root());
break;
case relationship::type::shared_workbook_revision_headers:
write_shared_workbook_revision_headers(document.root());
break;
case relationship::type::styles:
write_styles(document.root());
break;
case relationship::type::theme:
write_theme(document.root());
break;
case relationship::type::volatile_dependencies:
write_volatile_dependencies(document.root());
break;
case relationship::type::worksheet:
write_worksheet(document.root(), rel);
break;
}
std::ostringstream document_stream;
document.save(document_stream);
destination_.write_string(document_stream.str(), rel.get_target_uri());
if (write_document)
{
write_document_to_archive(document, rel.get_target().get_path(), destination_);
}
}
// Unknown Parts
@ -687,7 +640,7 @@ void xlsx_producer::write_manifest()
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())
for (const auto &extension : source_.get_manifest().get_extensions_with_default_types())
{
auto default_node = types_node.append_child("Default");
default_node.append_attribute("Extension").set_value(extension.c_str());
@ -695,32 +648,31 @@ void xlsx_producer::write_manifest()
default_node.append_attribute("ContentType").set_value(content_type.c_str());
}
for (const auto &part : source_.get_manifest().get_overriden_parts())
for (const auto &part : source_.get_manifest().get_parts_with_overriden_types())
{
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_content_type_string(part);
override_node.append_attribute("PartName").set_value(part.string().c_str());
auto content_type = source_.get_manifest().get_override_type(part);
override_node.append_attribute("ContentType").set_value(content_type.c_str());
}
for (const auto &part : source_.get_manifest().get_parts_with_relationships())
for (const auto &part : source_.get_manifest().get_parts())
{
auto part_rels = source_.get_manifest().get_part_relationships(part);
auto part_rels = source_.get_manifest().get_relationships(part);
if (part_rels.empty()) continue;
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");
path parent(part.parent().string().front() == '/' ? part.parent().string().substr(1) : part.parent().string());
path rels_path(parent.append("_rels").append(part.filename() + ".rels").string());
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_extended_properties(pugi::xml_node root)
void xlsx_producer::write_extended_properties(const relationship &rel, pugi::xml_node root)
{
auto properties_node = root.append_child("Properties");
@ -765,7 +717,7 @@ void xlsx_producer::write_extended_properties(pugi::xml_node root)
}
}
void xlsx_producer::write_core_properties(pugi::xml_node root)
void xlsx_producer::write_core_properties(const relationship &rel, pugi::xml_node root)
{
auto core_properties_node = root.append_child("cp:coreProperties");
@ -788,14 +740,14 @@ void xlsx_producer::write_core_properties(pugi::xml_node root)
core_properties_node.append_child("cp:category");
}
void xlsx_producer::write_custom_properties(pugi::xml_node root)
void xlsx_producer::write_custom_properties(const relationship &rel, pugi::xml_node root)
{
auto properties_node = root.append_child("Properties");
/*auto properties_node = */root.append_child("Properties");
}
// Write SpreadsheetML-Specific Package Parts
void xlsx_producer::write_workbook(pugi::xml_node root)
void xlsx_producer::write_workbook(const relationship &rel, pugi::xml_node root)
{
std::size_t num_visible = 0;
@ -842,14 +794,13 @@ void xlsx_producer::write_workbook(pugi::xml_node root)
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);
auto wb_rel = source_.d_->manifest_.get_relationship(path("/"), xlnt::relationship::type::office_document);
for (const auto ws : source_)
{
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);
auto sheet_rel = source_.d_->manifest_.get_relationship(wb_rel.get_target().get_path(), sheet_rel_id);
auto sheet_node = sheets_node.append_child("sheet");
sheet_node.append_attribute("name").set_value(ws.get_title().c_str());
@ -893,51 +844,118 @@ void xlsx_producer::write_workbook(pugi::xml_node root)
defined_name_node.text().set(target_string.c_str());
}
*/
for (const auto &child_rel : source_.get_manifest().get_relationships(rel.get_target().get_path()))
{
pugi::xml_document document;
switch (child_rel.get_type())
{
case relationship::type::calculation_chain:
write_calculation_chain(child_rel, document.root());
break;
case relationship::type::chartsheet:
write_chartsheet(child_rel, document.root());
break;
case relationship::type::connections:
write_connections(child_rel, document.root());
break;
case relationship::type::custom_xml_mappings:
write_custom_xml_mappings(child_rel, document.root());
break;
case relationship::type::dialogsheet:
write_dialogsheet(child_rel, document.root());
break;
case relationship::type::external_workbook_references:
write_external_workbook_references(child_rel, document.root());
break;
case relationship::type::metadata:
write_metadata(child_rel, document.root());
break;
case relationship::type::pivot_table:
write_pivot_table(child_rel, document.root());
break;
case relationship::type::shared_string_table:
write_shared_string_table(child_rel, document.root());
break;
case relationship::type::shared_workbook_revision_headers:
write_shared_workbook_revision_headers(child_rel, document.root());
break;
case relationship::type::styles:
write_styles(child_rel, document.root());
break;
case relationship::type::theme:
write_theme(child_rel, document.root());
break;
case relationship::type::volatile_dependencies:
write_volatile_dependencies(child_rel, document.root());
break;
case relationship::type::worksheet:
write_worksheet(child_rel, document.root());
break;
default:
break;
}
write_document_to_archive(document, child_rel.get_target().get_path(), destination_);
}
}
// Write Workbook Relationship Target Parts
void xlsx_producer::write_calculation_chain(pugi::xml_node root)
void xlsx_producer::write_calculation_chain(const relationship &rel, pugi::xml_node root)
{
auto calc_chain_node = root.append_child("calcChain");
/*auto calc_chain_node = */root.append_child("calcChain");
}
void xlsx_producer::write_chartsheet(pugi::xml_node root, const relationship &rel)
void xlsx_producer::write_chartsheet(const relationship &rel, pugi::xml_node root)
{
auto chartsheet_node = root.append_child("chartsheet");
/*auto chartsheet_node = */root.append_child("chartsheet");
}
void xlsx_producer::write_connections(pugi::xml_node root)
void xlsx_producer::write_connections(const relationship &rel, pugi::xml_node root)
{
auto connections_node = root.append_child("connections");
/*auto connections_node = */root.append_child("connections");
}
void xlsx_producer::write_custom_xml_mappings(pugi::xml_node root)
void xlsx_producer::write_custom_xml_mappings(const relationship &rel, pugi::xml_node root)
{
auto map_info_node = root.append_child("MapInfo");
/*auto map_info_node = */root.append_child("MapInfo");
}
void xlsx_producer::write_dialogsheet(pugi::xml_node root, const relationship &rel)
void xlsx_producer::write_dialogsheet(const relationship &rel, pugi::xml_node root)
{
auto dialogsheet_node = root.append_child("dialogsheet");
/*auto dialogsheet_node = */root.append_child("dialogsheet");
}
void xlsx_producer::write_external_workbook_references(pugi::xml_node root)
void xlsx_producer::write_external_workbook_references(const relationship &rel, pugi::xml_node root)
{
auto external_link_node = root.append_child("externalLink");
/*auto external_link_node = */root.append_child("externalLink");
}
void xlsx_producer::write_metadata(pugi::xml_node root)
void xlsx_producer::write_metadata(const relationship &rel, pugi::xml_node root)
{
auto metadata_node = root.append_child("metadata");
/*auto metadata_node = */root.append_child("metadata");
}
void xlsx_producer::write_pivot_table(pugi::xml_node root)
void xlsx_producer::write_pivot_table(const relationship &rel, pugi::xml_node root)
{
auto pivot_table_definition_node = root.append_child("pivotTableDefinition");
/*auto pivot_table_definition_node = */root.append_child("pivotTableDefinition");
}
void xlsx_producer::write_shared_string_table(pugi::xml_node root)
void xlsx_producer::write_shared_string_table(const relationship &rel, pugi::xml_node root)
{
auto sst_node = root.append_child("sst");
@ -997,22 +1015,22 @@ void xlsx_producer::write_shared_string_table(pugi::xml_node root)
}
}
void xlsx_producer::write_shared_workbook_revision_headers(pugi::xml_node root)
void xlsx_producer::write_shared_workbook_revision_headers(const relationship &rel, pugi::xml_node root)
{
auto headers_node = root.append_child("headers");
/*auto headers_node = */root.append_child("headers");
}
void xlsx_producer::write_shared_workbook(pugi::xml_node root)
void xlsx_producer::write_shared_workbook(const relationship &rel, pugi::xml_node root)
{
auto revisions_node = root.append_child("revisions");
/*auto revisions_node = */root.append_child("revisions");
}
void xlsx_producer::write_shared_workbook_user_data(pugi::xml_node root)
void xlsx_producer::write_shared_workbook_user_data(const relationship &rel, pugi::xml_node root)
{
auto users_node = root.append_child("users");
/*auto users_node = */root.append_child("users");
}
void xlsx_producer::write_styles(pugi::xml_node root)
void xlsx_producer::write_styles(const relationship &rel, pugi::xml_node root)
{
auto stylesheet_node = root.append_child("styleSheet");
stylesheet_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
@ -1067,7 +1085,7 @@ void xlsx_producer::write_styles(pugi::xml_node root)
}
}
void xlsx_producer::write_theme(pugi::xml_node root)
void xlsx_producer::write_theme(const relationship &rel, pugi::xml_node root)
{
auto theme_node = root.append_child("a:theme");
theme_node.append_attribute("xmlns:a").set_value(constants::get_namespace("drawingml").c_str());
@ -1403,12 +1421,12 @@ void xlsx_producer::write_theme(pugi::xml_node root)
theme_node.append_child("a:extraClrSchemeLst");
}
void xlsx_producer::write_volatile_dependencies(pugi::xml_node root)
void xlsx_producer::write_volatile_dependencies(const relationship &rel, pugi::xml_node root)
{
auto vol_types_node = root.append_child("volTypes");
/*auto vol_types_node = */root.append_child("volTypes");
}
void xlsx_producer::write_worksheet(pugi::xml_node root, const relationship &rel)
void xlsx_producer::write_worksheet(const relationship &rel, pugi::xml_node root)
{
auto worksheet_node = root.append_child("worksheet");
worksheet_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
@ -1702,9 +1720,9 @@ void xlsx_producer::write_worksheet(pugi::xml_node root, const relationship &rel
}
}
if (!source_.impl().manifest_.get_part_relationships(rel.get_target_uri()).empty())
if (!source_.impl().manifest_.get_relationships(rel.get_target().get_path()).empty())
{
auto sheet_rels = source_.impl().manifest_.get_part_relationships(rel.get_target_uri());
auto sheet_rels = source_.impl().manifest_.get_relationships(rel.get_target().get_path());
std::vector<relationship> hyperlink_sheet_rels;
for (const auto &sheet_rel : sheet_rels)
@ -1722,7 +1740,7 @@ void xlsx_producer::write_worksheet(pugi::xml_node root, const relationship &rel
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("display").set_value(hyperlink_rel.get_target().get_path().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());
}
@ -1801,14 +1819,14 @@ void xlsx_producer::write_worksheet(pugi::xml_node root, const relationship &rel
// Sheet Relationship Target Parts
void xlsx_producer::write_comments(pugi::xml_node root)
void xlsx_producer::write_comments(const relationship &rel, pugi::xml_node root)
{
auto comments_node = root.append_child("comments");
/*auto comments_node = */root.append_child("comments");
}
void xlsx_producer::write_drawings(pugi::xml_node root)
void xlsx_producer::write_drawings(const relationship &rel, pugi::xml_node root)
{
auto ws_dr_node = root.append_child("wsDr");
/*auto ws_dr_node = */root.append_child("wsDr");
}
// Other Parts
@ -1825,5 +1843,12 @@ void xlsx_producer::write_unknown_relationships()
{
}
void xlsx_producer::write_thumbnail(const relationship &rel)
{
const auto &thumbnail = source_.get_thumbnail();
std::string thumbnail_string(thumbnail.begin(), thumbnail.end());
destination_.write_string(thumbnail_string, rel.get_target().get_path());
}
} // namespace detail
} // namepsace xlnt

View File

@ -63,38 +63,39 @@ private:
// Package Parts
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);
void write_core_properties(const relationship &rel, pugi::xml_node root);
void write_extended_properties(const relationship &rel, pugi::xml_node root);
void write_custom_properties(const relationship &rel, pugi::xml_node root);
void write_thumbnail(const relationship &rel);
// SpreadsheetML-Specific Package Parts
void write_workbook(pugi::xml_node root);
void write_workbook(const relationship &rel, pugi::xml_node root);
// Workbook Relationship Target Parts
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_calculation_chain(const relationship &rel, pugi::xml_node root);
void write_connections(const relationship &rel, pugi::xml_node root);
void write_custom_xml_mappings(const relationship &rel, pugi::xml_node root);
void write_external_workbook_references(const relationship &rel, pugi::xml_node root);
void write_metadata(const relationship &rel, pugi::xml_node root);
void write_pivot_table(const relationship &rel, pugi::xml_node root);
void write_shared_string_table(const relationship &rel, pugi::xml_node root);
void write_shared_workbook_revision_headers(const relationship &rel, pugi::xml_node root);
void write_shared_workbook(const relationship &rel, pugi::xml_node root);
void write_shared_workbook_user_data(const relationship &rel, pugi::xml_node root);
void write_styles(const relationship &rel, pugi::xml_node root);
void write_theme(const relationship &rel, pugi::xml_node root);
void write_volatile_dependencies(const relationship &rel, pugi::xml_node root);
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);
void write_chartsheet(const relationship &rel, pugi::xml_node root);
void write_dialogsheet(const relationship &rel, pugi::xml_node root);
void write_worksheet(const relationship &rel, pugi::xml_node root);
// Sheet Relationship Target Parts
void write_comments(pugi::xml_node root);
void write_drawings(pugi::xml_node root);
void write_comments(const relationship &rel, pugi::xml_node root);
void write_drawings(const relationship &rel, pugi::xml_node root);
// Other Parts

View File

@ -21,310 +21,169 @@
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <algorithm>
#include <unordered_set>
#include <xlnt/packaging/manifest.hpp>
#include <xlnt/utils/exceptions.hpp>
namespace {
std::string to_string(xlnt::content_type type)
{
return "";
}
xlnt::content_type from_string(const std::string &type_string)
{
return xlnt::content_type::unknown;
}
}
namespace xlnt {
void manifest::clear()
{
clear_types();
clear_relationships();
part_infos_.clear();
default_content_types_.clear();
override_content_types_.clear();
relationships_.clear();
}
void manifest::clear_types()
bool manifest::has_relationship(const path &part, relationship::type type) const
{
clear_default_types();
clear_override_types();
if (relationships_.find(part) == relationships_.end()) return false;
for (const auto &rel : relationships_.at(part))
{
if (rel.second.get_type() == type) return true;
}
return false;
}
void manifest::clear_default_types()
relationship manifest::get_relationship(const path &part, relationship::type type) const
{
extension_content_type_map_.clear();
}
void manifest::clear_override_types()
{
for (auto &info : part_infos_)
{
info.second.content_type.clear();
}
}
void manifest::clear_relationships()
{
clear_package_relationships();
clear_part_relationships();
}
void manifest::clear_package_relationships()
{
package_relationships_.clear();
}
void manifest::clear_part_relationships()
{
for (auto &info : part_infos_)
{
info.second.relationships.clear();
}
}
bool manifest::has_package_relationship(relationship::type type) const
{
for (const auto &rel : package_relationships_)
{
if (rel.get_type() == type)
{
return true;
}
}
return false;
}
bool manifest::has_part_relationship(const path &part, relationship::type type) const
{
for (const auto &rel : part_infos_.at(part).relationships)
{
if (rel.get_type() == type)
{
return true;
}
}
return false;
}
relationship manifest::get_package_relationship(relationship::type type) const
{
for (const auto &rel : package_relationships_)
{
if (rel.get_type() == type)
{
return rel;
}
}
if (relationships_.find(part) == relationships_.end()) throw key_not_found();
for (const auto &rel : relationships_.at(part))
{
if (rel.second.get_type() == type) return rel.second;
}
throw key_not_found();
}
std::vector<relationship> manifest::get_package_relationships(relationship::type type) const
std::vector<relationship> manifest::get_relationships(const path &part, relationship::type type) const
{
std::vector<relationship> matches;
for (const auto &rel : package_relationships_)
{
if (rel.get_type() == type)
{
matches.push_back(rel);
}
}
for (const auto &rel : relationships_.at(part))
{
if (rel.second.get_type() == type)
{
matches.push_back(rel.second);
}
}
return matches;
}
relationship manifest::get_part_relationship(const path &part, relationship::type type) const
std::string manifest::get_content_type(const path &part) const
{
for (const auto &rel : part_infos_.at(part).relationships)
{
if (rel.get_type() == type)
{
return rel;
}
}
throw key_not_found();
}
std::vector<relationship> manifest::get_part_relationships(const path &part, relationship::type type) const
{
std::vector<relationship> matches;
for (const auto &rel : part_infos_.at(part).relationships)
{
if (rel.get_type() == type)
{
matches.push_back(rel);
}
}
return matches;
}
content_type manifest::get_content_type(const path &part) const
{
return from_string(get_content_type_string(part));
}
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;
if (has_override_type(part))
{
return get_override_type(part);
}
if (has_default_type(part.extension()))
{
return get_default_type(part.extension());
}
throw key_not_found();
}
void manifest::register_override_type(const path &part, const std::string &content_type)
{
part_infos_[part] = { content_type, {} };
override_content_types_[part] = content_type;
}
std::string manifest::register_package_relationship(relationship::type type, const path &target_uri, target_mode mode)
{
return register_package_relationship(type, target_uri, mode, next_package_relationship_id());
}
std::string manifest::register_package_relationship(relationship::type type, const path &target_uri, target_mode mode, const std::string &rel_id)
{
if (has_package_relationship(rel_id))
{
throw invalid_parameter();
}
relationship rel(rel_id, type, target_uri, mode);
package_relationships_.push_back(rel);
return rel_id;
}
bool manifest::has_package_relationship(const std::string &rel_id) const
{
for (const auto &rel : package_relationships_)
{
if (rel.get_id() == rel_id)
{
return true;
}
}
return false;
}
std::vector<path> manifest::get_overriden_parts() const
std::vector<path> manifest::get_parts_with_overriden_types() const
{
std::vector<path> overriden;
for (const auto &part : part_infos_)
for (const auto &part : override_content_types_)
{
if (!part.second.content_type.empty())
{
overriden.push_back(part.first);
}
overriden.push_back(part.first);
}
return overriden;
}
std::vector<relationship> manifest::get_package_relationships() const
std::vector<relationship> manifest::get_relationships(const path &part) const
{
return package_relationships_;
if (relationships_.find(part) == relationships_.end())
{
return {};
}
std::vector<relationship> relationships;
for (const auto &rel : relationships_.at(part))
{
relationships.push_back(rel.second);
}
return relationships;
}
relationship manifest::get_package_relationship(const std::string &rel_id) const
relationship manifest::get_relationship(const path &part, const std::string &rel_id) const
{
for (const auto rel : package_relationships_)
if (relationships_.find(part) == relationships_.end())
{
if (rel.get_id() == rel_id)
throw key_not_found();
}
for (const auto &rel : relationships_.at(part))
{
if (rel.second.get_id() == rel_id)
{
return rel;
return rel.second;
}
}
throw key_not_found();
}
std::vector<relationship> manifest::get_part_relationships(const path &part) const
std::vector<path> manifest::get_parts() const
{
if (part_infos_.find(part) == part_infos_.end())
std::unordered_set<path> parts;
for (const auto &part_rels : relationships_)
{
throw key_not_found();
parts.insert(part_rels.first);
for (const auto &rel : part_rels.second)
{
if (rel.second.get_target_mode() == target_mode::internal)
{
parts.insert(rel.second.get_target().get_path());
}
}
}
return part_infos_.at(part).relationships;
return std::vector<path>(parts.begin(), parts.end());
}
relationship manifest::get_part_relationship(const path &part, const std::string &rel_id) const
std::string manifest::register_relationship(const uri &source, relationship::type type, const uri &target, target_mode mode)
{
if (part_infos_.find(part) == part_infos_.end())
{
throw key_not_found();
}
for (const auto &rel : part_infos_.at(part).relationships)
{
if (rel.get_id() == rel_id)
{
return rel;
}
}
throw key_not_found();
return register_relationship(source, type, target, mode, next_relationship_id(source.get_path()));
}
std::vector<path> manifest::get_parts_with_relationships() const
std::string manifest::register_relationship(const uri &source, relationship::type type, const uri &target, target_mode mode, const std::string &rel_id)
{
std::vector<path> 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_part_relationship(const path &source_uri, relationship::type type, const path &target_uri, target_mode mode)
{
return register_part_relationship(source_uri, type, target_uri, mode, next_relationship_id(source_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)
{
relationship rel(rel_id, type, path(target_uri), mode);
part_infos_.at(source_uri).relationships.push_back(rel);
relationships_[source.get_path()][rel_id] = relationship(rel_id, type, source, target, mode);
return rel_id;
}
bool manifest::has_default_type(const std::string &extension) const
{
return extension_content_type_map_.find(extension) != extension_content_type_map_.end();
return default_content_types_.find(extension) != default_content_types_.end();
}
std::vector<std::string> manifest::get_default_type_extensions() const
std::vector<std::string> manifest::get_extensions_with_default_types() const
{
std::vector<std::string> extensions;
for (const auto &extension_type_pair : extension_content_type_map_)
for (const auto &extension_type_pair : default_content_types_)
{
extensions.push_back(extension_type_pair.first);
}
@ -334,54 +193,52 @@ std::vector<std::string> manifest::get_default_type_extensions() const
std::string manifest::get_default_type(const std::string &extension) const
{
if (extension_content_type_map_.find(extension) == extension_content_type_map_.end())
if (default_content_types_.find(extension) == default_content_types_.end())
{
throw key_not_found();
}
return extension_content_type_map_.at(extension);
return default_content_types_.at(extension);
}
void manifest::register_default_type(const std::string &extension, const std::string &content_type)
{
extension_content_type_map_[extension] = content_type;
default_content_types_[extension] = content_type;
}
void manifest::unregister_default_type(const std::string &extension)
{
extension_content_type_map_.erase(extension);
}
std::string manifest::next_package_relationship_id() const
{
std::string r_id("rId");
std::size_t index = 1;
while (std::find_if(package_relationships_.begin(), package_relationships_.end(),
[&](const relationship &r) { return r.get_id() == r_id + std::to_string(index); })
!= package_relationships_.end())
{
++index;
}
return r_id + std::to_string(index);
default_content_types_.erase(extension);
}
std::string manifest::next_relationship_id(const path &part) const
{
std::string r_id("rId");
if (relationships_.find(part) == relationships_.end()) return "rId1";
std::size_t index = 1;
const auto &part_rels = relationships_.at(part);
const auto &part_rels = get_part_relationships(part);
while (std::find_if(part_rels.begin(), part_rels.end(),
[&](const relationship &r) { return r.get_id() == r_id + std::to_string(index); })
!= part_rels.end())
while (part_rels.find("rId" + std::to_string(index)) != part_rels.end())
{
++index;
}
return r_id + std::to_string(index);
return "rId" + std::to_string(index);
}
bool manifest::has_override_type(const xlnt::path &part) const
{
return override_content_types_.find(part) != override_content_types_.end();
}
std::string manifest::get_override_type(const xlnt::path &part) const
{
if (!has_override_type(part))
{
throw key_not_found();
}
return override_content_types_.at(part);
}
} // namespace xlnt

View File

@ -30,7 +30,7 @@ relationship::relationship()
{
}
relationship::relationship(const std::string &id, type t, const path &source, const path &target, target_mode mode)
relationship::relationship(const std::string &id, type t, const uri &source, const uri &target, target_mode mode)
: id_(id),
type_(t),
source_(source),
@ -44,17 +44,17 @@ std::string relationship::get_id() const
return id_;
}
target_mode relationship::get_mode() const
target_mode relationship::get_target_mode() const
{
return mode_;
}
path relationship::get_source() const
uri relationship::get_source() const
{
return source_;
}
path relationship::get_target() const
uri relationship::get_target() const
{
return target_;
}
@ -68,7 +68,7 @@ bool relationship::operator==(const relationship &rhs) const
{
return type_ == rhs.type_
&& id_ == rhs.id_
&& source_ == the.source_
&& source_ == rhs.source_
&& target_ == rhs.target_
&& mode_ == rhs.mode_;
}

View File

@ -17,13 +17,13 @@ public:
bool files_equal(const xlnt::path &left, const xlnt::path &right)
{
if(left.to_string() == right.to_string())
if(left.string() == right.string())
{
return true;
}
std::ifstream stream_left(left.to_string(), std::ios::binary);
std::ifstream stream_right(right.to_string(), std::ios::binary);
std::ifstream stream_left(left.string(), std::ios::binary);
std::ifstream stream_right(right.string(), std::ios::binary);
while(stream_left && stream_right)
{
@ -48,9 +48,9 @@ public:
{
temporary_file temp;
std::ifstream in_stream(existing_file.to_string(), std::ios::binary);
std::ifstream in_stream(existing_file.string(), std::ios::binary);
xlnt::zip_file f(in_stream);
std::ofstream out_stream(temp.get_path().to_string(), std::ios::binary);
std::ofstream out_stream(temp.get_path().string(), std::ios::binary);
f.save(out_stream);
out_stream.close();
@ -62,7 +62,7 @@ public:
temporary_file temp_file;
std::vector<std::uint8_t> source_bytes;
std::ifstream in_stream(existing_file.to_string(), std::ios::binary);
std::ifstream in_stream(existing_file.string(), std::ios::binary);
while(in_stream)
{
@ -122,7 +122,7 @@ public:
{
xlnt::zip_file f(existing_file);
auto info = f.getinfo(xlnt::path("text.txt"));
TS_ASSERT(info.filename.to_string() == "text.txt");
TS_ASSERT(info.filename.string() == "text.txt");
}
void test_infolist()

28
source/packaging/uri.cpp Normal file
View File

@ -0,0 +1,28 @@
#include <xlnt/packaging/uri.hpp>
namespace xlnt {
uri::uri()
{
}
uri::uri(const std::string &uri_string) : path_(uri_string)
{
}
std::string uri::to_string() const
{
return path_.string();
}
path uri::get_path() const
{
return path_;
}
bool operator==(const uri &left, const uri &right)
{
return left.to_string() == right.to_string();
}
} // namespace xlnt

View File

@ -185,11 +185,11 @@ void zip_file::load(std::istream &stream)
void zip_file::load(const path &filename)
{
filename_ = filename;
std::ifstream stream(filename.to_string(), std::ios::binary);
std::ifstream stream(filename.string(), std::ios::binary);
if (!stream.good())
{
throw invalid_file(filename.to_string());
throw invalid_file(filename.string());
}
reset();
@ -197,7 +197,7 @@ void zip_file::load(const path &filename)
if (buffer_.empty())
{
throw invalid_file(filename.to_string() + " - empty file");
throw invalid_file(filename.string() + " - empty file");
}
remove_comment();
@ -220,7 +220,7 @@ void zip_file::load(const std::vector<unsigned char> &bytes)
void zip_file::save(const path &filename)
{
filename_ = filename;
std::ofstream stream(filename.to_string(), std::ios::binary);
std::ofstream stream(filename.string(), std::ios::binary);
save(stream);
}
@ -341,7 +341,7 @@ zip_info zip_file::getinfo(const path &name)
start_read();
}
int index = mz_zip_reader_locate_file(archive_.get(), name.to_string('/').c_str(), nullptr, 0);
int index = mz_zip_reader_locate_file(archive_.get(), name.string().c_str(), nullptr, 0);
if (index == -1)
{
@ -462,19 +462,15 @@ void zip_file::write_file(const path &filename)
if (filename.is_absolute())
{
arcname = path();
bool first = true;
auto split = filename.split();
auto iter = split.begin() + 1;
arcname = path();
for (auto part : filename)
{
if (first)
{
first = false;
continue;
}
arcname.append(part);
}
while (iter != split.end())
{
arcname.append(*iter++);
}
}
write_file(filename, arcname);
@ -482,7 +478,7 @@ void zip_file::write_file(const path &filename)
void zip_file::write_file(const path &filename, const path &arcname)
{
std::fstream file(filename.to_string(), std::ios::binary | std::ios::in);
std::fstream file(filename.string(), std::ios::binary | std::ios::in);
std::stringstream ss;
ss << file.rdbuf();
@ -497,13 +493,13 @@ void zip_file::write_string(const std::string &bytes, const path &arcname)
start_write();
}
mz_zip_writer_add_mem(archive_.get(), arcname.to_string('/').c_str(),
mz_zip_writer_add_mem(archive_.get(), arcname.string().c_str(),
bytes.data(), bytes.size(), MZ_BEST_COMPRESSION);
}
void zip_file::write_string(const std::string &bytes, const zip_info &info)
{
if (info.filename.to_string().empty() || info.date_time.year < 1980)
if (info.filename.string().empty() || info.date_time.year < 1980)
{
throw std::runtime_error("must specify a filename and valid date (year >= 1980");
}
@ -515,7 +511,7 @@ void zip_file::write_string(const std::string &bytes, const zip_info &info)
auto crc = crc32buf(bytes.c_str(), bytes.size());
mz_zip_writer_add_mem_ex(archive_.get(), info.filename.to_string('/').c_str(), bytes.data(), bytes.size(),
mz_zip_writer_add_mem_ex(archive_.get(), info.filename.string().c_str(), bytes.data(), bytes.size(),
info.comment.c_str(), static_cast<mz_uint16>(info.comment.size()),
MZ_BEST_COMPRESSION, 0, crc);
}
@ -524,7 +520,7 @@ std::string zip_file::read(const zip_info &info)
{
std::size_t size;
void *data_raw = mz_zip_reader_extract_file_to_heap(archive_.get(),
info.filename.to_string('/').c_str(), &size, 0);
info.filename.string().c_str(), &size, 0);
if (data_raw == nullptr)
{
@ -550,7 +546,7 @@ bool zip_file::has_file(const path &name)
start_read();
}
int index = mz_zip_reader_locate_file(archive_.get(), name.to_string('/').c_str(), nullptr, 0);
int index = mz_zip_reader_locate_file(archive_.get(), name.string().c_str(), nullptr, 0);
return index != -1;
}

View File

@ -172,7 +172,7 @@ std::array<std::uint8_t, 4> rgb_color::decode_hex_string(const std::string &hex_
auto g = static_cast<std::uint8_t>((x >> 8) & 0xff);
auto b = static_cast<std::uint8_t>(x & 0xff);
return { r, g, b, a };
return { {r, g, b, a} };
}
rgb_color::rgb_color(const std::string &hex_string)
@ -181,7 +181,7 @@ rgb_color::rgb_color(const std::string &hex_string)
}
rgb_color::rgb_color(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a)
: rgba_({r, g, b, a})
: rgba_({{r, g, b, a}})
{
}

View File

@ -46,16 +46,8 @@ char system_separator()
bool is_root(const std::string &part)
{
return part.size() == 2 && part.back() == ':'
&& part.front() >= 'A' && part.front() <= 'Z';
}
std::string get_working_directory()
{
TCHAR buffer[MAX_PATH];
GetCurrentDirectory(MAX_PATH, buffer);
std::basic_string<TCHAR> working_directory(buffer);
return std::string(working_directory.begin(), working_directory.end());
return part == "/" || (part.size() == 2 && part.back() == ':'
&& part.front() >= 'A' && part.front() <= 'Z');
}
#else
@ -67,21 +59,7 @@ char system_separator()
bool is_root(const std::string &part)
{
return part.empty();
}
std::string get_working_directory()
{
std::size_t buffer_size = 100;
std::vector<char> buffer(buffer_size, '\0');
while (getcwd(&buffer[0], buffer_size) == nullptr)
{
buffer_size *= 2;
buffer.resize(buffer_size, '\0');
}
return std::string(&buffer[0]);
return part == "/";
}
#endif
@ -110,23 +88,6 @@ std::vector<std::string> split_path(const std::string &path, char delim)
return split;
}
std::vector<std::string> split_path_universal(const std::string &path)
{
auto initial = split_path(path, system_separator());
if (initial.size() == 1 && system_separator() == '\\')
{
auto alternative = split_path(path, '/');
if (alternative.size() > 1)
{
return alternative;
}
}
return initial;
}
bool file_exists(const std::string &path)
{
struct stat info;
@ -143,9 +104,9 @@ bool directory_exists(const std::string path)
namespace xlnt {
char path::separator()
char path::system_separator()
{
return system_separator();
return ::system_separator();
}
path::path()
@ -153,11 +114,7 @@ path::path()
}
path::path(const std::string &path_string) : parts_(split_path_universal(path_string))
{
}
path::path(const std::string &path_string, char sep) : parts_(split_path(path_string, sep))
path::path(const std::string &path_string) : internal_(path_string)
{
}
@ -170,91 +127,79 @@ bool path::is_relative() const
bool path::is_absolute() const
{
return !parts_.empty() && ::is_root(parts_.front());
auto split_path = split();
return !split_path.empty() && ::is_root(split_path.front());
}
bool path::is_root() const
{
return parts_.size() == 1 && ::is_root(parts_.front());
return ::is_root(internal_);
}
path path::parent() const
{
path result;
result.parts_ = parts_;
if (result.parts_.size() > 1)
{
result.parts_.pop_back();
}
else
{
return path("");
}
if (is_root()) return *this;
auto split_path = split();
split_path.pop_back();
if (split_path.empty())
{
return path("");
}
path result;
for (const auto &component : split_path)
{
result = result.append(component);
}
return result;
}
std::string path::basename() const
std::string path::filename() const
{
return parts_.empty() ? "" : parts_.back();
auto split_path = split();
return split_path.empty() ? "" : split_path.back();
}
std::string path::extension() const
{
auto base = basename();
auto base = filename();
auto last_dot = base.find_last_of('.');
if (last_dot == std::string::npos) return "";
return base.substr(last_dot + 1);
return last_dot == std::string::npos ? "" : base.substr(last_dot + 1);
}
// conversion
std::string path::to_string(char sep) const
std::string path::string() const
{
if (parts_.empty()) return "";
std::string result;
for (const auto &part : parts_)
{
result.append(part);
result.push_back(sep);
}
result.pop_back();
return result;
return internal_;
}
path path::make_absolute(const path &base_path) const
std::vector<std::string> path::split() const
{
return split_path(internal_, guess_separator());
}
path path::resolve(const path &base_path) const
{
if (is_absolute())
{
return *this;
}
path copy = base_path;
path copy(base_path.internal_);
for (const auto &part : parts_)
for (const auto &part : split())
{
if (part == ".")
{
continue;
}
else if (part == ".." && copy.parts_.size() > 1)
{
copy.parts_.pop_back();
}
else
{
copy.parts_.push_back(part);
}
copy = copy.append(part);
}
return copy;
return copy;
}
// filesystem attributes
@ -266,120 +211,56 @@ bool path::exists() const
bool path::is_directory() const
{
return directory_exists(to_string());
return directory_exists(string());
}
bool path::is_file() const
{
return file_exists(to_string());
return file_exists(string());
}
// filesystem
std::string path::read_contents() const
{
std::ifstream f(to_string());
std::ifstream f(string());
std::ostringstream ss;
ss << f.rdbuf();
return ss.str();
}
// mutators
path &path::append(const std::string &to_append)
{
parts_.push_back(to_append);
return *this;
}
// append
path path::append(const std::string &to_append) const
{
path copy(*this);
copy.append(to_append);
return copy;
}
path &path::append(const path &to_append)
{
parts_.insert(parts_.end(), to_append.begin(), to_append.end());
return *this;
path copy(internal_);
if (!internal_.empty() && internal_.back() != guess_separator())
{
copy.internal_.push_back(guess_separator());
}
copy.internal_.append(to_append);
return copy;
}
path path::append(const path &to_append) const
{
path copy(*this);
copy.append(to_append);
return copy;
return append(to_append.string());
}
// iterators
path::iterator path::begin()
char path::guess_separator() const
{
return parts_.begin();
if (system_separator() == '/') return '/';
if (is_absolute()) return internal_.at(2);
return internal_.find('/') == std::string::npos ? '/' : '\\';
}
path::iterator path::end()
bool operator==(const path &left, const path &right)
{
return parts_.end();
}
path::const_iterator path::begin() const
{
return cbegin();
}
path::const_iterator path::end() const
{
return cend();
}
path::const_iterator path::cbegin() const
{
return parts_.cbegin();
}
path::const_iterator path::cend() const
{
return parts_.cend();
}
path::reverse_iterator path::rbegin()
{
return parts_.rbegin();
}
path::reverse_iterator path::rend()
{
return parts_.rend();
}
path::const_reverse_iterator path::rbegin() const
{
return crbegin();
}
path::const_reverse_iterator path::rend() const
{
return crend();
}
path::const_reverse_iterator path::crbegin() const
{
return parts_.crbegin();
}
path::const_reverse_iterator path::crend() const
{
return parts_.crend();
}
std::string path::to_hash_string() const
{
return to_string('/');
return left.internal_ == right.internal_;
}
} // namespace xlnt

View File

@ -20,7 +20,7 @@ public:
}
TS_ASSERT(!temp.get_path().exists());
std::ofstream stream(temp.get_path().to_string());
std::ofstream stream(temp.get_path().string());
TS_ASSERT(temp.get_path().exists());
}
};

View File

@ -16,7 +16,7 @@ public:
{
std::vector<std::uint8_t> buffer;
wb.save(buffer);
wb.save(xlnt::path("C:\\Users\\Thomas\\Desktop\\a.xlsx"));
wb.save(xlnt::path("a.xlsx"));
xlnt::zip_file wb_archive(buffer);
xlnt::zip_file file_archive(file);

View File

@ -228,8 +228,8 @@ 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_package_relationship(xlnt::relationship::type::office_document));
TS_ASSERT_THROWS(m.get_part_relationships(xlnt::path("xl/workbook.xml")), xlnt::key_not_found);
TS_ASSERT(!m.has_relationship(xlnt::path("/"), xlnt::relationship::type::office_document));
TS_ASSERT_THROWS(m.get_relationships(xlnt::path("xl/workbook.xml")), xlnt::key_not_found);
}
void test_memory()

View File

@ -68,16 +68,16 @@ workbook workbook::minimal()
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);
wb.d_->manifest_.register_relationship(uri("/"), relationship::type::office_document,
uri("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);
auto ws_rel = wb.d_->manifest_.register_relationship(uri("workbook.xml"),
relationship::type::worksheet, uri("sheet1.xml"), target_mode::internal);
wb.d_->sheet_title_rel_id_map_[title] = ws_rel;
return wb;
@ -90,8 +90,8 @@ workbook workbook::empty_excel()
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_relationship(uri("/"), relationship::type::office_document,
uri("xl/workbook.xml"), target_mode::internal);
wb.d_->manifest_.register_default_type("rels",
"application/vnd.openxmlformats-package.relationships+xml");
@ -127,13 +127,13 @@ workbook workbook::empty_excel()
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_relationship(uri("/"), relationship::type::core_properties,
uri("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.d_->manifest_.register_relationship(uri("/"), relationship::type::extended_properties,
uri("docProps/app.xml"), target_mode::internal);
wb.set_application("Microsoft Excel");
wb.create_sheet();
@ -278,15 +278,15 @@ worksheet workbook::create_sheet()
auto sheet_id = d_->worksheets_.size() + 1;
std::string sheet_filename = "sheet" + std::to_string(sheet_id) + ".xml";
path sheet_path = constants::package_worksheets().append(sheet_filename);
d_->worksheets_.push_back(detail::worksheet_impl(this, sheet_id, title));
auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document);
d_->manifest_.register_override_type(sheet_path,
auto workbook_rel = d_->manifest_.get_relationship(path("/"), relationship::type::office_document);
uri sheet_uri(constants::package_worksheets().append(sheet_filename).string());
d_->manifest_.register_override_type(sheet_uri.get_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);
auto ws_rel = d_->manifest_.register_relationship(workbook_rel.get_target(),
relationship::type::worksheet, sheet_uri, target_mode::internal);
d_->sheet_title_rel_id_map_[title] = ws_rel;
return worksheet(&d_->worksheets_.back());
@ -611,14 +611,14 @@ const theme &workbook::get_theme() const
void workbook::set_theme(const theme &value)
{
auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document);
auto workbook_rel = d_->manifest_.get_relationship(path("/"), relationship::type::office_document);
if (!d_->manifest_.has_part_relationship(workbook_rel.get_target_uri(), relationship::type::theme))
if (!d_->manifest_.has_relationship(workbook_rel.get_target().get_path(), 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_->manifest_.register_relationship(workbook_rel.get_target(),
relationship::type::theme, uri(constants::part_theme().string()), target_mode::internal);
}
d_->has_theme_ = true;
@ -642,14 +642,14 @@ std::vector<named_range> workbook::get_named_ranges() const
std::size_t workbook::add_format(const format &to_add)
{
auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document);
auto workbook_rel = d_->manifest_.get_relationship(path("/"), relationship::type::office_document);
if (!d_->manifest_.has_part_relationship(workbook_rel.get_target_uri(), relationship::type::styles))
if (!d_->manifest_.has_relationship(workbook_rel.get_target().get_path(), 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);
d_->manifest_.register_relationship(workbook_rel.get_target(),
relationship::type::styles, uri(constants::part_styles().string()), target_mode::internal);
}
return d_->stylesheet_.add_format(to_add);
@ -657,14 +657,14 @@ std::size_t workbook::add_format(const format &to_add)
std::size_t workbook::add_style(const style &to_add)
{
auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document);
auto workbook_rel = d_->manifest_.get_relationship(path("/"), relationship::type::office_document);
if (!d_->manifest_.has_part_relationship(workbook_rel.get_target_uri(), relationship::type::styles))
if (!d_->manifest_.has_relationship(workbook_rel.get_target().get_path(), 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);
d_->manifest_.register_relationship(workbook_rel.get_target(),
relationship::type::styles, uri(constants::part_styles().string()), target_mode::internal);
}
return d_->stylesheet_.add_style(to_add);
@ -741,14 +741,14 @@ const std::vector<text> &workbook::get_shared_strings() const
void workbook::add_shared_string(const text &shared, bool allow_duplicates)
{
auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document);
auto workbook_rel = d_->manifest_.get_relationship(path("/"), relationship::type::office_document);
if (!d_->manifest_.has_part_relationship(workbook_rel.get_target_uri(), relationship::type::shared_string_table))
if (!d_->manifest_.has_relationship(workbook_rel.get_target().get_path(), relationship::type::styles))
{
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);
d_->manifest_.register_relationship(workbook_rel.get_target(),
relationship::type::shared_string_table, uri(constants::part_shared_strings().string()), target_mode::internal);
}
if (!allow_duplicates)
@ -776,9 +776,12 @@ bool workbook::contains(const std::string &sheet_title) const
void workbook::set_thumbnail(const std::vector<std::uint8_t> &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);
if (!d_->manifest_.has_relationship(path("/"), relationship::type::thumbnail))
{
d_->manifest_.register_default_type(extension, content_type);
d_->manifest_.register_relationship(uri("/"), relationship::type::thumbnail,
uri("docProps/thumbnail.jpeg"), target_mode::internal);
}
d_->thumbnail_.assign(thumbnail.begin(), thumbnail.end());
}

View File

@ -29,9 +29,8 @@ public:
void test_invalid_cell()
{
xlnt::workbook wb;
auto ws = wb.get_active_sheet();
TS_ASSERT_THROWS(xlnt::cell_reference invalid(xlnt::column_t((xlnt::column_t::index_t)0), 0), xlnt::invalid_cell_reference);
TS_ASSERT_THROWS(xlnt::cell_reference(xlnt::column_t((xlnt::column_t::index_t)0), 0),
xlnt::invalid_cell_reference);
}
void test_worksheet_dimension()

Binary file not shown.

View File

@ -59,7 +59,7 @@ public:
static xlnt::path get_data_directory(const std::string &append = "")
{
return xlnt::path("../../tests/data")
.make_absolute(get_executable_directory())
.resolve(get_executable_directory())
.append(xlnt::path(append));
}
@ -70,14 +70,14 @@ public:
throw std::runtime_error("destination file already exists and overwrite==false");
}
std::ifstream src(source.to_string(), std::ios::binary);
std::ofstream dst(destination.to_string(), std::ios::binary);
std::ifstream src(source.string(), std::ios::binary);
std::ofstream dst(destination.string(), std::ios::binary);
dst << src.rdbuf();
}
static void delete_file(const xlnt::path &path)
{
std::remove(path.to_string().c_str());
std::remove(path.string().c_str());
}
};

View File

@ -40,13 +40,13 @@ public:
{
if(path_.exists())
{
std::remove(path_.to_string().c_str());
std::remove(path_.string().c_str());
}
}
~temporary_file()
{
std::remove(path_.to_string().c_str());
std::remove(path_.string().c_str());
}
xlnt::path get_path() const { return path_; }

View File

@ -135,23 +135,47 @@ public:
auto left_info = left_archive.infolist();
auto right_info = right_archive.infolist();
if (left_info.size() != right_info.size()) return false;
if (left_info.size() != right_info.size())
{
std::cout << "left has a different number of files than right" << std::endl;
std::cout << "left has: ";
for (auto &info : left_info)
{
std::cout << info.filename.string() << ", ";
}
std::cout << std::endl;
std::cout << "right has: ";
for (auto &info : left_info)
{
std::cout << info.filename.string() << ", ";
}
std::cout << std::endl;
}
bool match = true;
for (auto left_member : left_info)
{
if (!right_archive.has_file(left_member)) return false;
if (!right_archive.has_file(left_member))
{
match = false;
std::cout << "right is missing file: " << left_member.filename.string() << std::endl;
continue;
}
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;
std::cout << left_member.filename.string() << std::endl;
match = false;
}
}
return true;
return match;
}
static bool workbooks_match(const xlnt::workbook &left, const xlnt::workbook &right)