From 02f7d4243ecfcbd6b03174228290653983f7a634 Mon Sep 17 00:00:00 2001 From: Lars Uffmann Date: Fri, 20 Dec 2024 02:05:38 +0100 Subject: [PATCH] 2024-12-20 added bool XLXmlFile::valid() addressing issues #312 and - en passant - #310 --- OpenXLSX/headers/XLContentTypes.hpp | 3 +- OpenXLSX/headers/XLProperties.hpp | 8 +- OpenXLSX/headers/XLSharedStrings.hpp | 4 +- OpenXLSX/headers/XLSheet.hpp | 31 ++++++- OpenXLSX/headers/XLStyles.hpp | 24 ++--- OpenXLSX/headers/XLWorkbook.hpp | 10 +- OpenXLSX/headers/XLXmlFile.hpp | 21 ++++- OpenXLSX/sources/XLContentTypes.cpp | 4 +- OpenXLSX/sources/XLDocument.cpp | 6 +- OpenXLSX/sources/XLProperties.cpp | 14 ++- OpenXLSX/sources/XLRelationships.cpp | 2 +- OpenXLSX/sources/XLSharedStrings.cpp | 9 +- OpenXLSX/sources/XLSheet.cpp | 6 +- OpenXLSX/sources/XLStyles.cpp | 133 ++++++++++++++++----------- OpenXLSX/sources/XLWorkbook.cpp | 8 +- OpenXLSX/sources/XLXmlFile.cpp | 1 + README.md | 5 + 17 files changed, 200 insertions(+), 89 deletions(-) diff --git a/OpenXLSX/headers/XLContentTypes.hpp b/OpenXLSX/headers/XLContentTypes.hpp index cbe420b8..d13304fb 100644 --- a/OpenXLSX/headers/XLContentTypes.hpp +++ b/OpenXLSX/headers/XLContentTypes.hpp @@ -245,7 +245,8 @@ namespace OpenXLSX */ std::vector getContentItems(); - // ---------- Protected Member Functions ---------- // + private: // ---------- Private Member Variables ---------- // + static constexpr const char *m_classFile = "[Content_Types].xml"; // passed to XLXmlFile constructor for underlying m_xmlName }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLProperties.hpp b/OpenXLSX/headers/XLProperties.hpp index d0afa785..70338b35 100644 --- a/OpenXLSX/headers/XLProperties.hpp +++ b/OpenXLSX/headers/XLProperties.hpp @@ -67,6 +67,8 @@ namespace OpenXLSX class OPENXLSX_EXPORT XLProperties : public XLXmlFile { private: + static constexpr const char *m_classFile = "docProps/core.xml"; // passed to XLXmlFile constructor for underlying m_xmlName + /** * @brief constructor helper function: create core.xml content from template * @param workbook @@ -81,7 +83,7 @@ namespace OpenXLSX /** * @brief */ - XLProperties() = default; + XLProperties(); /** * @brief @@ -169,6 +171,8 @@ namespace OpenXLSX class OPENXLSX_EXPORT XLAppProperties : public XLXmlFile { private: + static constexpr const char *m_classFile = "docProps/app.xml"; // passed to XLXmlFile constructor for underlying m_xmlName + /** * @brief constructor helper function: create app.xml content from template * @param workbook @@ -183,7 +187,7 @@ namespace OpenXLSX /** * @brief */ - XLAppProperties() = default; + XLAppProperties(); /** * @brief enable XLAppProperties to re-create a worksheet list in docProps/app.xml element from workbookXml diff --git a/OpenXLSX/headers/XLSharedStrings.hpp b/OpenXLSX/headers/XLSharedStrings.hpp index b84b2d94..5bbd1728 100644 --- a/OpenXLSX/headers/XLSharedStrings.hpp +++ b/OpenXLSX/headers/XLSharedStrings.hpp @@ -80,7 +80,7 @@ namespace OpenXLSX /** * @brief */ - XLSharedStrings() = default; + XLSharedStrings(); /** * @brief @@ -172,6 +172,8 @@ namespace OpenXLSX private: std::deque* m_stringCache {}; /** < Each string must have an unchanging memory address; hence the use of std::deque */ + + static constexpr const char *m_classFile = "xl/sharedStrings.xml"; // passed to XLXmlFile constructor for underlying m_xmlName }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLSheet.hpp b/OpenXLSX/headers/XLSheet.hpp index 47c07453..c4147244 100644 --- a/OpenXLSX/headers/XLSheet.hpp +++ b/OpenXLSX/headers/XLSheet.hpp @@ -93,15 +93,17 @@ namespace OpenXLSX /** * @brief Constructor */ - XLSheetBase() : XLXmlFile(nullptr) {}; + XLSheetBase() : XLXmlFile(nullptr, m_classFile) {}; /** * @brief The constructor. There are no default constructor, so all parameters must be provided for * constructing an XLAbstractSheet object. Since this is a pure abstract class, instantiation is only * possible via one of the derived classes. * @param xmlData + * @param classFile base name of the underlying base class (without sheet numbering) */ - explicit XLSheetBase(XLXmlData* xmlData) : XLXmlFile(xmlData) {}; + explicit XLSheetBase(XLXmlData* xmlData) : XLXmlFile(xmlData, m_classFile) {}; + explicit XLSheetBase(XLXmlData* xmlData, std::string classFile) : XLXmlFile(xmlData, classFile) {}; /** * @brief The copy constructor. @@ -299,6 +301,12 @@ namespace OpenXLSX .setParam("sheetID", relationshipID()) .setParam("cloneName", newName)); } + + //---------------------------------------------------------------------------------------------------------------------- + // Private Member Variables + //---------------------------------------------------------------------------------------------------------------------- + private: + static constexpr const char *m_classFile = "(XLSheetBase: uninitialized)"; // passed to XLXmlFile constructor for underlying m_xmlName }; /** @@ -319,7 +327,7 @@ namespace OpenXLSX /** * @brief Default constructor */ - XLWorksheet() : XLSheetBase(nullptr) {}; + XLWorksheet() : XLSheetBase(nullptr, m_classFile) {}; /** * @brief @@ -578,7 +586,13 @@ namespace OpenXLSX */ bool setActive_impl(); + //---------------------------------------------------------------------------------------------------------------------- + // Private Member Variables + //---------------------------------------------------------------------------------------------------------------------- + private: XLMergeCells m_merges; /**< class handling the */ + + static constexpr const char *m_classFile = "xl/worksheets/sheet#.xml"; // passed to XLXmlFile constructor for underlying m_xmlName }; /** @@ -597,7 +611,7 @@ namespace OpenXLSX /** * @brief Default constructor */ - XLChartsheet() : XLSheetBase(nullptr) {}; + XLChartsheet() : XLSheetBase(nullptr, m_classFile) {}; /** * @brief @@ -660,6 +674,12 @@ namespace OpenXLSX * @param selected */ void setSelected_impl(bool selected); + + //---------------------------------------------------------------------------------------------------------------------- + // Private Member Variables + //---------------------------------------------------------------------------------------------------------------------- + private: + static constexpr const char *m_classFile = "XLChartsheet class: refer to ::name() for details"; // passed to XLXmlFile constructor for underlying m_xmlName }; /** @@ -833,9 +853,10 @@ namespace OpenXLSX //---------------------------------------------------------------------------------------------------------------------- // Private Member Variables //---------------------------------------------------------------------------------------------------------------------- - private: std::variant m_sheet; /**< */ + + static constexpr const char *m_classFile = "(XLSheet: uninitialized)"; // passed to XLXmlFile constructor for underlying m_xmlName }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLStyles.hpp b/OpenXLSX/headers/XLStyles.hpp index cb6e0b7a..a7c852be 100644 --- a/OpenXLSX/headers/XLStyles.hpp +++ b/OpenXLSX/headers/XLStyles.hpp @@ -2113,7 +2113,7 @@ namespace OpenXLSX /** * @brief */ - XLStyles() = default; + XLStyles(); /** * @brief @@ -2129,30 +2129,30 @@ namespace OpenXLSX ~XLStyles(); /** - * @brief - * @param other + * @brief The copy constructor. + * @param other an existing styles object other will be also referred by this */ - XLStyles(const XLStyles& other) = default; + XLStyles(const XLStyles& other); /** - * @brief - * @param other + * @brief The move constructor. + * @param other an existing styles object other will be assigned to this */ - XLStyles(XLStyles&& other) noexcept = default; + XLStyles(XLStyles&& other) noexcept; /** - * @brief + * @brief copy assignment * @param other * @return */ - XLStyles& operator=(const XLStyles& other) = default; + XLStyles& operator=(const XLStyles& other); /** - * @brief + * @brief move assignment * @param other * @return */ - XLStyles& operator=(XLStyles&& other) noexcept = default; + XLStyles& operator=(XLStyles&& other) noexcept; /** * @brief Get the number formats object @@ -2206,6 +2206,8 @@ namespace OpenXLSX std::unique_ptr m_cellStyleFormats; // handle to the underlying cell style formats descriptions std::unique_ptr m_cellFormats; // handle to the underlying cell formats descriptions std::unique_ptr m_cellStyles; // handle to the underlying cell styles + + static constexpr const char *m_classFile = "xl/styles.xml"; // passed to XLXmlFile constructor for underlying m_xmlName }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 700601b1..b20d3336 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -89,14 +89,16 @@ namespace OpenXLSX /** * @brief Default constructor. Creates an empty ('null') XLWorkbook object. */ - XLWorkbook() = default; + XLWorkbook(); /** * @brief Constructor. Takes a pointer to an XLXmlData object (stored in the parent XLDocument object). * @param xmlData A pointer to the underlying XLXmlData object, which holds the XML data. - * @note Do not create an XLWorkbook object directly. Get access through the an XLDocument object. + * @param pathTo the path to the workbook file origin of xmlData, used to initialize m_classFile + * @note Do not create an XLWorkbook object directly. Access via XLDocument::workbook(). */ explicit XLWorkbook(XLXmlData* xmlData); + explicit XLWorkbook(XLXmlData* xmlData, std::string pathTo); /** * @brief Copy Constructor. @@ -394,6 +396,10 @@ namespace OpenXLSX * @return true if sheetNode can be considered visible (and could be activated) */ bool isVisible(XMLNode const& sheetNode) const; + + private: // ---------- Private Member Variables ---------- // + static constexpr const char * m_classFileDefault = "xl/workbook.xml"; + std::string m_classFile; // passed to XLXmlFile constructor for underlying m_xmlName, defaults to m_classFileDefault }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLXmlFile.hpp b/OpenXLSX/headers/XLXmlFile.hpp index 77012a4c..50d3fe7a 100644 --- a/OpenXLSX/headers/XLXmlFile.hpp +++ b/OpenXLSX/headers/XLXmlFile.hpp @@ -78,8 +78,10 @@ namespace OpenXLSX /** * @brief Constructor. Creates an object based on the xmlData input. * @param xmlData An XLXmlData object with the XML data to be represented by the object. + * @param xmlName optional name of the underlying XML file within the document */ explicit XLXmlFile(XLXmlData* xmlData); + explicit XLXmlFile(XLXmlData* xmlData, std::string xmlName); /** * @brief Copy constructor. Default implementation used. @@ -98,6 +100,20 @@ namespace OpenXLSX */ ~XLXmlFile(); + /** + * @brief check whether class is linked to a valid XML file + * @return true if the class should have a link to valid data + * @return false if accessing any other sheet properties / methods could cause a segmentation fault + * @note for example, if an XLSheet is created with a default constructor, XLSheetBase::valid() (derived from XLXmlFile) would return false + */ + bool valid() const { return m_xmlData != nullptr; } + + /** + * @brief Method to retrieve a descriptive name of the class link to the document XML + * @return A std::string with the document's XML file + */ + std::string const & xmlName() const { return m_xmlName; } + /** * @brief The copy assignment operator. The default implementation has been used. * @param other The object to copy. @@ -156,8 +172,9 @@ namespace OpenXLSX */ const XMLDocument& xmlDocument() const; - protected: // ===== PRIVATE MEMBER VARIABLES - XLXmlData* m_xmlData { nullptr }; /**< The underlying XML data object. */ + protected: // ===== PRIVATE MEMBER VARIABLES + XLXmlData* m_xmlData { nullptr }; /**< The underlying XML data object. */ + std::string m_xmlName { "uninitialized" }; /**< informational: should be initialized with path to the underlying XML file within the document */ }; } // namespace OpenXLSX diff --git a/OpenXLSX/sources/XLContentTypes.cpp b/OpenXLSX/sources/XLContentTypes.cpp index d16aeab9..6a794a9f 100644 --- a/OpenXLSX/sources/XLContentTypes.cpp +++ b/OpenXLSX/sources/XLContentTypes.cpp @@ -224,12 +224,12 @@ std::string XLContentItem::path() const { return m_contentNode->attribute("PartN /** * @details */ -XLContentTypes::XLContentTypes() = default; +XLContentTypes::XLContentTypes() : XLXmlFile(nullptr, m_classFile) {} /** * @details */ -XLContentTypes::XLContentTypes(XLXmlData* xmlData) : XLXmlFile(xmlData) {} +XLContentTypes::XLContentTypes(XLXmlData* xmlData) : XLXmlFile(xmlData, m_classFile) {} /** * @details diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index f0b085a5..9b3a0174 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -592,7 +592,7 @@ void XLDocument::open(const std::string& fileName) } // ===== Open the workbook and document property items - m_workbook = XLWorkbook(getXmlData(workbookPath)); + m_workbook = XLWorkbook(getXmlData(workbookPath), workbookPath); // 2024-05-31: moved XLWorkbook object creation up in code worksheets info can be used for XLAppProperties generation from scratch // ===== 2024-06-03: creating core and extended properties if they do not exist @@ -693,11 +693,13 @@ void XLDocument::create(const std::string& fileName) { create( fileName, XLForce void XLDocument::close() { if (m_archive.isValid()) m_archive.close(); + // m_suppressWarnings shall remain in the configured setting + m_filePath.clear(); - m_data.clear(); m_xmlSavingDeclaration = XLXmlSavingDeclaration(); + m_data.clear(); m_sharedStringCache.clear(); // 2024-12-18 BUGFIX: clear shared strings cache - addresses issue #283 m_sharedStrings = XLSharedStrings(); // diff --git a/OpenXLSX/sources/XLProperties.cpp b/OpenXLSX/sources/XLProperties.cpp index f481e68a..35d3b52b 100644 --- a/OpenXLSX/sources/XLProperties.cpp +++ b/OpenXLSX/sources/XLProperties.cpp @@ -246,10 +246,15 @@ void XLProperties::createFromTemplate() prop.text().set("2019-08-16T00:34:26Z"); } +/** + * @details default constructor + */ +XLProperties::XLProperties() : XLXmlFile(nullptr, m_classFile) {} + /** * @details */ -XLProperties::XLProperties(XLXmlData* xmlData) : XLXmlFile(xmlData) +XLProperties::XLProperties(XLXmlData* xmlData) : XLXmlFile(xmlData, m_classFile) { XMLNode doc = xmlData->getXmlDocument()->document_element(); XMLNode child = doc.first_child_of_type(pugi::node_element); @@ -382,11 +387,16 @@ void XLAppProperties::createFromTemplate(XMLDocument const & workbookXml) props.append_child("AppVersion").text().set("16.0300"); } +/** + * @details default constructor + */ +XLAppProperties::XLAppProperties() : XLXmlFile(nullptr, m_classFile) {} + /** * @details */ XLAppProperties::XLAppProperties(XLXmlData* xmlData, XMLDocument const & workbookXml) - : XLXmlFile(xmlData) + : XLXmlFile(xmlData, m_classFile) { XMLNode doc = xmlData->getXmlDocument()->document_element(); XMLNode child = doc.first_child_of_type(pugi::node_element); diff --git a/OpenXLSX/sources/XLRelationships.cpp b/OpenXLSX/sources/XLRelationships.cpp index 05fb4679..c17e1180 100644 --- a/OpenXLSX/sources/XLRelationships.cpp +++ b/OpenXLSX/sources/XLRelationships.cpp @@ -347,7 +347,7 @@ bool XLRelationshipItem::empty() const { return m_relationshipNode->empty(); } * used to return all relationship targets as absolute paths within the XLSX archive */ XLRelationships::XLRelationships(XLXmlData* xmlData, std::string pathTo) - : XLXmlFile(xmlData) + : XLXmlFile(xmlData, pathTo) { constexpr const char *relFolder = "_rels/"; // all relationships are stored in a (sub-)folder named "_rels/" static const size_t relFolderLen = strlen(relFolder); // 2024-08-23: strlen seems to not be accepted in a constexpr in VS2019 with c++17 diff --git a/OpenXLSX/sources/XLSharedStrings.cpp b/OpenXLSX/sources/XLSharedStrings.cpp index 36cffa00..b7cf6c46 100644 --- a/OpenXLSX/sources/XLSharedStrings.cpp +++ b/OpenXLSX/sources/XLSharedStrings.cpp @@ -55,13 +55,18 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. using namespace OpenXLSX; +/** + * @details Default constructor + */ +XLSharedStrings::XLSharedStrings() : XLXmlFile(nullptr, m_classFile) {} + /** * @details Constructs a new XLSharedStrings object. Only one (common) object is allowed per XLDocument instance. * A filepath to the underlying XML file must be provided. */ XLSharedStrings::XLSharedStrings(XLXmlData* xmlData, std::deque* stringCache) - : XLXmlFile(xmlData), - m_stringCache(stringCache) + : XLXmlFile(xmlData, m_classFile), + m_stringCache(stringCache) { XMLDocument & doc = xmlDocument(); if (doc.document_element().empty()) // handle a bad (no document element) xl/sharedStrings.xml diff --git a/OpenXLSX/sources/XLSheet.cpp b/OpenXLSX/sources/XLSheet.cpp index b4f6c721..a336cb84 100644 --- a/OpenXLSX/sources/XLSheet.cpp +++ b/OpenXLSX/sources/XLSheet.cpp @@ -117,7 +117,7 @@ namespace OpenXLSX * @details The constructor begins by constructing an instance of its superclass, XLAbstractXMLFile. The default * sheet type is WorkSheet and the default sheet state is Visible. */ -XLSheet::XLSheet(XLXmlData* xmlData) : XLXmlFile(xmlData) +XLSheet::XLSheet(XLXmlData* xmlData) : XLXmlFile(xmlData, m_classFile) { if (xmlData->getXmlType() == XLContentType::Worksheet) m_sheet = XLWorksheet(xmlData); @@ -251,7 +251,7 @@ void XLSheet::print(std::basic_ostream& ostr) const { xmlDocument().docume * For example, columns with identical formatting are by default grouped under the same node. However, this makes it more difficult to * parse, so the constructor reconfigures it so each column has it's own formatting. */ -XLWorksheet::XLWorksheet(XLXmlData* xmlData) : XLSheetBase(xmlData) +XLWorksheet::XLWorksheet(XLXmlData* xmlData) : XLSheetBase(xmlData, m_classFile) { // ===== Read the dimensions of the Sheet and set data members accordingly. if (const std::string dimensions = xmlDocument().document_element().child("dimension").attribute("ref").value(); @@ -765,7 +765,7 @@ bool XLWorksheet::setRowFormat(uint32_t rowNumber, XLStyleIndex cellFormatIndex) /** * @details Constructor */ -XLChartsheet::XLChartsheet(XLXmlData* xmlData) : XLSheetBase(xmlData) {} +XLChartsheet::XLChartsheet(XLXmlData* xmlData) : XLSheetBase(xmlData, m_classFile) {} /** * @details Destructor. Default implementation used. diff --git a/OpenXLSX/sources/XLStyles.cpp b/OpenXLSX/sources/XLStyles.cpp index 9e67c09e..bc25cb07 100644 --- a/OpenXLSX/sources/XLStyles.cpp +++ b/OpenXLSX/sources/XLStyles.cpp @@ -649,7 +649,6 @@ XLNumberFormats::XLNumberFormats(const XMLNode& numberFormats) XMLNode node = numberFormats.first_child_of_type(pugi::node_element); while (not node.empty()) { std::string nodeName = node.name(); - // std::cout << "XMLNumberFormats constructor, node name is " << nodeName << std::endl; if (nodeName == "numFmt") m_numberFormats.push_back(XLNumberFormat(node)); else @@ -666,16 +665,12 @@ XLNumberFormats::~XLNumberFormats() XLNumberFormats::XLNumberFormats(const XLNumberFormats& other) : m_numberFormatsNode(std::make_unique(*other.m_numberFormatsNode)), m_numberFormats(other.m_numberFormats) -{ - // std::cout << __func__ << " copy constructor" << std::endl; -} +{} XLNumberFormats::XLNumberFormats(XLNumberFormats&& other) : m_numberFormatsNode(std::move(other.m_numberFormatsNode)), m_numberFormats(std::move(other.m_numberFormats)) -{ - // std::cout << __func__ << " move constructor" << std::endl; -} +{} /** @@ -683,7 +678,6 @@ XLNumberFormats::XLNumberFormats(XLNumberFormats&& other) */ XLNumberFormats& XLNumberFormats::operator=(const XLNumberFormats& other) { - // std::cout << "XLNumberFormats::" << __func__ << " copy assignment" << std::endl; if (&other != this) { *m_numberFormatsNode = *other.m_numberFormatsNode; m_numberFormats.clear(); @@ -932,16 +926,12 @@ XLFonts::~XLFonts() XLFonts::XLFonts(const XLFonts& other) : m_fontsNode(std::make_unique(*other.m_fontsNode)), m_fonts(other.m_fonts) -{ - // std::cout << __func__ << " copy constructor" << std::endl; -} +{} XLFonts::XLFonts(XLFonts&& other) : m_fontsNode(std::move(other.m_fontsNode)), m_fonts(std::move(other.m_fonts)) -{ - // std::cout << __func__ << " move constructor" << std::endl; -} +{} /** @@ -949,7 +939,6 @@ XLFonts::XLFonts(XLFonts&& other) */ XLFonts& XLFonts::operator=(const XLFonts& other) { - // std::cout << "XLFonts::" << __func__ << " copy assignment" << std::endl; if (&other != this) { *m_fontsNode = *other.m_fontsNode; m_fonts.clear(); @@ -1177,16 +1166,12 @@ XLGradientStops::~XLGradientStops() XLGradientStops::XLGradientStops(const XLGradientStops& other) : m_gradientNode(std::make_unique(*other.m_gradientNode)), m_gradientStops(other.m_gradientStops) -{ - // std::cout << __func__ << " copy constructor" << std::endl; -} +{} XLGradientStops::XLGradientStops(XLGradientStops&& other) : m_gradientNode(std::move(other.m_gradientNode)), m_gradientStops(std::move(other.m_gradientStops)) -{ - // std::cout << __func__ << " move constructor" << std::endl; -} +{} /** @@ -1194,7 +1179,6 @@ XLGradientStops::XLGradientStops(XLGradientStops&& other) */ XLGradientStops& XLGradientStops::operator=(const XLGradientStops& other) { - // std::cout << "XLGradientStops::" << __func__ << " copy assignment" << std::endl; if (&other != this) { *m_gradientNode = *other.m_gradientNode; m_gradientStops.clear(); @@ -1501,16 +1485,12 @@ XLFills::~XLFills() XLFills::XLFills(const XLFills& other) : m_fillsNode(std::make_unique(*other.m_fillsNode)), m_fills(other.m_fills) -{ - // std::cout << __func__ << " copy constructor" << std::endl; -} +{} XLFills::XLFills(XLFills&& other) : m_fillsNode(std::move(other.m_fillsNode)), m_fills(std::move(other.m_fills)) -{ - // std::cout << __func__ << " move constructor" << std::endl; -} +{} /** @@ -1518,7 +1498,6 @@ XLFills::XLFills(XLFills&& other) */ XLFills& XLFills::operator=(const XLFills& other) { - // std::cout << "XLFills::" << __func__ << " copy assignment" << std::endl; if (&other != this) { *m_fillsNode = *other.m_fillsNode; m_fills.clear(); @@ -1792,16 +1771,12 @@ XLBorders::~XLBorders() XLBorders::XLBorders(const XLBorders& other) : m_bordersNode(std::make_unique(*other.m_bordersNode)), m_borders(other.m_borders) -{ - // std::cout << __func__ << " copy constructor" << std::endl; -} +{} XLBorders::XLBorders(XLBorders&& other) : m_bordersNode(std::move(other.m_bordersNode)), m_borders(std::move(other.m_borders)) -{ - // std::cout << __func__ << " move constructor" << std::endl; -} +{} /** @@ -1809,7 +1784,6 @@ XLBorders::XLBorders(XLBorders&& other) */ XLBorders& XLBorders::operator=(const XLBorders& other) { - // std::cout << "XLBorders::" << __func__ << " copy assignment" << std::endl; if (&other != this) { *m_bordersNode = *other.m_bordersNode; m_borders.clear(); @@ -2159,17 +2133,13 @@ XLCellFormats::XLCellFormats(const XLCellFormats& other) : m_cellFormatsNode(std::make_unique(*other.m_cellFormatsNode)), m_cellFormats(other.m_cellFormats), m_permitXfId(other.m_permitXfId) -{ - // std::cout << __func__ << " copy constructor" << std::endl; -} +{} XLCellFormats::XLCellFormats(XLCellFormats&& other) : m_cellFormatsNode(std::move(other.m_cellFormatsNode)), m_cellFormats(std::move(other.m_cellFormats)), m_permitXfId(other.m_permitXfId) -{ - // std::cout << __func__ << " move constructor" << std::endl; -} +{} /** @@ -2177,7 +2147,6 @@ XLCellFormats::XLCellFormats(XLCellFormats&& other) */ XLCellFormats& XLCellFormats::operator=(const XLCellFormats& other) { - // std::cout << "XLCellFormats::" << __func__ << " copy assignment" << std::endl; if (&other != this) { *m_cellFormatsNode = *other.m_cellFormatsNode; m_cellFormats.clear(); @@ -2339,7 +2308,6 @@ XLCellStyles::XLCellStyles(const XMLNode& cellStyles) XMLNode node = cellStyles.first_child_of_type(pugi::node_element); while (not node.empty()) { std::string nodeName = node.name(); - // std::cout << "XLCellStyles constructor, node name is " << nodeName << std::endl; if (nodeName == "cellStyle") m_cellStyles.push_back(XLCellStyle(node)); else @@ -2356,16 +2324,12 @@ XLCellStyles::~XLCellStyles() XLCellStyles::XLCellStyles(const XLCellStyles& other) : m_cellStylesNode(std::make_unique(*other.m_cellStylesNode)), m_cellStyles(other.m_cellStyles) -{ - // std::cout << __func__ << " copy constructor" << std::endl; -} +{} XLCellStyles::XLCellStyles(XLCellStyles&& other) : m_cellStylesNode(std::move(other.m_cellStylesNode)), m_cellStyles(std::move(other.m_cellStyles)) -{ - // std::cout << __func__ << " move constructor" << std::endl; -} +{} /** @@ -2373,7 +2337,6 @@ XLCellStyles::XLCellStyles(XLCellStyles&& other) */ XLCellStyles& XLCellStyles::operator=(const XLCellStyles& other) { - // std::cout << "XLCellStyles::" << __func__ << " copy assignment" << std::endl; if (&other != this) { *m_cellStylesNode = *other.m_cellStylesNode; m_cellStyles.clear(); @@ -2435,11 +2398,16 @@ XLStyleIndex XLCellStyles::create(XLCellStyle copyFrom, std::string styleEntries } +/** + * @details Default constructor + */ +XLStyles::XLStyles() : XLXmlFile(nullptr, m_classFile) {} + /** * @details Creates an XLStyles object, which will initialize from the given xmlData */ XLStyles::XLStyles(XLXmlData* xmlData, bool suppressWarnings, std::string stylesPrefix) - : XLXmlFile(xmlData), + : XLXmlFile(xmlData, m_classFile), m_suppressWarnings( suppressWarnings ) { XMLDocument & doc = xmlDocument(); @@ -2552,6 +2520,67 @@ XLStyles::~XLStyles() { } +/** + * @details copy-construct an XLStyles object + */ +XLStyles::XLStyles(const XLStyles& other) + : XLXmlFile(other), + m_suppressWarnings(other.m_suppressWarnings), + m_numberFormats (std::make_unique(*other.m_numberFormats) ), + m_fonts (std::make_unique(*other.m_fonts) ), + m_fills (std::make_unique(*other.m_fills) ), + m_borders (std::make_unique(*other.m_borders) ), + m_cellStyleFormats(std::make_unique(*other.m_cellStyleFormats)), + m_cellFormats (std::make_unique(*other.m_cellFormats) ), + m_cellStyles (std::make_unique(*other.m_cellStyles) ) +{} + +/** + * @details move-construct an XLStyles object + */ +XLStyles::XLStyles(XLStyles&& other) noexcept + : XLXmlFile(other), + m_suppressWarnings(other.m_suppressWarnings), + m_numberFormats (std::move(other.m_numberFormats) ), + m_fonts (std::move(other.m_fonts) ), + m_fills (std::move(other.m_fills) ), + m_borders (std::move(other.m_borders) ), + m_cellStyleFormats(std::move(other.m_cellStyleFormats)), + m_cellFormats (std::move(other.m_cellFormats) ), + m_cellStyles (std::move(other.m_cellStyles) ) +{} + +/** + * @details copy-assign an XLStyles object + */ +XLStyles& XLStyles::operator=(const XLStyles& other) +{ + if (&other != this) { + XLStyles temp = other; // copy-construct + *this = std::move(temp); // move-assign & invalidate temp + } + return *this; +} + +/** + * @details move-assign an XLStyles object + */ +XLStyles& XLStyles::operator=(XLStyles&& other) noexcept +{ + if (&other != this) { + XLXmlFile::operator=(std::move(other)); + m_suppressWarnings = other.m_suppressWarnings; + m_numberFormats = std::move(other.m_numberFormats ); + m_fonts = std::move(other.m_fonts ); + m_fills = std::move(other.m_fills ); + m_borders = std::move(other.m_borders ); + m_cellStyleFormats = std::move(other.m_cellStyleFormats); + m_cellFormats = std::move(other.m_cellFormats ); + m_cellStyles = std::move(other.m_cellStyles ); + } + return *this; +} + /** * @details return a handle to the underlying number formats */ diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index 1f0debf9..bf1d1196 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -67,11 +67,17 @@ namespace XMLNode sheetsNode(const XMLDocument& doc) { return doc.document_element().child("sheets"); } } // namespace +/** + * @details Default constructor + */ +XLWorkbook::XLWorkbook() : XLXmlFile(nullptr, m_classFileDefault), m_classFile(m_classFileDefault) {} + /** * @details The constructor initializes the member variables and calls the loadXMLData from the * XLAbstractXMLFile base class. */ -XLWorkbook::XLWorkbook(XLXmlData* xmlData) : XLXmlFile(xmlData) {} +XLWorkbook::XLWorkbook(XLXmlData* xmlData) : XLXmlFile(xmlData, m_classFileDefault), m_classFile(m_classFileDefault) {} +XLWorkbook::XLWorkbook(XLXmlData* xmlData, std::string pathTo) : XLXmlFile(xmlData, pathTo), m_classFile(pathTo) {} /** * @details diff --git a/OpenXLSX/sources/XLXmlFile.cpp b/OpenXLSX/sources/XLXmlFile.cpp index 454479d0..41529a9a 100644 --- a/OpenXLSX/sources/XLXmlFile.cpp +++ b/OpenXLSX/sources/XLXmlFile.cpp @@ -59,6 +59,7 @@ using namespace OpenXLSX; * the data will be read from the .zip file, using the given path. */ XLXmlFile::XLXmlFile(XLXmlData* xmlData) : m_xmlData(xmlData) {} +XLXmlFile::XLXmlFile(XLXmlData* xmlData, std::string xmlName) : m_xmlData(xmlData), m_xmlName(xmlName) {} XLXmlFile::~XLXmlFile() = default; diff --git a/README.md b/README.md index 2a956c37..d2952de8 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,11 @@ Microsoft Excel® files, with the .xlsx format. As the heading says - the latest "Release" that is shown on https://github.com/troldal/OpenXLSX/releases is from 2021-11-06, and severely outdated - please pull / download the latest SW version directly from the repository in its current state. Link for those that do not want to use ```git```: https://github.com/troldal/OpenXLSX/archive/refs/heads/master.zip +## (aral-matrix) 20 December 2024 - XLXmlFile and derived classes (XLWorksheet!) now expose a ::valid() and ::xmlName() method +* addressed https://github.com/troldal/OpenXLSX/issues/312 on a lower level, all classes derived from XLXmlFile now have a bool valid() method that will return true if a non-nullptr XML data block is linked to the class. For the user, this mostly matters in XLWorksheet, XLWorkbook & XLStyles +* additionally, all these classes now expose a std::string const & xmlName() method which serves mostly debugging purposes and - apart from worksheets / chartsheets - should point to the source XML file within the document archive +* while addressing issue #312, implemented explicit copy/move constructors and assignment operators for XLStyles, which should also address https://github.com/troldal/OpenXLSX/issues/310 + ## (aral-matrix) 19 December 2024 - XLStyles enhancement to address issues #304 and #305 - artificial ordering of XML elements * In order to address https://github.com/troldal/OpenXLSX/issues/304 and https://github.com/troldal/OpenXLSX/issues/305, some XLStyles classes now support a strict predefined XML element node order