diff --git a/Src/libCZI/CziMetadata.h b/Src/libCZI/CziMetadata.h index 923ebd51..76abd2c9 100644 --- a/Src/libCZI/CziMetadata.h +++ b/Src/libCZI/CziMetadata.h @@ -15,9 +15,14 @@ class CCziMetadata : public libCZI::ICziMetadata, public std::enable_shared_from private: struct XmlNodeWrapperThrowExcp { - [[noreturn]] static void ThrowInvalidPath() + [[noreturn]] static void ThrowInvalidPath(const char* path="") { - throw libCZI::LibCZIMetadataException("invalid path", libCZI::LibCZIMetadataException::ErrorType::InvalidPath); + std::string message = "invalid path"; + if (path && *path != '\0') { + message += ": "; + message += path; + } + throw libCZI::LibCZIMetadataException(message.c_str(), libCZI::LibCZIMetadataException::ErrorType::InvalidPath); } }; diff --git a/Src/libCZI/CziMetadataBuilder.cpp b/Src/libCZI/CziMetadataBuilder.cpp index e686a629..956a32d2 100644 --- a/Src/libCZI/CziMetadataBuilder.cpp +++ b/Src/libCZI/CziMetadataBuilder.cpp @@ -5,7 +5,6 @@ #include "CziMetadataBuilder.h" #include "utilities.h" #include -#include #include #include #include "CziUtils.h" @@ -15,9 +14,13 @@ using namespace pugi; using namespace libCZI; using namespace std; -/*static*/void CNodeWrapper::MetadataBuilderXmlNodeWrapperThrowExcp::ThrowInvalidPath() -{ - throw libCZI::LibCZIMetadataBuilderException("invalid path", libCZI::LibCZIMetadataBuilderException::ErrorType::InvalidPath); +/*static*/ void CNodeWrapper::MetadataBuilderXmlNodeWrapperThrowExcp::ThrowInvalidPath(const char* path){ + std::string message = "invalid path"; + if (path && *path != '\0') { + message += ": "; + message += path; + } + throw libCZI::LibCZIMetadataBuilderException(message.c_str(), libCZI::LibCZIMetadataBuilderException::ErrorType::InvalidPath); } /*virtual*/std::shared_ptr CNodeWrapper::AppendChildNode(const char* name) diff --git a/Src/libCZI/CziMetadataBuilder.h b/Src/libCZI/CziMetadataBuilder.h index 72f52dbf..9282189d 100644 --- a/Src/libCZI/CziMetadataBuilder.h +++ b/Src/libCZI/CziMetadataBuilder.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "libCZI.h" #include "CziSubBlockDirectory.h" #include "pugixml.hpp" @@ -36,7 +37,7 @@ class CNodeWrapper : public libCZI::IXmlNodeRw std::shared_ptr builderRef; struct MetadataBuilderXmlNodeWrapperThrowExcp { - static void ThrowInvalidPath(); + static void ThrowInvalidPath(const char* path=""); }; public: CNodeWrapper(std::shared_ptr builderRef, pugi::xml_node_struct* node_struct) : diff --git a/Src/libCZI/XmlNodeWrapper.h b/Src/libCZI/XmlNodeWrapper.h index b4bb5d37..6670101d 100644 --- a/Src/libCZI/XmlNodeWrapper.h +++ b/Src/libCZI/XmlNodeWrapper.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "libCZI_Metadata.h" #include @@ -91,6 +92,19 @@ class XmlPathSpecifierUtilities return GetChildElementNodeWithAttributes(node, nodeName, attribute_value_pairs); } } + + static std::wstring getAbsoluteNodePath(pugi::xml_node node) { + std::wstring path; + for (pugi::xml_node current = node; current; current = current.parent()) { +#ifdef PUGIXML_WCHAR_MODE + std::wstring wstr(current.name()); +#else + std::wstring wstr = Utilities::convertUtf8ToWchar_t(current.name()); +#endif + path = L"/" + wstr + path; + } + return path; + } /// Gets the n-th child node with name 'node_name' from the specified node. The index is zero-based. /// If this node does not exist, an exception is thrown. @@ -103,7 +117,7 @@ class XmlPathSpecifierUtilities auto child_node = node.child(node_name.c_str()); if (!child_node) { - tExcp::ThrowInvalidPath(); + tExcp::ThrowInvalidPath(Utilities::convertWchar_tToUtf8((getAbsoluteNodePath(node) + L"/" + node_name + L" with index " + std::to_wstring(index)).c_str()).c_str()); } for (std::uint32_t i = 0; i <= index; ++i) @@ -116,7 +130,7 @@ class XmlPathSpecifierUtilities child_node = child_node.next_sibling(node_name.c_str()); if (!child_node) { - tExcp::ThrowInvalidPath(); + tExcp::ThrowInvalidPath(Utilities::convertWchar_tToUtf8((getAbsoluteNodePath(node) + L"/" + node_name + L" with index " + std::to_wstring(index)).c_str()).c_str()); } } @@ -336,13 +350,13 @@ class XmlNodeWrapperReadonly : public libCZI::IXmlNodeRead Utilities::Tokenize(p, tokens, L"/"); if (tokens.empty()) { - tExcp::ThrowInvalidPath(); + tExcp::ThrowInvalidPath(path); } // if any of the tokens is empty, then we have a path like "/a//b", which is invalid if (any_of(tokens.cbegin(), tokens.cend(), [](const std::wstring& str) {return str.empty(); })) { - tExcp::ThrowInvalidPath(); + tExcp::ThrowInvalidPath(path); } auto node = XmlPathSpecifierUtilities::GetChildElementNodeWithAttributes(this->node, tokens[0]);