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 { 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> /// <summary>
/// The manifest keeps track of all files in the OOXML package and /// The manifest keeps track of all files in the OOXML package and
/// their type and relationships. /// their type and relationships.
@ -76,122 +40,69 @@ class XLNT_CLASS manifest
{ {
public: public:
/// <summary> /// <summary>
/// Convenience method for clear_types() and clear_relationships() /// Unregisters all default and override type and all relationships and known parts.
/// </summary> /// </summary>
void clear(); 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> /// <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> /// </summary>
void clear_types(); bool has_relationship(const path &source, relationship::type type) const;
/// <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;
/// <summary> /// <summary>
/// Returns true if the manifest contains a relationship with the given type with part as the source. /// Returns true if the manifest contains a relationship with the given type with part as the source.
/// </summary> /// </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> /// <summary>
/// Returns true if the manifest contains a relationship with the given type with part as the source. ///
/// </summary> /// </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; // Content Types
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;
/// <summary> /// <summary>
/// Given the path to a part, returns the content type of the part as a string. /// Given the path to a part, returns the content type of the part as a string.
/// </summary> /// </summary>
std::string get_content_type_string(const path &part) const; std::string get_content_type(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);
// Default Content Types
/// <summary> /// <summary>
/// Returns true if a default content type for the extension has been registered. /// Returns true if a default content type for the extension has been registered.
/// </summary> /// </summary>
@ -200,9 +111,7 @@ public:
/// <summary> /// <summary>
/// Returns a vector of all extensions with registered default content types. /// Returns a vector of all extensions with registered default content types.
/// </summary> /// </summary>
std::vector<std::string> get_default_type_extensions() const; std::vector<std::string> get_extensions_with_default_types() const;
std::vector<path> get_parts_with_relationships() const;
/// <summary> /// <summary>
/// Returns the registered default content type for parts of the given extension. /// Returns the registered default content type for parts of the given extension.
@ -212,29 +121,50 @@ public:
/// <summary> /// <summary>
/// Associates the given extension with the given content type. /// Associates the given extension with the given content type.
/// </summary> /// </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> /// <summary>
/// Unregisters the default content type for the given extension. /// Unregisters the default content type for the given extension.
/// </summary> /// </summary>
void unregister_default_type(const std::string &extension); 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: 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::string next_relationship_id(const path &part) const;
std::unordered_map<path, part_info> part_infos_; std::unordered_map<std::string, std::string> default_content_types_;
std::vector<relationship> package_relationships_; std::unordered_map<path, std::string> override_content_types_;
std::unordered_map<std::string, std::string> extension_content_type_map_; std::unordered_map<path, std::unordered_map<std::string, relationship>> relationships_;
}; };
} // namespace xlnt } // namespace xlnt

View File

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

View File

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

View File

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

View File

