diff --git a/sdk/storage/azure-storage-common/inc/azure/storage/common/internal/xml_wrapper.hpp b/sdk/storage/azure-storage-common/inc/azure/storage/common/internal/xml_wrapper.hpp index 31c4fb14cb..5166527ffb 100644 --- a/sdk/storage/azure-storage-common/inc/azure/storage/common/internal/xml_wrapper.hpp +++ b/sdk/storage/azure-storage-common/inc/azure/storage/common/internal/xml_wrapper.hpp @@ -4,6 +4,7 @@ #pragma once #include +#include #include namespace Azure { namespace Storage { namespace _internal { @@ -19,54 +20,42 @@ namespace Azure { namespace Storage { namespace _internal { struct XmlNode final { - explicit XmlNode(XmlNodeType type, std::string name = std::string()) - : Type(type), Name(std::move(name)) - { - } - - explicit XmlNode(XmlNodeType type, std::string name, std::string value) - : Type(type), Name(std::move(name)), Value(std::move(value)), HasValue(true) + explicit XmlNode( + XmlNodeType type, + std::string name = std::string(), + std::string value = {})) + : Type(type), Name(std::move(name)), Value(std::move(value)) { } XmlNodeType Type; std::string Name; std::string Value; - bool HasValue = false; }; class XmlReader final { public: - explicit XmlReader(const char* data, size_t length); + XmlReader(uint8_t const* data, size_t length); XmlReader(const XmlReader& other) = delete; XmlReader& operator=(const XmlReader& other) = delete; - XmlReader(XmlReader&& other) noexcept { *this = std::move(other); } - XmlReader& operator=(XmlReader&& other) noexcept - { - m_context = other.m_context; - other.m_context = nullptr; - return *this; - } + XmlReader(XmlReader&& other) noexcept; + XmlReader& operator=(XmlReader&& other) noexcept; ~XmlReader(); XmlNode Read(); private: - void* m_context = nullptr; + struct XmlReaderContext; + std::unique_ptr m_context; }; class XmlWriter final { public: - explicit XmlWriter(); + XmlWriter(); XmlWriter(const XmlWriter& other) = delete; XmlWriter& operator=(const XmlWriter& other) = delete; - XmlWriter(XmlWriter&& other) noexcept { *this = std::move(other); } - XmlWriter& operator=(XmlWriter&& other) noexcept - { - m_context = other.m_context; - other.m_context = nullptr; - return *this; - } + XmlWriter(XmlWriter&& other) noexcept; + XmlWriter& operator=(XmlWriter&& other) noexcept; ~XmlWriter(); void Write(XmlNode node); @@ -74,7 +63,11 @@ namespace Azure { namespace Storage { namespace _internal { std::string GetDocument(); private: - void* m_context = nullptr; + struct XmlWriterContext; + std::unique_ptr m_context; }; + void XmlGlobalInitialize(); + void XmlGlobalDeinitialize(); + }}} // namespace Azure::Storage::_internal diff --git a/sdk/storage/azure-storage-common/src/xml_wrapper.cpp b/sdk/storage/azure-storage-common/src/xml_wrapper.cpp index 4190240c45..13ca4293f5 100644 --- a/sdk/storage/azure-storage-common/src/xml_wrapper.cpp +++ b/sdk/storage/azure-storage-common/src/xml_wrapper.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -27,7 +28,10 @@ namespace Azure { namespace Storage { namespace _internal { #if defined(AZ_PLATFORM_WINDOWS) - struct XmlReaderContext + void XmlGlobalInitialize() {} + void XmlGlobalDeinitialize() {} + + struct XmlReader::XmlReaderContext { XmlReaderContext() { @@ -65,7 +69,7 @@ namespace Azure { namespace Storage { namespace _internal { throw std::runtime_error("Xml data too big."); } - auto context = std::make_unique(); + m_context = std::make_unique(); WS_XML_READER_BUFFER_INPUT bufferInput; ZeroMemory(&bufferInput, sizeof(bufferInput)); @@ -77,7 +81,12 @@ namespace Azure { namespace Storage { namespace _internal { textEncoding.encoding.encodingType = WS_XML_READER_ENCODING_TYPE_TEXT; textEncoding.charSet = WS_CHARSET_AUTO; HRESULT ret = WsSetInput( - context->reader, &textEncoding.encoding, &bufferInput.input, nullptr, 0, context->error); + m_context->reader, + &textEncoding.encoding, + &bufferInput.input, + nullptr, + 0, + m_context->error); if (ret != S_OK) { throw std::runtime_error("Failed to initialize xml reader."); @@ -85,7 +94,11 @@ namespace Azure { namespace Storage { namespace _internal { WS_CHARSET charSet; ret = WsGetReaderProperty( - context->reader, WS_XML_READER_PROPERTY_CHARSET, &charSet, sizeof(charSet), context->error); + m_context->reader, + WS_XML_READER_PROPERTY_CHARSET, + &charSet, + sizeof(charSet), + m_context->error); if (ret != S_OK) { throw std::runtime_error("Failed to get xml encoding."); @@ -94,34 +107,24 @@ namespace Azure { namespace Storage { namespace _internal { { throw std::runtime_error("Unsupported xml encoding."); } - - m_context = context.release(); } - XmlReader::~XmlReader() - { - if (m_context) - { - delete static_cast(m_context); - } - } + XmlReader::~XmlReader() = default; XmlNode XmlReader::Read() { - auto context = static_cast(m_context); - auto moveToNext = [&]() { - HRESULT ret = WsReadNode(context->reader, context->error); + HRESULT ret = WsReadNode(m_context->reader, m_context->error); if (!SUCCEEDED(ret)) { throw std::runtime_error("Failed to parse xml."); } }; - if (context->readingAttributes) + if (m_context->readingAttributes) { const WS_XML_ATTRIBUTE* attribute - = context->attributeElementNode->attributes[context->attributeIndex]; + = m_context->attributeElementNode->attributes[m_context->attributeIndex]; std::string name( reinterpret_cast(attribute->localName->bytes), attribute->localName->length); @@ -136,19 +139,19 @@ namespace Azure { namespace Storage { namespace _internal { std::string value( reinterpret_cast(utf8Text->value.bytes), utf8Text->value.length); - if (++context->attributeIndex == context->attributeElementNode->attributeCount) + if (++m_context->attributeIndex == m_context->attributeElementNode->attributeCount) { moveToNext(); - context->readingAttributes = false; - context->attributeElementNode = nullptr; - context->attributeIndex = 0; + m_context->readingAttributes = false; + m_context->attributeElementNode = nullptr; + m_context->attributeIndex = 0; } return XmlNode{XmlNodeType::Attribute, std::move(name), std::move(value)}; } const WS_XML_NODE* node; - HRESULT ret = WsGetReaderNode(context->reader, &node, context->error); + HRESULT ret = WsGetReaderNode(m_context->reader, &node, m_context->error); if (!SUCCEEDED(ret)) { throw std::runtime_error("Failed to parse xml."); @@ -163,9 +166,9 @@ namespace Azure { namespace Storage { namespace _internal { if (elementNode->attributeCount != 0) { - context->readingAttributes = true; - context->attributeElementNode = elementNode; - context->attributeIndex = 0; + m_context->readingAttributes = true; + m_context->attributeElementNode = elementNode; + m_context->attributeIndex = 0; } else { @@ -189,7 +192,7 @@ namespace Azure { namespace Storage { namespace _internal { reinterpret_cast(utf8Text->value.bytes), utf8Text->value.length); moveToNext(); - ret = WsGetReaderNode(context->reader, &node, context->error); + ret = WsGetReaderNode(m_context->reader, &node, m_context->error); if (!SUCCEEDED(ret)) { throw std::runtime_error("Failed to parse xml."); @@ -203,7 +206,7 @@ namespace Azure { namespace Storage { namespace _internal { } case WS_XML_NODE_TYPE_END_ELEMENT: moveToNext(); - return XmlNode{XmlNodeType::EndTag}; + return XmlNode{XmlNodeType::EndTag, std::string()}; case WS_XML_NODE_TYPE_EOF: return XmlNode{XmlNodeType::End}; case WS_XML_NODE_TYPE_CDATA: @@ -218,7 +221,7 @@ namespace Azure { namespace Storage { namespace _internal { } } - struct XmlWriterContext + struct XmlWriter::XmlWriterContext { XmlWriterContext() { @@ -258,37 +261,29 @@ namespace Azure { namespace Storage { namespace _internal { XmlWriter::XmlWriter() { - auto context = std::make_unique(); + m_context = std::make_unique(); - HRESULT ret = WsCreateXmlBuffer(context->heap, nullptr, 0, &context->buffer, context->error); + HRESULT ret + = WsCreateXmlBuffer(m_context->heap, nullptr, 0, &m_context->buffer, m_context->error); if (ret != NO_ERROR) { throw std::runtime_error("Failed to initialize xml writer."); } - ret = WsSetOutputToBuffer(context->writer, context->buffer, nullptr, 0, context->error); + ret = WsSetOutputToBuffer(m_context->writer, m_context->buffer, nullptr, 0, m_context->error); if (ret != NO_ERROR) { throw std::runtime_error("Failed to initialize xml writer."); } - - m_context = context.release(); } - XmlWriter::~XmlWriter() - { - if (m_context) - { - delete static_cast(m_context); - } - } + XmlWriter::~XmlWriter() = default; void XmlWriter::Write(XmlNode node) { - auto context = static_cast(m_context); if (node.Type == XmlNodeType::StartTag) { - if (node.HasValue) + if (!node.Value.empty()) { Write(XmlNode{XmlNodeType::StartTag, std::move(node.Name)}); Write(XmlNode{XmlNodeType::Text, std::string(), std::move(node.Value)}); @@ -300,7 +295,7 @@ namespace Azure { namespace Storage { namespace _internal { name.length = static_cast(node.Name.length()); name.dictionary = nullptr; WS_XML_STRING ns = WS_XML_STRING_NULL; - HRESULT ret = WsWriteStartElement(context->writer, nullptr, &name, &ns, context->error); + HRESULT ret = WsWriteStartElement(m_context->writer, nullptr, &name, &ns, m_context->error); if (!SUCCEEDED(ret)) { throw std::runtime_error("Failed to write xml."); @@ -308,7 +303,7 @@ namespace Azure { namespace Storage { namespace _internal { } else if (node.Type == XmlNodeType::EndTag) { - HRESULT ret = WsWriteEndElement(context->writer, context->error); + HRESULT ret = WsWriteEndElement(m_context->writer, m_context->error); if (!SUCCEEDED(ret)) { throw std::runtime_error("Failed to write xml."); @@ -317,10 +312,10 @@ namespace Azure { namespace Storage { namespace _internal { else if (node.Type == XmlNodeType::Text) { HRESULT ret = WsWriteCharsUtf8( - context->writer, + m_context->writer, reinterpret_cast(node.Value.data()), static_cast(node.Value.size()), - context->error); + m_context->error); if (!SUCCEEDED(ret)) { throw std::runtime_error("Failed to write xml."); @@ -334,13 +329,13 @@ namespace Azure { namespace Storage { namespace _internal { name.dictionary = nullptr; WS_XML_STRING ns = WS_XML_STRING_NULL; HRESULT ret - = WsWriteStartAttribute(context->writer, nullptr, &name, &ns, FALSE, context->error); + = WsWriteStartAttribute(m_context->writer, nullptr, &name, &ns, FALSE, m_context->error); if (!SUCCEEDED(ret)) { throw std::runtime_error("Failed to write xml."); } Write(XmlNode{XmlNodeType::Text, std::string(), std::move(node.Value)}); - ret = WsWriteEndAttribute(context->writer, context->error); + ret = WsWriteEndAttribute(m_context->writer, m_context->error); if (!SUCCEEDED(ret)) { throw std::runtime_error("Failed to write xml."); @@ -359,29 +354,23 @@ namespace Azure { namespace Storage { namespace _internal { std::string XmlWriter::GetDocument() { - auto context = static_cast(m_context); - BOOL boolValueTrue = TRUE; - WS_XML_WRITER_PROPERTY writerProperty[2]; - writerProperty[0].id = WS_XML_WRITER_PROPERTY_WRITE_DECLARATION; - writerProperty[0].value = &boolValueTrue; - writerProperty[0].valueSize = sizeof(boolValueTrue); - writerProperty[1].id = WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE; - ULONG maxBufferSize = 256 * 1024 * 1024UL; - writerProperty[1].value = &maxBufferSize; - writerProperty[1].valueSize = sizeof(maxBufferSize); + WS_XML_WRITER_PROPERTY writerProperty; + writerProperty.id = WS_XML_WRITER_PROPERTY_WRITE_DECLARATION; + writerProperty.value = &boolValueTrue; + writerProperty.valueSize = sizeof(boolValueTrue); void* xml = nullptr; ULONG xmlLength = 0; HRESULT ret = WsWriteXmlBufferToBytes( - context->writer, - context->buffer, + m_context->writer, + m_context->buffer, nullptr, - writerProperty, - sizeof(writerProperty) / sizeof(writerProperty[0]), - context->heap, + &writerProperty, + 1, + m_context->heap, &xml, &xmlLength, - context->error); + m_context->error); if (!SUCCEEDED(ret)) { throw std::runtime_error("Failed to write xml."); @@ -392,17 +381,30 @@ namespace Azure { namespace Storage { namespace _internal { #else - struct XmlGlobalInitializer final + void XmlGlobalInitialize() { - XmlGlobalInitializer() { xmlInitParser(); } - ~XmlGlobalInitializer() { xmlCleanupParser(); } - }; + static std::once_flag flag; + std::call_once(flag, [] { xmlInitParser(); }); + } - static void XmlGlobalInitialize() { static XmlGlobalInitializer globalInitializer; } + void XmlGlobalDeinitialize() + { + static std::once_flag flag; + std::call_once(flag, [] { xmlCleanupParser(); }); + } - struct XmlReaderContext + XmlReader::XmlReader(XmlReader&& other) noexcept { *this = std::move(other); } + XmlReader& XmlReader::operator=(XmlReader&& other) noexcept { - xmlTextReaderPtr reader = nullptr; + m_context = std::move(other.m_context); + return *this; + } + + using ReaderPtr = std::unique_ptr; + struct XmlReader::XmlReaderContext + { + explicit XmlReaderContext(ReaderPtr&& reader_) : reader(std::move(reader_)) {} + ReaderPtr reader; bool readingAttributes = false; bool readingEmptyTag = false; }; @@ -416,38 +418,31 @@ namespace Azure { namespace Storage { namespace _internal { throw std::runtime_error("Xml data too big."); } - xmlTextReaderPtr reader - = xmlReaderForMemory(data, static_cast(length), nullptr, nullptr, 0); + auto reader = ReaderPtr( + xmlReaderForMemory(data, static_cast(length), nullptr, nullptr, 0), xmlFreeTextReader); + if (!reader) { throw std::runtime_error("Failed to parse xml."); } - XmlReaderContext* context = new XmlReaderContext(); - context->reader = reader; - m_context = context; + m_context = std::make_unique(std::move(reader)); } - XmlReader::~XmlReader() - { - if (m_context) - { - auto context = static_cast(m_context); - xmlFreeTextReader(static_cast(context->reader)); - delete context; - } - } + XmlReader::~XmlReader() = default; XmlNode XmlReader::Read() { - auto context = static_cast(m_context); + auto context = m_context.get(); if (context->readingAttributes) { - int ret = xmlTextReaderMoveToNextAttribute(context->reader); + int ret = xmlTextReaderMoveToNextAttribute(context->reader.get()); if (ret == 1) { - const char* name = reinterpret_cast(xmlTextReaderConstName(context->reader)); - const char* value = reinterpret_cast(xmlTextReaderConstValue(context->reader)); + const char* name + = reinterpret_cast(xmlTextReaderConstName(context->reader.get())); + const char* value + = reinterpret_cast(xmlTextReaderConstValue(context->reader.get())); return XmlNode{XmlNodeType::Attribute, name, value}; } else if (ret == 0) @@ -465,7 +460,7 @@ namespace Azure { namespace Storage { namespace _internal { return XmlNode{XmlNodeType::EndTag}; } - int ret = xmlTextReaderRead(context->reader); + int ret = xmlTextReaderRead(context->reader.get()); if (ret == 0) { return XmlNode{XmlNodeType::End}; @@ -475,13 +470,14 @@ namespace Azure { namespace Storage { namespace _internal { throw std::runtime_error("Failed to parse xml."); } - int type = xmlTextReaderNodeType(context->reader); - bool is_empty = xmlTextReaderIsEmptyElement(context->reader) == 1; - bool has_value = xmlTextReaderHasValue(context->reader) == 1; - bool has_attributes = xmlTextReaderHasAttributes(context->reader) == 1; + int type = xmlTextReaderNodeType(context->reader.get()); + bool is_empty = xmlTextReaderIsEmptyElement(context->reader.get()) == 1; + bool has_value = xmlTextReaderHasValue(context->reader.get()) == 1; + bool has_attributes = xmlTextReaderHasAttributes(context->reader.get()) == 1; - const char* name = reinterpret_cast(xmlTextReaderConstName(context->reader)); - const char* value = reinterpret_cast(xmlTextReaderConstValue(context->reader)); + const char* name = reinterpret_cast(xmlTextReaderConstName(context->reader.get())); + const char* value + = reinterpret_cast(xmlTextReaderConstValue(context->reader.get())); if (has_attributes) { @@ -520,48 +516,48 @@ namespace Azure { namespace Storage { namespace _internal { return Read(); } - struct XmlWriterContext + using BufferPtr = std::unique_ptr; + using WriterPtr = std::unique_ptr; + struct XmlWriter::XmlWriterContext { - xmlBufferPtr buffer; - xmlTextWriterPtr writer; + XmlWriterContext(BufferPtr&& buffer_, WriterPtr&& writer_) + : buffer(std::move(buffer_)), writer(std::move(writer_)) + { + } + BufferPtr buffer; + WriterPtr writer; }; + XmlWriter::XmlWriter(XmlWriter&& other) noexcept { *this = std::move(other); } + XmlWriter& XmlWriter::operator=(XmlWriter&& other) noexcept + { + m_context = std::move(other.m_context); + return *this; + } + XmlWriter::XmlWriter() { XmlGlobalInitialize(); - auto buffer = xmlBufferCreate(); + auto buffer = BufferPtr(xmlBufferCreate(), xmlBufferFree); if (!buffer) { throw std::runtime_error("Failed to initialize xml writer."); } - auto writer = xmlNewTextWriterMemory(static_cast(buffer), 0); + auto writer = WriterPtr(xmlNewTextWriterMemory(buffer.get(), 0), xmlFreeTextWriter); if (!writer) { - xmlBufferFree(static_cast(buffer)); throw std::runtime_error("Failed to initialize xml writer."); } - xmlTextWriterStartDocument(static_cast(writer), nullptr, nullptr, nullptr); + xmlTextWriterStartDocument(writer.get(), nullptr, nullptr, nullptr); - auto context = new XmlWriterContext; - context->buffer = buffer; - context->writer = writer; - m_context = context; + m_context = std::make_unique(std::move(buffer), std::move(writer)); } - XmlWriter::~XmlWriter() - { - if (m_context) - { - auto context = static_cast(m_context); - xmlFreeTextWriter(static_cast(context->writer)); - xmlBufferFree(static_cast(context->buffer)); - delete context; - } - } + XmlWriter::~XmlWriter() = default; namespace { inline xmlChar* BadCast(const char* x) @@ -572,11 +568,10 @@ namespace Azure { namespace Storage { namespace _internal { void XmlWriter::Write(XmlNode node) { - auto context = static_cast(m_context); - xmlTextWriterPtr writer = context->writer; + xmlTextWriterPtr writer = m_context->writer.get(); if (node.Type == XmlNodeType::StartTag) { - if (!node.HasValue) + if (node.Value.empty()) { xmlTextWriterStartElement(writer, BadCast(node.Name.data())); } @@ -611,9 +606,8 @@ namespace Azure { namespace Storage { namespace _internal { std::string XmlWriter::GetDocument() { - auto context = static_cast(m_context); - xmlBufferPtr buffer = context->buffer; - return std::string(reinterpret_cast(buffer->content), buffer->use); + return std::string( + reinterpret_cast(m_context->buffer->content), m_context->buffer->use); } #endif