From cf80c46b6671ebbd4308671ea96cc65b2c931a7e Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Fri, 5 Aug 2016 01:52:05 -0400 Subject: [PATCH] a little refactoring --- include/xlnt/cell/cell.hpp | 20 +- include/xlnt/packaging/default_type.hpp | 53 - include/xlnt/packaging/manifest.hpp | 233 +- include/xlnt/packaging/override_type.hpp | 53 - include/xlnt/packaging/relationship.hpp | 107 +- include/xlnt/utils/path.hpp | 7 +- include/xlnt/workbook/workbook.hpp | 53 +- include/xlnt/worksheet/worksheet.hpp | 7 - include/xlnt/xlnt.hpp | 2 - source/cell/cell.cpp | 12 +- source/cell/tests/test_cell.hpp | 2 +- source/detail/cell_impl.hpp | 2 +- source/detail/comment_serializer.cpp | 34 - source/detail/comment_serializer.hpp | 57 - source/detail/excel_serializer.cpp | 383 --- source/detail/excel_serializer.hpp | 185 -- source/detail/manifest_serializer.cpp | 97 - source/detail/manifest_serializer.hpp | 55 - source/detail/relationship_serializer.cpp | 108 - source/detail/relationship_serializer.hpp | 64 - source/detail/shared_strings_serializer.cpp | 183 -- source/detail/shared_strings_serializer.hpp | 48 - source/detail/style_serializer.cpp | 1261 ---------- source/detail/style_serializer.hpp | 82 - source/detail/theme_serializer.cpp | 370 --- source/detail/theme_serializer.hpp | 50 - source/detail/workbook_impl.hpp | 9 - source/detail/workbook_serializer.cpp | 329 --- source/detail/workbook_serializer.hpp | 69 - source/detail/worksheet_serializer.cpp | 600 ----- source/detail/worksheet_serializer.hpp | 59 - source/detail/xlsx_consumer.cpp | 1372 +++++++++++ source/detail/xlsx_consumer.hpp | 126 + source/detail/xlsx_producer.cpp | 2062 +++++++++++++++++ .../{xlsx_writer.hpp => xlsx_producer.hpp} | 63 +- source/detail/xlsx_writer.cpp | 325 --- source/packaging/default_type.cpp | 58 - source/packaging/manifest.cpp | 376 ++- source/packaging/override_type.cpp | 60 - source/packaging/override_type.hpp | 14 - source/packaging/relationship.cpp | 115 +- source/packaging/tests/test_core.hpp | 30 +- source/styles/tests/test_stylesheet.hpp | 31 +- source/utils/path.cpp | 12 +- source/workbook/tests/test_read.hpp | 111 +- source/workbook/tests/test_style_reader.hpp | 4 +- source/workbook/tests/test_theme.hpp | 9 +- source/workbook/tests/test_workbook.hpp | 38 +- source/workbook/tests/test_write.hpp | 201 +- source/workbook/tests/test_write_workbook.hpp | 87 +- source/workbook/workbook.cpp | 301 +-- source/worksheet/tests/test_worksheet.hpp | 2 +- source/worksheet/worksheet.cpp | 14 +- tests/helpers/xml_helper.hpp | 49 + 54 files changed, 4665 insertions(+), 5389 deletions(-) delete mode 100644 include/xlnt/packaging/default_type.hpp delete mode 100644 include/xlnt/packaging/override_type.hpp delete mode 100644 source/detail/comment_serializer.cpp delete mode 100644 source/detail/comment_serializer.hpp delete mode 100644 source/detail/excel_serializer.cpp delete mode 100644 source/detail/excel_serializer.hpp delete mode 100644 source/detail/manifest_serializer.cpp delete mode 100644 source/detail/manifest_serializer.hpp delete mode 100644 source/detail/relationship_serializer.cpp delete mode 100644 source/detail/relationship_serializer.hpp delete mode 100644 source/detail/shared_strings_serializer.cpp delete mode 100644 source/detail/shared_strings_serializer.hpp delete mode 100644 source/detail/style_serializer.cpp delete mode 100644 source/detail/style_serializer.hpp delete mode 100644 source/detail/theme_serializer.cpp delete mode 100644 source/detail/theme_serializer.hpp delete mode 100644 source/detail/workbook_serializer.cpp delete mode 100644 source/detail/workbook_serializer.hpp delete mode 100644 source/detail/worksheet_serializer.cpp delete mode 100644 source/detail/worksheet_serializer.hpp create mode 100644 source/detail/xlsx_consumer.cpp create mode 100644 source/detail/xlsx_consumer.hpp create mode 100644 source/detail/xlsx_producer.cpp rename source/detail/{xlsx_writer.hpp => xlsx_producer.hpp} (56%) delete mode 100644 source/detail/xlsx_writer.cpp delete mode 100644 source/packaging/default_type.cpp delete mode 100644 source/packaging/override_type.cpp delete mode 100644 source/packaging/override_type.hpp diff --git a/include/xlnt/cell/cell.hpp b/include/xlnt/cell/cell.hpp index b4f4f7b1..49ed6402 100644 --- a/include/xlnt/cell/cell.hpp +++ b/include/xlnt/cell/cell.hpp @@ -44,17 +44,24 @@ class font; class format; class number_format; class protection; -class relationship; class style; class workbook; class worksheet; +class xlsx_consumer; +class xlsx_producer; struct date; struct datetime; struct time; struct timedelta; -namespace detail { struct cell_impl; } +namespace detail { + +class xlsx_consumer; +class xlsx_producer; +struct cell_impl; + +} // namespace detail /// /// Describes cell associated properties. @@ -151,9 +158,9 @@ public: // hyperlink /// - /// Return a relationship representing this cell's hyperlink. + /// Return the URL of this cell's hyperlink. /// - relationship get_hyperlink() const; + std::string get_hyperlink() const; /// /// Add a hyperlink to this cell pointing to the URI of the given value. @@ -183,6 +190,8 @@ public: const format &get_format() const; void set_format(const format &new_format); + + void set_format_id(std::size_t format_id); void clear_format(); @@ -380,7 +389,8 @@ private: // make these friends so they can use the private constructor friend class style; friend class worksheet; - friend class worksheet_serializer; + friend class detail::xlsx_consumer; + friend class detail::xlsx_producer; friend struct detail::cell_impl; void guess_type_and_set_value(const std::string &value); diff --git a/include/xlnt/packaging/default_type.hpp b/include/xlnt/packaging/default_type.hpp deleted file mode 100644 index 654425ea..00000000 --- a/include/xlnt/packaging/default_type.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2014-2016 Thomas Fussell -// Copyright (c) 2010-2015 openpyxl -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE -// -// @license: http://www.opensource.org/licenses/mit-license.php -// @author: see AUTHORS file -#pragma once - -#include - -#include - -namespace xlnt { - -/// -/// Default types in an OOXML package are identified by their extension. -/// All files in the package with this extension will be assigned the given -/// content type unless an override type for the exact file is provided. -/// -class XLNT_CLASS default_type -{ -public: - default_type(); - default_type(const std::string &extension, const std::string &content_type); - default_type(const default_type &other); - default_type &operator=(const default_type &other); - - std::string get_extension() const; - std::string get_content_type() const; - -private: - std::string extension_; - std::string content_type_; -}; - -} // namespace xlnt diff --git a/include/xlnt/packaging/manifest.hpp b/include/xlnt/packaging/manifest.hpp index 3a076444..82ae89c8 100644 --- a/include/xlnt/packaging/manifest.hpp +++ b/include/xlnt/packaging/manifest.hpp @@ -27,37 +27,236 @@ #include #include -#include -#include +#include #include 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 +}; + /// -/// The manifest keeps track of all files the OOXML package and -/// their type. +/// The manifest keeps track of all files in the OOXML package and +/// their type and relationships. /// class XLNT_CLASS manifest { public: - using default_types_container = std::unordered_map; - using override_types_container = std::unordered_map>; - + /// + /// Convenience method for clear_types() and clear_relationships() + /// void clear(); - bool has_default_type(const std::string &extension) const; - std::string get_default_type(const std::string &extension) const; - const default_types_container &get_default_types() const; - void add_default_type(const std::string &extension, const std::string &content_type); + /// + /// Convenince method for clear_default_types() and clear_override_types() + /// + void clear_types(); - bool has_override_type(const path &part) const; - std::string get_override_type(const path &part) const; - const override_types_container &get_override_types() const; - void add_override_type(const path &part, const std::string &content_type); + /// + /// Unregisters every default content type (i.e. type based on part extension). + /// + void clear_default_types(); + + /// + /// Unregisters every content type for every part except default types. + /// + void clear_override_types(); + + /// + /// Convenince method for clear_package_relationships() and clear_part_relationships() + /// + void clear_relationships(); + + /// + /// Unregisters every relationship with the package root as the source. + /// + void clear_package_relationships(); + + /// + /// Unregisters every relationship except those with the package root as the source. + /// + void clear_part_relationships(); + + /// + /// Returns true if the manifest contains a package relationship with the given type. + /// + bool has_package_relationship(relationship::type type) const; + + /// + /// Returns true if the manifest contains a relationship with the given type with part as the source. + /// + bool has_part_relationship(const path &part, relationship::type type) const; + + relationship get_package_relationship(relationship::type type) const; + + std::vector get_package_relationships(relationship::type type) const; + + relationship get_part_relationship(const path &part, relationship::type type) const; + + std::vector get_part_relationships(const path &part, relationship::type type) const; + + /// + /// Given the path to a part, returns the content type of the part as + /// a content_type enum value or content_type::unknown if it isn't known. + /// + content_type get_part_content_type(const path &part) const; + + /// + /// Given the path to a part, returns the content type of the part as a string. + /// + std::string get_part_content_type_string(const path &part) const; + + /// + /// Registers a part of the given type at the standard path and creates a + /// relationship with the new part as a target of "source". The type of the + /// relationship is inferred based on the provided types. + /// + void register_part(const path &part, const path &parent, const std::string &content_type, relationship::type relation); + + /// + /// + /// + void register_part(const path &parent, const relationship &rel, const std::string &content_type); + + /// + /// Registers a package part of the given type at the standard path and creates a + /// relationship with the package root as the source. The type of the + /// relationship is inferred based on the provided type. + /// + void register_package_part(const path &part, const std::string &content_type, relationship::type relation); + + /// + /// Unregisters the path of the part of the given type and removes all relationships + /// with the part as a source or target. + /// + void unregister_part(const path &part); + + /// + /// Returns true if the part at the given path has been registered in this manifest. + /// + bool has_part(const path &part) const; + + /// + /// Returns the path of every registered part in this manifest. + /// + std::vector get_parts() const; + + /// + /// Returns every registered relationship with the package root as the source. + /// + std::vector get_package_relationships() const; + + /// + /// Returns the package relationship with the given ID. + /// + relationship get_package_relationship(const std::string &rel_id); + + /// + /// Returns every registered relationship with the part of the given type + /// as the source. + /// + std::vector get_part_relationships(const path &part) const; + + /// + /// Returns the registered relationship with the part of the given type + /// as the source and the ID matching the provided ID. + /// + relationship get_part_relationship(const path &part, const std::string &rel_id) const; + + /// + /// + /// + std::string register_external_package_relationship(relationship::type type, const std::string &target_uri); + + /// + /// + /// + std::string register_external_package_relationship(relationship::type type, const std::string &target_uri, const std::string &rel_id); + + /// + /// + /// + std::string register_external_relationship(const path &source_part, relationship::type type, const std::string &target_uri); + + /// + /// + /// + std::string register_external_relationship(const path &source_part, relationship::type type, const std::string &target_uri, const std::string &rel_id); + + /// + /// Returns true if a default content type for the extension has been registered. + /// + bool has_default_type(const std::string &extension) const; + + /// + /// Returns a vector of all extensions with registered default content types. + /// + std::vector get_default_type_extensions() const; + + /// + /// Returns the registered default content type for parts of the given extension. + /// + std::string get_default_type(const std::string &extension) const; + + /// + /// Associates the given extension with the given content type. + /// + void register_default_type(const std::string &extension, const std::string &content_type); + + /// + /// Unregisters the default content type for the given extension. + /// + void unregister_default_type(const std::string &extension); private: - default_types_container default_types_; - override_types_container override_types_; + struct part_info + { + std::string content_type; + std::vector relationships; + }; + + std::string next_package_relationship_id() const;\ + + std::string next_relationship_id(const path &part) const; + + std::unordered_map> part_infos_; + + std::vector package_relationships_; + + std::unordered_map extension_content_type_map_; }; } // namespace xlnt diff --git a/include/xlnt/packaging/override_type.hpp b/include/xlnt/packaging/override_type.hpp deleted file mode 100644 index 645cb793..00000000 --- a/include/xlnt/packaging/override_type.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2014-2016 Thomas Fussell -// Copyright (c) 2010-2015 openpyxl -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE -// -// @license: http://www.opensource.org/licenses/mit-license.php -// @author: see AUTHORS file -#pragma once - -#include - -#include -#include - -namespace xlnt { - -/// -/// An override_type applies a different content type to a file which -/// already has a default content type for its extension. -/// -class XLNT_CLASS override_type -{ -public: - override_type(); - override_type(const path &part, const std::string &content_type); - override_type(const override_type &other); - override_type &operator=(const override_type &other); - - path get_part() const; - std::string get_content_type() const; - -private: - path part_; - std::string content_type_; -}; - -} // namespace xlnt diff --git a/include/xlnt/packaging/relationship.hpp b/include/xlnt/packaging/relationship.hpp index 42b2af2c..e60dc560 100644 --- a/include/xlnt/packaging/relationship.hpp +++ b/include/xlnt/packaging/relationship.hpp @@ -26,6 +26,7 @@ #include #include +#include namespace xlnt { @@ -34,34 +35,61 @@ namespace xlnt { /// enum class XLNT_CLASS target_mode { + /// + /// The relationship references a resource that is external to the package. + /// + internal, /// /// The relationship references a part that is inside the package. /// - external, - /// - /// The relationship references a resource that is external to the package. - /// - internal + external }; /// /// All package relationships must be one of these defined types. /// -enum class relationship_type +enum class XLNT_CLASS relationship_type { - invalid, - hyperlink, - drawing, - worksheet, - chartsheet, - shared_strings, - styles, - theme, - extended_properties, - core_properties, - office_document, - custom_xml, - thumbnail + unknown, + + // Package + core_properties, + extended_properties, + custom_properties, + office_document, + thumbnail, + printer_settings, + + // SpreadsheetML + 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, + theme, + revision_log, + shared_workbook_user_data, + single_cell_table_definitions, + styles, + table_definition, + volatile_dependencies, + workbook, + worksheet, + + hyperlink, + image }; /// @@ -73,47 +101,44 @@ class XLNT_CLASS relationship public: using type = relationship_type; - static type type_from_string(const std::string &type_string); - - static std::string type_to_string(type t); - relationship(); - relationship(const std::string &t, const std::string &r_id = "", const std::string &target_uri = ""); - - relationship(type t, const std::string &r_id = "", const std::string &target_uri = ""); + relationship(const std::string &id, type t, const path &target, target_mode mode); /// - /// gets a string that identifies the relationship. + /// Returns a string of the form rId# that identifies the relationship. /// std::string get_id() const; - /// - /// gets the URI of the package or part that owns the relationship. - /// - std::string get_source_uri() const; + /// + /// Returns the type of this relationship. + /// + type get_type() const; /// - /// gets a value that indicates whether the target of the relationship is or External to the Package. + /// Returns whether the target of the relationship is internal or external to the package. /// target_mode get_target_mode() const; /// - /// gets the URI of the target resource of the relationship. + /// Returns the URI of the package part this relationship points to. /// - std::string get_target_uri() const; - - type get_type() const; - - std::string get_type_string() const; + path get_target_uri() const; + /// + /// Returns true if and only if rhs is equal to this relationship. + /// bool operator==(const relationship &rhs) const; + /// + /// Returns true if and only if rhs is not equal to this relationship. + /// + bool operator!=(const relationship &rhs) const; + private: + std::string id_; type type_; - std::string id_; - std::string source_uri_; - std::string target_uri_; + path target_uri_; target_mode target_mode_; }; diff --git a/include/xlnt/utils/path.hpp b/include/xlnt/utils/path.hpp index 4b652527..57f924bc 100644 --- a/include/xlnt/utils/path.hpp +++ b/include/xlnt/utils/path.hpp @@ -106,7 +106,12 @@ public: /// /// Return the last component of this path. /// - std::string basename(); + std::string basename() const; + + /// + /// Return the part of the path following the last . in the basename. + /// + std::string extension() const; // conversion diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index a387685f..b7acd4fd 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -68,7 +68,10 @@ enum class calendar; enum class relationship_type; namespace detail { +struct stylesheet; struct workbook_impl; +class xlsx_consumer; +class xlsx_producer; } // namespace detail /// @@ -183,14 +186,14 @@ public: /// This may throw an exception if the sheet isn't found. /// Use workbook::contains(const std::string &) to make sure the sheet exists. /// - worksheet get_sheet_by_name(const std::string &sheet_name); + worksheet get_sheet_by_title(const std::string &sheet_name); /// /// Return the const worksheet with the given name. /// This may throw an exception if the sheet isn't found. /// Use workbook::contains(const std::string &) to make sure the sheet exists. /// - const worksheet get_sheet_by_name(const std::string &sheet_name) const; + const worksheet get_sheet_by_title(const std::string &sheet_name) const; /// /// Return the worksheet at the given index. @@ -202,6 +205,16 @@ public: /// const worksheet get_sheet_by_index(std::size_t index) const; + /// + /// Return the worksheet with a sheetId of id. + /// + worksheet get_sheet_by_id(std::size_t id); + + /// + /// Return the const worksheet with a sheetId of id. + /// + const worksheet get_sheet_by_id(std::size_t id) const; + /// /// Return true if this workbook contains a sheet with the given name. /// @@ -360,15 +373,15 @@ public: // serialization - bool save(std::vector &data); - bool save(const std::string &filename); - bool save(const xlnt::path &filename); - bool save(std::ostream &stream); + void save(std::vector &data); + void save(const std::string &filename); + void save(const xlnt::path &filename); + void save(std::ostream &stream); - bool load(const std::vector &data); - bool load(const std::string &filename); - bool load(const xlnt::path &filename); - bool load(std::istream &stream); + void load(const std::vector &data); + void load(const std::string &filename); + void load(const xlnt::path &filename); + void load(std::istream &stream); void set_code_name(const std::string &code_name); @@ -396,22 +409,12 @@ public: style &create_style(const std::string &name); std::size_t add_style(const style &new_style); void clear_styles(); - const std::vector