@ -71,9 +71,9 @@ struct workbook_impl
guess_types_(other.guess_types_), guess_types_(other.guess_types_),
data_only_(other.data_only_), data_only_(other.data_only_),
stylesheet_(other.stylesheet_), stylesheet_(other.stylesheet_),
manifest_(other.manifest_),
has_theme_(other.has_theme_), has_theme_(other.has_theme_),
theme_(other.theme_), theme_(other.theme_),
manifest_(other.manifest_),
write_core_properties_(other.write_core_properties_), write_core_properties_(other.write_core_properties_),
creator_(other.creator_), creator_(other.creator_),
last_modified_by_(other.last_modified_by_), 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"; 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) std::size_t string_to_size_t(const std::string &s)
{ {
#if ULLONG_MAX == SIZE_MAX #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> template<typename T>
T from_string(const std::string &string); 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()); document.load_string(archive.read(part).c_str());
auto root_node = document.child("Relationships"); auto root_node = document.child("Relationships");
xlnt::uri source(part.string());
for (auto relationship_node : root_node.children("Relationship")) for (auto relationship_node : root_node.children("Relationship"))
{ {
std::string id(relationship_node.attribute("Id").value()); std::string id(relationship_node.attribute("Id").value());
std::string type_string(relationship_node.attribute("Type").value()); std::string type_string(relationship_node.attribute("Type").value());
auto type = from_string<xlnt::relationship::type>(type_string); 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; 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) void check_document_type(const std::string &document_content_type)
{ {
if (document_content_type != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" 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(); auto &manifest = destination_.get_manifest();
read_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; 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()) switch (rel.get_type())
{ {
@ -752,20 +712,9 @@ void xlsx_consumer::populate_workbook()
read_custom_property(document.root()); read_custom_property(document.root());
break; break;
case relationship::type::office_document: case relationship::type::office_document:
check_document_type(manifest.get_content_type_string(rel.get_target_uri())); check_document_type(manifest.get_content_type(rel.get_target().get_path()));
workbook_part = rel.get_target_uri();
read_workbook(document.root()); read_workbook(document.root());
break; 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: case relationship::type::calculation_chain:
read_calculation_chain(document.root()); read_calculation_chain(document.root());
break; break;
@ -799,13 +748,17 @@ void xlsx_consumer::populate_workbook()
case relationship::type::volatile_dependencies: case relationship::type::volatile_dependencies:
read_volatile_dependencies(document.root()); read_volatile_dependencies(document.root());
break; 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; 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()) switch (rel.get_type())
{ {
@ -818,6 +771,8 @@ void xlsx_consumer::populate_workbook()
case relationship::type::worksheet: case relationship::type::worksheet:
read_worksheet(document.root(), rel.get_id()); read_worksheet(document.root(), rel.get_id());
break; break;
default:
break;
} }
} }
@ -846,18 +801,6 @@ void xlsx_consumer::read_manifest()
const auto root_node = document.child("Types"); const auto root_node = document.child("Types");
auto &manifest = destination_.get_manifest(); 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()) for (const auto child : root_node.children())
{ {
if (child.name() == std::string("Default")) if (child.name() == std::string("Default"))
@ -874,8 +817,9 @@ void xlsx_consumer::read_manifest()
for (const auto &package_rel : package_rels) for (const auto &package_rel : package_rels)
{ {
manifest.register_package_relationship(package_rel.get_type(), manifest.register_relationship(uri("/"),
package_rel.get_target_uri(), package_rel.get_type(),
package_rel.get_target(),
package_rel.get_target_mode(), package_rel.get_target_mode(),
package_rel.get_id()); package_rel.get_id());
} }
@ -886,14 +830,13 @@ void xlsx_consumer::read_manifest()
|| relationship_source.filename.extension() != ".rels") continue; || relationship_source.filename.extension() != ".rels") continue;
auto part_rels = read_relationships(relationship_source.filename, source_); auto part_rels = read_relationships(relationship_source.filename, source_);
auto source_uri = relationship_source.filename.parent().parent() uri source(relationship_source.filename.parent().parent()
.append(relationship_source.filename.basename()); .append(relationship_source.filename.filename()).string());
for (const auto part_rel : part_rels) for (const auto part_rel : part_rels)
{ {
auto part = source_uri; manifest.register_relationship(source, part_rel.get_type(),
manifest.register_part_relationship(source_uri, part_rel.get_type(), part_rel.get_target(), part_rel.get_target_mode(), part_rel.get_id());
part_rel.get_target_uri(), 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; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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 // 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; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_connections(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_custom_property(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_custom_xml_mappings(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_dialogsheet(const pugi::xml_node root, const std::string &title)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_external_workbook_references(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_metadata(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_pivot_table(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) 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; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_shared_workbook(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_shared_workbook_user_data(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) 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; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) 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; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_drawings(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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 // Unknown Parts
@ -1360,14 +1303,14 @@ void xlsx_consumer::read_unknown_parts(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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) void xlsx_consumer::read_unknown_relationships(const pugi::xml_node root)
{ {
pugi::xml_document document; pugi::xml_document document;
document.load_string(source_.read(path("[Content Types].xml")).c_str()); 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 } // 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("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("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) 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() void xlsx_producer::populate_archive()
{ {
write_manifest(); 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; pugi::xml_document document;
bool write_document = true;
switch (rel.get_type()) switch (rel.get_type())
{ {
case relationship::type::core_properties: case relationship::type::core_properties:
write_core_properties(document.root()); write_core_properties(rel, document.root());
break; break;
case relationship::type::extended_properties: case relationship::type::extended_properties:
write_extended_properties(document.root()); write_extended_properties(rel, document.root());
break; break;
case relationship::type::custom_properties: case relationship::type::custom_properties:
write_custom_properties(document.root()); write_custom_properties(rel, document.root());
break; break;
case relationship::type::office_document: case relationship::type::office_document:
write_workbook(document.root()); write_workbook(rel, document.root());
workbook_part = rel.get_target_uri();
break; break;
case relationship::type::thumbnail: case relationship::type::thumbnail:
destination_.write_string( write_thumbnail(rel);
std::string(source_.get_thumbnail().begin(), source_.get_thumbnail().end()), write_document = false;
rel.get_target_uri()); break;
continue;
} default:
break;
}
write_document_to_archive(document, rel.get_target_uri(), destination_); if (write_document)
} {
write_document_to_archive(document, rel.get_target().get_path(), 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());
} }
// Unknown Parts // Unknown Parts
@ -687,7 +640,7 @@ void xlsx_producer::write_manifest()
auto types_node = content_types_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"); 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"); auto default_node = types_node.append_child("Default");
default_node.append_attribute("Extension").set_value(extension.c_str()); 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()); 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"); auto override_node = types_node.append_child("Override");
override_node.append_attribute("PartName").set_value(("/" + part.to_string('/')).c_str()); override_node.append_attribute("PartName").set_value(part.string().c_str());
auto content_type = source_.get_manifest().get_content_type_string(part); auto content_type = source_.get_manifest().get_override_type(part);
override_node.append_attribute("ContentType").set_value(content_type.c_str()); 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; pugi::xml_document part_rels_document;
write_relationships(part_rels, part_rels_document.root()); 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(part_rels_document, rels_path, destination_);
} }
write_document_to_archive(content_types_document, path("[Content_Types].xml"), 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"); 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"); 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"); 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 // 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; 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 sheets_node = workbook_node.append_child("sheets");
auto defined_names_node = workbook_node.append_child("definedNames"); 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_) for (const auto ws : source_)
{ {
auto sheet_rel_id = source_.d_->sheet_title_rel_id_map_[ws.get_title()]; 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"); auto sheet_node = sheets_node.append_child("sheet");
sheet_node.append_attribute("name").set_value(ws.get_title().c_str()); 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()); 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 // 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"); 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"); 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").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"); 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("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"); 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"); 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").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; std::vector<relationship> hyperlink_sheet_rels;
for (const auto &sheet_rel : 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) for (const auto &hyperlink_rel : hyperlink_sheet_rels)
{ {
auto hyperlink_node = hyperlinks_node.append_child("hyperlink"); 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("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()); 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 // 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 // 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 } // namespace detail
} // namepsace xlnt } // namepsace xlnt

View File

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

View File

@ -21,310 +21,169 @@
// //
// @license: http://www.opensource.org/licenses/mit-license.php // @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file // @author: see AUTHORS file
#include <algorithm> #include <algorithm>
#include <unordered_set>
#include <xlnt/packaging/manifest.hpp> #include <xlnt/packaging/manifest.hpp>
#include <xlnt/utils/exceptions.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 { namespace xlnt {
void manifest::clear() void manifest::clear()
{ {
clear_types(); default_content_types_.clear();
clear_relationships(); override_content_types_.clear();
part_infos_.clear(); relationships_.clear();
} }
void manifest::clear_types() bool manifest::has_relationship(const path &part, relationship::type type) const
{ {
clear_default_types(); if (relationships_.find(part) == relationships_.end()) return false;
clear_override_types();
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(); if (relationships_.find(part) == relationships_.end()) throw key_not_found();
}
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;
}
}
for (const auto &rel : relationships_.at(part))
{
if (rel.second.get_type() == type) return rel.second;
}
throw key_not_found(); 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; std::vector<relationship> matches;
for (const auto &rel : package_relationships_) for (const auto &rel : relationships_.at(part))
{ {
if (rel.get_type() == type) if (rel.second.get_type() == type)
{ {
matches.push_back(rel); matches.push_back(rel.second);
} }
} }
return matches; 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 (has_override_type(part))
{ {
if (rel.get_type() == type) return get_override_type(part);
{ }
return rel;
} if (has_default_type(part.extension()))
} {
return get_default_type(part.extension());
throw key_not_found(); }
}
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;
} }
void manifest::register_override_type(const path &part, const std::string &content_type) 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) std::vector<path> manifest::get_parts_with_overriden_types() const
{
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> overriden; 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; 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(); 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()) return register_relationship(source, type, target, mode, next_relationship_id(source.get_path()));
{
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();
} }
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; relationships_[source.get_path()][rel_id] = relationship(rel_id, type, source, target, mode);
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);
return rel_id; return rel_id;
} }
bool manifest::has_default_type(const std::string &extension) const 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; 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); 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 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(); 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) 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) void manifest::unregister_default_type(const std::string &extension)
{ {
extension_content_type_map_.erase(extension); default_content_types_.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);
} }
std::string manifest::next_relationship_id(const path &part) const 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; std::size_t index = 1;
const auto &part_rels = relationships_.at(part);
const auto &part_rels = get_part_relationships(part); while (part_rels.find("rId" + std::to_string(index)) != part_rels.end())
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())
{ {
++index; ++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 } // 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), : id_(id),
type_(t), type_(t),
source_(source), source_(source),
@ -44,17 +44,17 @@ std::string relationship::get_id() const
return id_; return id_;
} }
target_mode relationship::get_mode() const target_mode relationship::get_target_mode() const
{ {
return mode_; return mode_;
} }
path relationship::get_source() const uri relationship::get_source() const
{ {
return source_; return source_;
} }
path relationship::get_target() const uri relationship::get_target() const
{ {
return target_; return target_;
} }
@ -68,7 +68,7 @@ bool relationship::operator==(const relationship &rhs) const
{ {
return type_ == rhs.type_ return type_ == rhs.type_
&& id_ == rhs.id_ && id_ == rhs.id_
&& source_ == the.source_ && source_ == rhs.source_
&& target_ == rhs.target_ && target_ == rhs.target_
&& mode_ == rhs.mode_; && mode_ == rhs.mode_;
} }

