#include <libxml/parser.h>
#include <cstdarg> //For va_list.
-#include <memory> //For auto_ptr.
+#include <memory> //For unique_ptr.
namespace xmlpp {
Validator::Validator()
-: valid_(0), exception_(0)
+: exception_ptr_(nullptr)
{
}
release_underlying();
}
-void Validator::initialize_valid()
+void Validator::initialize_context()
{
- //Tell the validity valid about the callbacks:
- //(These are only called if validation is on - see above)
- valid_->error = &callback_validity_error;
- valid_->warning = &callback_validity_warning;
-
- //Allow the callback_validity_*() methods to retrieve the C++ instance:
- valid_->userData = this;
-
- //Clear these temporary buffers too:
+ //Clear these temporary buffers:
validate_error_.erase();
validate_warning_.erase();
}
void Validator::release_underlying()
{
- if(valid_)
- {
- valid_->userData = 0; //Not really necessary.
-
- xmlFreeValidCtxt(valid_);
- valid_ = 0;
- }
}
void Validator::on_validity_error(const Glib::ustring& message)
void Validator::check_for_validity_messages()
{
- if(!validate_error_.empty())
+ Glib::ustring msg;
+ try
{
- if(!exception_)
- exception_ = new validity_error("Validity error:\n" + validate_error_);
+ if (exception_ptr_)
+ std::rethrow_exception(exception_ptr_);
+ }
+ catch (const std::exception& e)
+ {
+ msg = e.what();
+ }
+ catch (...)
+ {
+ msg = "Unknown exception\n";
+ }
+ bool validity_msg = false;
+ if (!validate_error_.empty())
+ {
+ validity_msg = true;
+ msg += "\nValidity error:\n" + validate_error_;
validate_error_.erase();
}
- if(!validate_warning_.empty())
+ if (!validate_warning_.empty())
{
- if(!exception_)
- exception_ = new validity_error("Validity warning:\n" + validate_warning_);
-
+ validity_msg = true;
+ msg += "\nValidity warning:\n" + validate_warning_;
validate_warning_.erase();
}
+
+ try
+ {
+ if (validity_msg)
+ throw validity_error(msg);
+ }
+ catch (...)
+ {
+ exception_ptr_ = std::current_exception();
+ }
}
void Validator::callback_validity_error(void* valid_, const char* msg, ...)
{
- Validator* validator = static_cast<Validator*>(valid_);
+ auto validator = static_cast<Validator*>(valid_);
if(validator)
{
vsnprintf(buff, sizeof(buff)/sizeof(buff[0]), msg, arg);
va_end(arg);
- #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
try
{
- #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
validator->on_validity_error(Glib::ustring(buff));
- #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
}
- catch(const exception& e)
+ catch (...)
{
- validator->handleException(e);
+ validator->handle_exception();
}
- #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
}
}
void Validator::callback_validity_warning(void* valid_, const char* msg, ...)
{
- Validator* validator = static_cast<Validator*>(valid_);
+ auto validator = static_cast<Validator*>(valid_);
if(validator)
{
vsnprintf(buff, sizeof(buff)/sizeof(buff[0]), msg, arg);
va_end(arg);
- #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
try
{
- #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
validator->on_validity_warning(Glib::ustring(buff));
- #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
}
- catch(const exception& e)
+ catch (...)
{
- validator->handleException(e);
+ validator->handle_exception();
}
- #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
}
}
-void Validator::handleException(const exception& e)
+void Validator::handle_exception()
{
- exception_ = e.Clone();
-
- release_underlying();
+ exception_ptr_ = std::current_exception();
+
+ // Don't delete the DTD validation context or schema validation context
+ // while validating. It would cause accesses to deallocated memory in libxml2
+ // functions after the return from Validator::callback_validity_...().
+ // Parser::handle_exception() calls xmlStopParser(), but there is no
+ // xmlStopValidator() or similar function to call here.
+ // We don't throw the exception here, since it would have to pass through
+ // C functions. That's not guaranteed to work. It might work, but it depends
+ // on the C compiler and the options used when building libxml2.
+
+ //release_underlying();
}
void Validator::check_for_exception()
{
check_for_validity_messages();
-
- if(exception_)
+
+ if (exception_ptr_)
{
- std::auto_ptr<exception> tmp(exception_);
- exception_ = 0;
- tmp->Raise();
+ std::exception_ptr tmp(exception_ptr_);
+ exception_ptr_ = nullptr;
+ std::rethrow_exception(tmp);
}
}
} // namespace xmlpp
-
-