XML: Use RAII wrappers instead of manual memory management (#5767)
Co-authored-by: alesapin <alesapin@gmail.com> Co-authored-by: Anton Popov <anton@clickhouse.com>
This commit is contained in:
parent
0f62b3aa63
commit
6960ad1247
@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace Azure { namespace Storage { namespace _internal {
|
||||
@ -40,19 +41,15 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
explicit XmlReader(const char* 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<XmlReaderContext> m_context;
|
||||
};
|
||||
|
||||
class XmlWriter final {
|
||||
@ -60,13 +57,8 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
explicit 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 +66,8 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
std::string GetDocument();
|
||||
|
||||
private:
|
||||
void* m_context = nullptr;
|
||||
struct XmlWriterContext;
|
||||
std::unique_ptr<XmlWriterContext> m_context;
|
||||
};
|
||||
|
||||
}}} // namespace Azure::Storage::_internal
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
@ -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()
|
||||
{
|
||||
@ -95,20 +99,14 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
throw std::runtime_error("Unsupported xml encoding.");
|
||||
}
|
||||
|
||||
m_context = context.release();
|
||||
m_context = std::move(context);
|
||||
}
|
||||
|
||||
XmlReader::~XmlReader()
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
delete static_cast<XmlReaderContext*>(m_context);
|
||||
}
|
||||
}
|
||||
XmlReader::~XmlReader() {}
|
||||
|
||||
XmlNode XmlReader::Read()
|
||||
{
|
||||
auto context = static_cast<XmlReaderContext*>(m_context);
|
||||
auto& context = m_context;
|
||||
|
||||
auto moveToNext = [&]() {
|
||||
HRESULT ret = WsReadNode(context->reader, context->error);
|
||||
@ -218,7 +216,7 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
}
|
||||
}
|
||||
|
||||
struct XmlWriterContext
|
||||
struct XmlWriter::XmlWriterContext
|
||||
{
|
||||
XmlWriterContext()
|
||||
{
|
||||
@ -272,20 +270,14 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
throw std::runtime_error("Failed to initialize xml writer.");
|
||||
}
|
||||
|
||||
m_context = context.release();
|
||||
m_context = std::move(context);
|
||||
}
|
||||
|
||||
XmlWriter::~XmlWriter()
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
delete static_cast<XmlWriterContext*>(m_context);
|
||||
}
|
||||
}
|
||||
XmlWriter::~XmlWriter() {}
|
||||
|
||||
void XmlWriter::Write(XmlNode node)
|
||||
{
|
||||
auto context = static_cast<XmlWriterContext*>(m_context);
|
||||
auto& context = m_context;
|
||||
if (node.Type == XmlNodeType::StartTag)
|
||||
{
|
||||
if (node.HasValue)
|
||||
@ -359,7 +351,7 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
|
||||
std::string XmlWriter::GetDocument()
|
||||
{
|
||||
auto context = static_cast<XmlWriterContext*>(m_context);
|
||||
auto& context = m_context;
|
||||
|
||||
BOOL boolValueTrue = TRUE;
|
||||
WS_XML_WRITER_PROPERTY writerProperty[2];
|
||||
@ -400,11 +392,15 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
|
||||
static void XmlGlobalInitialize() { static XmlGlobalInitializer globalInitializer; }
|
||||
|
||||
struct XmlReaderContext
|
||||
struct XmlReader::XmlReaderContext
|
||||
{
|
||||
xmlTextReaderPtr reader = nullptr;
|
||||
using XmlTextReaderPtr = std::unique_ptr<xmlTextReader, decltype(&xmlFreeTextReader)>;
|
||||
|
||||
XmlTextReaderPtr reader;
|
||||
bool readingAttributes = false;
|
||||
bool readingEmptyTag = false;
|
||||
|
||||
explicit XmlReaderContext(XmlTextReaderPtr&& reader_) : reader(std::move(reader_)) {}
|
||||
};
|
||||
|
||||
XmlReader::XmlReader(const char* data, size_t length)
|
||||
@ -416,38 +412,38 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
throw std::runtime_error("Xml data too big.");
|
||||
}
|
||||
|
||||
xmlTextReaderPtr reader
|
||||
= xmlReaderForMemory(data, static_cast<int>(length), nullptr, nullptr, 0);
|
||||
auto reader = XmlReaderContext::XmlTextReaderPtr(
|
||||
xmlReaderForMemory(data, static_cast<int>(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<XmlReaderContext>(std::move(reader));
|
||||
}
|
||||
|
||||
XmlReader::~XmlReader()
|
||||
XmlReader::XmlReader(XmlReader&& other) noexcept { *this = std::move(other); }
|
||||
|
||||
XmlReader& XmlReader::operator=(XmlReader&& other) noexcept
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
auto context = static_cast<XmlReaderContext*>(m_context);
|
||||
xmlFreeTextReader(static_cast<xmlTextReaderPtr>(context->reader));
|
||||
delete context;
|
||||
}
|
||||
m_context = std::move(other.m_context);
|
||||
return *this;
|
||||
}
|
||||
|
||||
XmlReader::~XmlReader() = default;
|
||||
|
||||
XmlNode XmlReader::Read()
|
||||
{
|
||||
auto context = static_cast<XmlReaderContext*>(m_context);
|
||||
XmlReaderContext* context = m_context.get();
|
||||
xmlTextReader* reader = m_context->reader.get();
|
||||
if (context->readingAttributes)
|
||||
{
|
||||
int ret = xmlTextReaderMoveToNextAttribute(context->reader);
|
||||
int ret = xmlTextReaderMoveToNextAttribute(reader);
|
||||
if (ret == 1)
|
||||
{
|
||||
const char* name = reinterpret_cast<const char*>(xmlTextReaderConstName(context->reader));
|
||||
const char* value = reinterpret_cast<const char*>(xmlTextReaderConstValue(context->reader));
|
||||
const char* name = reinterpret_cast<const char*>(xmlTextReaderConstName(reader));
|
||||
const char* value = reinterpret_cast<const char*>(xmlTextReaderConstValue(reader));
|
||||
return XmlNode{XmlNodeType::Attribute, name, value};
|
||||
}
|
||||
else if (ret == 0)
|
||||
@ -465,7 +461,7 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
return XmlNode{XmlNodeType::EndTag};
|
||||
}
|
||||
|
||||
int ret = xmlTextReaderRead(context->reader);
|
||||
int ret = xmlTextReaderRead(reader);
|
||||
if (ret == 0)
|
||||
{
|
||||
return XmlNode{XmlNodeType::End};
|
||||
@ -475,13 +471,13 @@ 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(reader);
|
||||
bool is_empty = xmlTextReaderIsEmptyElement(reader) == 1;
|
||||
bool has_value = xmlTextReaderHasValue(reader) == 1;
|
||||
bool has_attributes = xmlTextReaderHasAttributes(reader) == 1;
|
||||
|
||||
const char* name = reinterpret_cast<const char*>(xmlTextReaderConstName(context->reader));
|
||||
const char* value = reinterpret_cast<const char*>(xmlTextReaderConstValue(context->reader));
|
||||
const char* name = reinterpret_cast<const char*>(xmlTextReaderConstName(reader));
|
||||
const char* value = reinterpret_cast<const char*>(xmlTextReaderConstValue(reader));
|
||||
|
||||
if (has_attributes)
|
||||
{
|
||||
@ -520,49 +516,53 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
return Read();
|
||||
}
|
||||
|
||||
struct XmlWriterContext
|
||||
struct XmlWriter::XmlWriterContext
|
||||
{
|
||||
xmlBufferPtr buffer;
|
||||
xmlTextWriterPtr writer;
|
||||
using XmlBufferPtr = std::unique_ptr<xmlBuffer, decltype(&xmlBufferFree)>;
|
||||
using XmlTextWriterPtr = std::unique_ptr<xmlTextWriter, decltype(&xmlFreeTextWriter)>;
|
||||
|
||||
XmlBufferPtr buffer;
|
||||
XmlTextWriterPtr writer;
|
||||
|
||||
explicit XmlWriterContext(XmlBufferPtr&& buffer_, XmlTextWriterPtr&& writer_)
|
||||
: buffer(std::move(buffer_)), writer(std::move(writer_))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
XmlWriter::XmlWriter()
|
||||
{
|
||||
XmlGlobalInitialize();
|
||||
auto buffer = xmlBufferCreate();
|
||||
auto buffer = XmlWriterContext::XmlBufferPtr(xmlBufferCreate(), xmlBufferFree);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
throw std::runtime_error("Failed to initialize xml writer.");
|
||||
}
|
||||
|
||||
auto writer = xmlNewTextWriterMemory(static_cast<xmlBufferPtr>(buffer), 0);
|
||||
auto writer = XmlWriterContext::XmlTextWriterPtr(
|
||||
xmlNewTextWriterMemory(buffer.get(), 0), xmlFreeTextWriter);
|
||||
|
||||
if (!writer)
|
||||
{
|
||||
xmlBufferFree(static_cast<xmlBufferPtr>(buffer));
|
||||
throw std::runtime_error("Failed to initialize xml writer.");
|
||||
}
|
||||
|
||||
xmlTextWriterStartDocument(static_cast<xmlTextWriterPtr>(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<XmlWriterContext>(std::move(buffer), std::move(writer));
|
||||
}
|
||||
|
||||
XmlWriter::~XmlWriter()
|
||||
XmlWriter::XmlWriter(XmlWriter&& other) noexcept { *this = std::move(other); }
|
||||
|
||||
XmlWriter& XmlWriter::operator=(XmlWriter&& other) noexcept
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
auto context = static_cast<XmlWriterContext*>(m_context);
|
||||
xmlFreeTextWriter(static_cast<xmlTextWriterPtr>(context->writer));
|
||||
xmlBufferFree(static_cast<xmlBufferPtr>(context->buffer));
|
||||
delete context;
|
||||
}
|
||||
m_context = std::move(other.m_context);
|
||||
return *this;
|
||||
}
|
||||
|
||||
XmlWriter::~XmlWriter() = default;
|
||||
|
||||
namespace {
|
||||
inline xmlChar* BadCast(const char* x)
|
||||
{
|
||||
@ -572,8 +572,7 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
|
||||
void XmlWriter::Write(XmlNode node)
|
||||
{
|
||||
auto context = static_cast<XmlWriterContext*>(m_context);
|
||||
xmlTextWriterPtr writer = context->writer;
|
||||
xmlTextWriter* writer = m_context->writer.get();
|
||||
if (node.Type == XmlNodeType::StartTag)
|
||||
{
|
||||
if (!node.HasValue)
|
||||
@ -611,9 +610,8 @@ namespace Azure { namespace Storage { namespace _internal {
|
||||
|
||||
std::string XmlWriter::GetDocument()
|
||||
{
|
||||
auto context = static_cast<XmlWriterContext*>(m_context);
|
||||
xmlBufferPtr buffer = context->buffer;
|
||||
return std::string(reinterpret_cast<const char*>(buffer->content), buffer->use);
|
||||
return std::string(
|
||||
reinterpret_cast<const char*>(m_context->buffer->content), m_context->buffer->use);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user