View File

@ -17,13 +17,13 @@ public:
bool files_equal(const xlnt::path &left, const xlnt::path &right) 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; return true;
} }
std::ifstream stream_left(left.to_string(), std::ios::binary); std::ifstream stream_left(left.string(), std::ios::binary);
std::ifstream stream_right(right.to_string(), std::ios::binary); std::ifstream stream_right(right.string(), std::ios::binary);
while(stream_left && stream_right) while(stream_left && stream_right)
{ {
@ -48,9 +48,9 @@ public:
{ {
temporary_file temp; 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); 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); f.save(out_stream);
out_stream.close(); out_stream.close();
@ -62,7 +62,7 @@ public:
temporary_file temp_file; temporary_file temp_file;
std::vector<std::uint8_t> source_bytes; 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) while(in_stream)
{ {
@ -122,7 +122,7 @@ public:
{ {
xlnt::zip_file f(existing_file); xlnt::zip_file f(existing_file);
auto info = f.getinfo(xlnt::path("text.txt")); 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() 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) void zip_file::load(const path &filename)
{ {
filename_ = filename; filename_ = filename;
std::ifstream stream(filename.to_string(), std::ios::binary); std::ifstream stream(filename.string(), std::ios::binary);
if (!stream.good()) if (!stream.good())
{ {
throw invalid_file(filename.to_string()); throw invalid_file(filename.string());
} }
reset(); reset();
@ -197,7 +197,7 @@ void zip_file::load(const path &filename)
if (buffer_.empty()) if (buffer_.empty())
{ {
throw invalid_file(filename.to_string() + " - empty file"); throw invalid_file(filename.string() + " - empty file");
} }
remove_comment(); remove_comment();
@ -220,7 +220,7 @@ void zip_file::load(const std::vector<unsigned char> &bytes)
void zip_file::save(const path &filename) void zip_file::save(const path &filename)
{ {
filename_ = filename; filename_ = filename;
std::ofstream stream(filename.to_string(), std::ios::binary); std::ofstream stream(filename.string(), std::ios::binary);
save(stream); save(stream);
} }
@ -341,7 +341,7 @@ zip_info zip_file::getinfo(const path &name)
start_read(); 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) if (index == -1)
{ {
@ -462,19 +462,15 @@ void zip_file::write_file(const path &filename)
if (filename.is_absolute()) if (filename.is_absolute())
{ {
arcname = path(); auto split = filename.split();
bool first = true;
auto iter = split.begin() + 1;
arcname = path();
for (auto part : filename) while (iter != split.end())
{ {
if (first) arcname.append(*iter++);
{ }
first = false;
continue;
}
arcname.append(part);
}
} }
write_file(filename, arcname); 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) 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; std::stringstream ss;
ss << file.rdbuf(); ss << file.rdbuf();
@ -497,13 +493,13 @@ void zip_file::write_string(const std::string &bytes, const path &arcname)
start_write(); 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); bytes.data(), bytes.size(), MZ_BEST_COMPRESSION);
} }
void zip_file::write_string(const std::string &bytes, const zip_info &info) 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"); 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()); 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()), info.comment.c_str(), static_cast<mz_uint16>(info.comment.size()),
MZ_BEST_COMPRESSION, 0, crc); MZ_BEST_COMPRESSION, 0, crc);
} }
@ -524,7 +520,7 @@ std::string zip_file::read(const zip_info &info)
{ {
std::size_t size; std::size_t size;
void *data_raw = mz_zip_reader_extract_file_to_heap(archive_.get(), 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) if (data_raw == nullptr)
{ {
@ -550,7 +546,7 @@ bool zip_file::has_file(const path &name)
start_read(); 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; 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 g = static_cast<std::uint8_t>((x >> 8) & 0xff);
auto b = static_cast<std::uint8_t>(x & 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) 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) 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) bool is_root(const std::string &part)
{ {
return part.size() == 2 && part.back() == ':' return part == "/" || (part.size() == 2 && part.back() == ':'
&& part.front() >= 'A' && part.front() <= 'Z'; && 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());
} }
#else #else
@ -67,21 +59,7 @@ char system_separator()
bool is_root(const std::string &part) bool is_root(const std::string &part)
{ {
return part.empty(); return part == "/";
}
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]);
} }
#endif #endif
@ -110,23 +88,6 @@ std::vector<std::string> split_path(const std::string &path, char delim)
return split; 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) bool file_exists(const std::string &path)
{ {
struct stat info; struct stat info;
@ -143,9 +104,9 @@ bool directory_exists(const std::string path)
namespace xlnt { namespace xlnt {
char path::separator() char path::system_separator()
{ {
return system_separator(); return ::system_separator();
} }
path::path() 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) : internal_(path_string)
{
}
path::path(const std::string &path_string, char sep) : parts_(split_path(path_string, sep))
{ {
} }
@ -170,91 +127,79 @@ bool path::is_relative() const
bool path::is_absolute() 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 bool path::is_root() const
{ {
return parts_.size() == 1 && ::is_root(parts_.front()); return ::is_root(internal_);
} }
path path::parent() const path path::parent() const
{ {
path result; if (is_root()) return *this;
result.parts_ = parts_;
if (result.parts_.size() > 1)
{
result.parts_.pop_back();
}
else
{
return path("");
}
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; 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 std::string path::extension() const
{ {
auto base = basename(); auto base = filename();
auto last_dot = base.find_last_of('.'); auto last_dot = base.find_last_of('.');
if (last_dot == std::string::npos) return ""; return last_dot == std::string::npos ? "" : base.substr(last_dot + 1);
return base.substr(last_dot + 1);
} }
// conversion // conversion
std::string path::to_string(char sep) const std::string path::string() const
{ {
if (parts_.empty()) return ""; return internal_;
std::string result;
for (const auto &part : parts_)
{
result.append(part);
result.push_back(sep);
}
result.pop_back();
return result;
} }
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()) if (is_absolute())
{ {
return *this; return *this;
} }
path copy = base_path; path copy(base_path.internal_);
for (const auto &part : parts_) for (const auto &part : split())
{ {
if (part == ".") copy = copy.append(part);
{
continue;
}
else if (part == ".." && copy.parts_.size() > 1)
{
copy.parts_.pop_back();
}
else
{
copy.parts_.push_back(part);
}
} }
return copy; return copy;
} }
// filesystem attributes // filesystem attributes
@ -266,120 +211,56 @@ bool path::exists() const
bool path::is_directory() const bool path::is_directory() const
{ {
return directory_exists(to_string()); return directory_exists(string());
} }
bool path::is_file() const bool path::is_file() const
{ {
return file_exists(to_string()); return file_exists(string());
} }
// filesystem // filesystem
std::string path::read_contents() const std::string path::read_contents() const
{ {
std::ifstream f(to_string()); std::ifstream f(string());
std::ostringstream ss; std::ostringstream ss;
ss << f.rdbuf(); ss << f.rdbuf();
return ss.str(); return ss.str();
} }
// mutators // append
path &path::append(const std::string &to_append)
{
parts_.push_back(to_append);
return *this;
}
path path::append(const std::string &to_append) const path path::append(const std::string &to_append) const
{ {
path copy(*this); path copy(internal_);
copy.append(to_append);
if (!internal_.empty() && internal_.back() != guess_separator())
return copy; {
} copy.internal_.push_back(guess_separator());
}
path &path::append(const path &to_append)
{ copy.internal_.append(to_append);
parts_.insert(parts_.end(), to_append.begin(), to_append.end());
return *this; return copy;
} }
path path::append(const path &to_append) const path path::append(const path &to_append) const
{ {
path copy(*this); return append(to_append.string());
copy.append(to_append);
return copy;
} }
// iterators char path::guess_separator() const
path::iterator path::begin()
{ {
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(); return left.internal_ == right.internal_;
}
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('/');
} }
} // namespace xlnt } // namespace xlnt

