/* Copyright (C) 2002 The gtkmm Development Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*/
#include
#include
#include
#include
namespace Glib
{
namespace Markup
{
Glib::ustring
escape_text(const Glib::ustring& text)
{
const auto buf = make_unique_ptr_gfree(g_markup_escape_text(text.data(), text.bytes()));
return Glib::ustring(buf.get());
}
/**** Glib::Markup::AttributeKeyLess ***************************************/
bool
AttributeKeyLess::operator()(const Glib::ustring& lhs, const Glib::ustring& rhs) const
{
return (lhs.raw() < rhs.raw());
}
/**** Glib::Markup::ParserCallbacks ****************************************/
class ParserCallbacks
{
public:
static const GMarkupParser vfunc_table;
static void start_element(GMarkupParseContext* context, const char* element_name,
const char** attribute_names, const char** attribute_values, void* user_data, GError** error);
static void end_element(
GMarkupParseContext* context, const char* element_name, void* user_data, GError** error);
static void text(GMarkupParseContext* context, const char* text, gsize text_len, void* user_data,
GError** error);
static void passthrough(GMarkupParseContext* context, const char* passthrough_text,
gsize text_len, void* user_data, GError** error);
static void error(GMarkupParseContext* context, GError* error, void* user_data);
};
const GMarkupParser ParserCallbacks::vfunc_table = {
&ParserCallbacks::start_element, &ParserCallbacks::end_element, &ParserCallbacks::text,
&ParserCallbacks::passthrough, &ParserCallbacks::error,
};
void
ParserCallbacks::start_element(GMarkupParseContext* context, const char* element_name,
const char** attribute_names, const char** attribute_values, void* user_data, GError** error)
{
ParseContext& cpp_context = *static_cast(user_data);
g_return_if_fail(context == cpp_context.gobj());
try
{
Parser::AttributeMap attributes;
if (attribute_names && attribute_values)
{
const char* const* pname = attribute_names;
const char* const* pvalue = attribute_values;
for (; *pname && *pvalue; ++pname, ++pvalue)
attributes.insert(Parser::AttributeMap::value_type(*pname, *pvalue));
g_return_if_fail(*pname == nullptr && *pvalue == nullptr);
}
cpp_context.get_parser()->on_start_element(cpp_context, element_name, attributes);
}
catch (MarkupError& err)
{
err.propagate(error);
}
catch (...)
{
Glib::exception_handlers_invoke();
}
}
void
ParserCallbacks::end_element(
GMarkupParseContext* context, const char* element_name, void* user_data, GError** error)
{
ParseContext& cpp_context = *static_cast(user_data);
g_return_if_fail(context == cpp_context.gobj());
try
{
cpp_context.get_parser()->on_end_element(cpp_context, element_name);
}
catch (MarkupError& err)
{
err.propagate(error);
}
catch (...)
{
Glib::exception_handlers_invoke();
}
}
void
ParserCallbacks::text(
GMarkupParseContext* context, const char* text, gsize text_len, void* user_data, GError** error)
{
ParseContext& cpp_context = *static_cast(user_data);
g_return_if_fail(context == cpp_context.gobj());
try
{
cpp_context.get_parser()->on_text(cpp_context, Glib::ustring(text, text + text_len));
}
catch (MarkupError& err)
{
err.propagate(error);
}
catch (...)
{
Glib::exception_handlers_invoke();
}
}
void
ParserCallbacks::passthrough(GMarkupParseContext* context, const char* passthrough_text,
gsize text_len, void* user_data, GError** error)
{
ParseContext& cpp_context = *static_cast(user_data);
g_return_if_fail(context == cpp_context.gobj());
try
{
cpp_context.get_parser()->on_passthrough(
cpp_context, Glib::ustring(passthrough_text, passthrough_text + text_len));
}
catch (MarkupError& err)
{
err.propagate(error);
}
catch (...)
{
Glib::exception_handlers_invoke();
}
}
void
ParserCallbacks::error(GMarkupParseContext* context, GError* error, void* user_data)
{
ParseContext& cpp_context = *static_cast(user_data);
g_return_if_fail(context == cpp_context.gobj());
g_return_if_fail(error->domain == G_MARKUP_ERROR);
try
{
cpp_context.get_parser()->on_error(cpp_context, MarkupError(g_error_copy(error)));
}
catch (...)
{
Glib::exception_handlers_invoke();
}
}
/**** Glib::Markup::Parser *************************************************/
Parser::Parser()
{
}
Parser::Parser(Parser&& other) noexcept : sigc::trackable(std::move(other))
{
}
Parser&
Parser::operator=(Parser&& other) noexcept
{
sigc::trackable::operator=(std::move(other));
return *this;
}
Parser::~Parser()
{
}
void
Parser::on_start_element(ParseContext&, const Glib::ustring&, const Parser::AttributeMap&)
{
}
void
Parser::on_end_element(ParseContext&, const Glib::ustring&)
{
}
void
Parser::on_text(ParseContext&, const Glib::ustring&)
{
}
void
Parser::on_passthrough(ParseContext&, const Glib::ustring&)
{
}
void
Parser::on_error(ParseContext&, const MarkupError&)
{
}
/**** Glib::Markup::ParseContext *******************************************/
ParseContext::ParseContext(Parser& parser, ParseFlags flags)
: parser_(&parser),
gobject_(g_markup_parse_context_new(&ParserCallbacks::vfunc_table, (GMarkupParseFlags)flags, this,
&ParseContext::destroy_notify_callback))
{
}
ParseContext::ParseContext(ParseContext&& other) noexcept : sigc::trackable(std::move(other)),
parser_(std::move(other.parser_)),
gobject_(std::move(other.gobject_))
{
}
ParseContext&
ParseContext::operator=(ParseContext&& other) noexcept
{
sigc::trackable::operator=(std::move(other));
parser_ = std::move(other.parser_);
gobject_ = std::move(other.gobject_);
other.parser_ = nullptr;
other.gobject_ = nullptr;
return *this;
}
ParseContext::~ParseContext()
{
parser_ = nullptr;
g_markup_parse_context_free(gobject_);
}
void
ParseContext::parse(const Glib::ustring& text)
{
GError* error = nullptr;
g_markup_parse_context_parse(gobject_, text.data(), text.bytes(), &error);
if (error)
Glib::Error::throw_exception(error);
}
void
ParseContext::parse(const char* text_begin, const char* text_end)
{
GError* error = nullptr;
g_markup_parse_context_parse(gobject_, text_begin, text_end - text_begin, &error);
if (error)
Glib::Error::throw_exception(error);
}
void
ParseContext::end_parse()
{
GError* error = nullptr;
g_markup_parse_context_end_parse(gobject_, &error);
if (error)
Glib::Error::throw_exception(error);
}
Glib::ustring
ParseContext::get_element() const
{
const char* const element_name = g_markup_parse_context_get_element(gobject_);
return convert_const_gchar_ptr_to_ustring(element_name);
}
int
ParseContext::get_line_number() const
{
int line_number = 0;
g_markup_parse_context_get_position(gobject_, &line_number, nullptr);
return line_number;
}
int
ParseContext::get_char_number() const
{
int char_number = 0;
g_markup_parse_context_get_position(gobject_, nullptr, &char_number);
return char_number;
}
// static
void
ParseContext::destroy_notify_callback(void* data)
{
ParseContext* const self = static_cast(data);
// Detect premature destruction.
g_return_if_fail(self->parser_ == nullptr);
}
} // namespace Markup
} // namespace Glib