View File

@ -20,7 +20,7 @@ public:
} }
TS_ASSERT(!temp.get_path().exists()); 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()); TS_ASSERT(temp.get_path().exists());
} }
}; };

View File

@ -16,7 +16,7 @@ public:
{ {
std::vector<std::uint8_t> buffer; std::vector<std::uint8_t> buffer;
wb.save(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 wb_archive(buffer);
xlnt::zip_file file_archive(file); xlnt::zip_file file_archive(file);

View File

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

View File

@ -68,16 +68,16 @@ workbook workbook::minimal()
wb.d_->manifest_.register_override_type(path("workbook.xml"), wb.d_->manifest_.register_override_type(path("workbook.xml"),
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"); "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml");
wb.d_->manifest_.register_package_relationship(relationship::type::office_document, wb.d_->manifest_.register_relationship(uri("/"), relationship::type::office_document,
path("workbook.xml"), target_mode::internal); uri("workbook.xml"), target_mode::internal);
std::string title("Sheet"); std::string title("Sheet");
wb.d_->worksheets_.push_back(detail::worksheet_impl(&wb, 1, title)); wb.d_->worksheets_.push_back(detail::worksheet_impl(&wb, 1, title));
wb.d_->manifest_.register_override_type(path("sheet1.xml"), wb.d_->manifest_.register_override_type(path("sheet1.xml"),
"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"); "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml");
auto ws_rel = wb.d_->manifest_.register_part_relationship(path("workbook.xml"), auto ws_rel = wb.d_->manifest_.register_relationship(uri("workbook.xml"),
relationship::type::worksheet, path("sheet1.xml"), target_mode::internal); relationship::type::worksheet, uri("sheet1.xml"), target_mode::internal);
wb.d_->sheet_title_rel_id_map_[title] = ws_rel; wb.d_->sheet_title_rel_id_map_[title] = ws_rel;
return wb; return wb;
@ -90,8 +90,8 @@ workbook workbook::empty_excel()
wb.d_->manifest_.register_override_type(path("xl/workbook.xml"), wb.d_->manifest_.register_override_type(path("xl/workbook.xml"),
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"); "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml");
wb.d_->manifest_.register_package_relationship(relationship::type::office_document, wb.d_->manifest_.register_relationship(uri("/"), relationship::type::office_document,
path("xl/workbook.xml"), target_mode::internal); uri("xl/workbook.xml"), target_mode::internal);
wb.d_->manifest_.register_default_type("rels", wb.d_->manifest_.register_default_type("rels",
"application/vnd.openxmlformats-package.relationships+xml"); "application/vnd.openxmlformats-package.relationships+xml");
@ -127,13 +127,13 @@ workbook workbook::empty_excel()
wb.d_->manifest_.register_override_type(path("docProps/core.xml"), wb.d_->manifest_.register_override_type(path("docProps/core.xml"),
"application/vnd.openxmlformats-package.coreproperties+xml"); "application/vnd.openxmlformats-package.coreproperties+xml");
wb.d_->manifest_.register_package_relationship(relationship::type::core_properties, wb.d_->manifest_.register_relationship(uri("/"), relationship::type::core_properties,
path("docProps/core.xml"), target_mode::internal); uri("docProps/core.xml"), target_mode::internal);
wb.d_->manifest_.register_override_type(path("docProps/app.xml"), wb.d_->manifest_.register_override_type(path("docProps/app.xml"),
"application/vnd.openxmlformats-officedocument.extended-properties+xml"); "application/vnd.openxmlformats-officedocument.extended-properties+xml");
wb.d_->manifest_.register_package_relationship(relationship::type::extended_properties, wb.d_->manifest_.register_relationship(uri("/"), relationship::type::extended_properties,
path("docProps/app.xml"), target_mode::internal); uri("docProps/app.xml"), target_mode::internal);
wb.set_application("Microsoft Excel"); wb.set_application("Microsoft Excel");
wb.create_sheet(); wb.create_sheet();
@ -278,15 +278,15 @@ worksheet workbook::create_sheet()
auto sheet_id = d_->worksheets_.size() + 1; auto sheet_id = d_->worksheets_.size() + 1;
std::string sheet_filename = "sheet" + std::to_string(sheet_id) + ".xml"; 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)); d_->worksheets_.push_back(detail::worksheet_impl(this, sheet_id, title));
auto workbook_rel = d_->manifest_.get_package_relationship(relationship::type::office_document); auto workbook_rel = d_->manifest_.get_relationship(path("/"), relationship::type::office_document);
d_->manifest_.register_override_type(sheet_path, 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"); "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml");
auto ws_rel = d_->manifest_.register_part_relationship(workbook_rel.get_target_uri(), auto ws_rel = d_->manifest_.register_relationship(workbook_rel.get_target(),
relationship::type::worksheet, sheet_path, target_mode::internal); relationship::type::worksheet, sheet_uri, target_mode::internal);
d_->sheet_title_rel_id_map_[title] = ws_rel; d_->sheet_title_rel_id_map_[title] = ws_rel;
return worksheet(&d_->worksheets_.back()); return worksheet(&d_->worksheets_.back());
@ -611,14 +611,14 @@ const theme &workbook::get_theme() const
void workbook::set_theme(const theme &value) 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(), d_->manifest_.register_override_type(constants::part_theme(),
"application/vnd.openxmlformats-officedocument.theme+xml"); "application/vnd.openxmlformats-officedocument.theme+xml");
d_->manifest_.register_part_relationship(workbook_rel.get_target_uri(), d_->manifest_.register_relationship(workbook_rel.get_target(),
relationship::type::theme, constants::part_theme(), target_mode::internal); relationship::type::theme, uri(constants::part_theme().string()), target_mode::internal);
} }
d_->has_theme_ = true; 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) 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(), d_->manifest_.register_override_type(constants::part_styles(),
"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"); "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml");
d_->manifest_.register_part_relationship(workbook_rel.get_target_uri(), d_->manifest_.register_relationship(workbook_rel.get_target(),
relationship::type::styles, constants::part_styles(), target_mode::internal); relationship::type::styles, uri(constants::part_styles().string()), target_mode::internal);
} }
return d_->stylesheet_.add_format(to_add); 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) 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(), d_->manifest_.register_override_type(constants::part_styles(),
"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"); "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml");
d_->manifest_.register_part_relationship(workbook_rel.get_target_uri(), d_->manifest_.register_relationship(workbook_rel.get_target(),
relationship::type::styles, constants::part_styles(), target_mode::internal); relationship::type::styles, uri(constants::part_styles().string()), target_mode::internal);
} }
return d_->stylesheet_.add_style(to_add); 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) 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(), d_->manifest_.register_override_type(constants::part_shared_strings(),
"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"); "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml");
d_->manifest_.register_part_relationship(workbook_rel.get_target_uri(), d_->manifest_.register_relationship(workbook_rel.get_target(),
relationship::type::shared_string_table, constants::part_shared_strings(), target_mode::internal); relationship::type::shared_string_table, uri(constants::part_shared_strings().string()), target_mode::internal);
} }
if (!allow_duplicates) 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, void workbook::set_thumbnail(const std::vector<std::uint8_t> &thumbnail,
const std::string &extension, const std::string &content_type) const std::string &extension, const std::string &content_type)
{ {
d_->manifest_.register_default_type(extension, content_type); if (!d_->manifest_.has_relationship(path("/"), relationship::type::thumbnail))
d_->manifest_.register_package_relationship(relationship::type::thumbnail, {
path("docProps/thumbnail.jpeg"), target_mode::internal); 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()); d_->thumbnail_.assign(thumbnail.begin(), thumbnail.end());
} }

View File

@ -29,9 +29,8 @@ public:
void test_invalid_cell() void test_invalid_cell()
{ {
xlnt::workbook wb; TS_ASSERT_THROWS(xlnt::cell_reference(xlnt::column_t((xlnt::column_t::index_t)0), 0),
auto ws = wb.get_active_sheet(); xlnt::invalid_cell_reference);
TS_ASSERT_THROWS(xlnt::cell_reference invalid(xlnt::column_t((xlnt::column_t::index_t)0), 0), xlnt::invalid_cell_reference);
} }
void test_worksheet_dimension() 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 = "") static xlnt::path get_data_directory(const std::string &append = "")
{ {
return xlnt::path("../../tests/data") return xlnt::path("../../tests/data")
.make_absolute(get_executable_directory()) .resolve(get_executable_directory())
.append(xlnt::path(append)); .append(xlnt::path(append));
} }
@ -70,14 +70,14 @@ public:
throw std::runtime_error("destination file already exists and overwrite==false"); throw std::runtime_error("destination file already exists and overwrite==false");
} }
std::ifstream src(source.to_string(), std::ios::binary); std::ifstream src(source.string(), std::ios::binary);
std::ofstream dst(destination.to_string(), std::ios::binary); std::ofstream dst(destination.string(), std::ios::binary);
dst << src.rdbuf(); dst << src.rdbuf();
} }
static void delete_file(const xlnt::path &path) 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()) if(path_.exists())
{ {
std::remove(path_.to_string().c_str()); std::remove(path_.string().c_str());
} }
} }
~temporary_file() ~temporary_file()
{ {
std::remove(path_.to_string().c_str()); std::remove(path_.string().c_str());
} }
xlnt::path get_path() const { return path_; } xlnt::path get_path() const { return path_; }

View File

@ -135,23 +135,47 @@ public:
auto left_info = left_archive.infolist(); auto left_info = left_archive.infolist();
auto right_info = right_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) 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 left_member_contents = left_archive.read(left_member);
auto right_member_contents = right_archive.read(left_member.filename); auto right_member_contents = right_archive.read(left_member.filename);
if (!strings_match(left_member_contents, right_member_contents)) if (!strings_match(left_member_contents, right_member_contents))
{ {
std::cout << left_member.filename.to_string() << std::endl; std::cout << left_member.filename.string() << std::endl;
return false; match = false;
} }
} }
return true; return match;
} }
static bool workbooks_match(const xlnt::workbook &left, const xlnt::workbook &right) static bool workbooks_match(const xlnt::workbook &left, const xlnt::workbook &right)