@@ -60,6 +60,7 @@ DEALINGS IN THE SOFTWARE.
6060
6161#include < cassert>
6262#include < cstring>
63+ #include < exception>
6364#include < future>
6465#include < limits>
6566#include < memory>
@@ -177,34 +178,63 @@ namespace osmium {
177178 class ExpatXMLParser {
178179
179180 XML_Parser m_parser;
181+ std::exception_ptr m_exception_ptr{};
180182
181- static void XMLCALL start_element_wrapper (void * data, const XML_Char* element, const XML_Char** attrs) {
182- static_cast <XMLParser*>(data)->start_element (element, attrs);
183+ template <typename TFunc>
184+ void member_wrap (XMLParser& xml_parser, TFunc&& func) noexcept {
185+ if (m_exception_ptr) {
186+ return ;
187+ }
188+ try {
189+ std::forward<TFunc>(func)(xml_parser);
190+ } catch (...) {
191+ m_exception_ptr = std::current_exception ();
192+ XML_StopParser (m_parser, 0 );
193+ }
194+ }
195+
196+ template <typename TFunc>
197+ static void wrap (void * data, TFunc&& func) noexcept {
198+ assert (data);
199+ auto & xml_parser = *static_cast <XMLParser*>(data);
200+ xml_parser.m_expat_xml_parser ->member_wrap (xml_parser, std::forward<TFunc>(func));
201+ }
202+
203+ static void XMLCALL start_element_wrapper (void * data, const XML_Char* element, const XML_Char** attrs) noexcept {
204+ wrap (data, [&](XMLParser& xml_parser) {
205+ xml_parser.start_element (element, attrs);
206+ });
183207 }
184208
185- static void XMLCALL end_element_wrapper (void * data, const XML_Char* element) {
186- static_cast <XMLParser*>(data)->end_element (element);
209+ static void XMLCALL end_element_wrapper (void * data, const XML_Char* element) noexcept {
210+ wrap (data, [&](XMLParser& xml_parser) {
211+ xml_parser.end_element (element);
212+ });
187213 }
188214
189- static void XMLCALL character_data_wrapper (void * data, const XML_Char* text, int len) {
190- static_cast <XMLParser*>(data)->characters (text, len);
215+ static void XMLCALL character_data_wrapper (void * data, const XML_Char* text, int len) noexcept {
216+ wrap (data, [&](XMLParser& xml_parser) {
217+ xml_parser.characters (text, len);
218+ });
191219 }
192220
193221 // This handler is called when there are any XML entities
194222 // declared in the OSM file. Entities are normally not used,
195223 // but they can be misused. See
196224 // https://en.wikipedia.org/wiki/Billion_laughs
197225 // The handler will just throw an error.
198- static void entity_declaration_handler (void * /* userData */ ,
226+ static void entity_declaration_handler (void * data ,
199227 const XML_Char* /* entityName*/ ,
200228 int /* is_parameter_entity*/ ,
201229 const XML_Char* /* value*/ ,
202230 int /* value_length*/ ,
203231 const XML_Char* /* base*/ ,
204232 const XML_Char* /* systemId*/ ,
205233 const XML_Char* /* publicId*/ ,
206- const XML_Char* /* notationName*/ ) {
207- throw osmium::xml_error{" XML entities are not supported" };
234+ const XML_Char* /* notationName*/ ) noexcept {
235+ wrap (data, [&](XMLParser& /* xml_parser*/ ) {
236+ throw osmium::xml_error{" XML entities are not supported" };
237+ });
208238 }
209239
210240 public:
@@ -233,12 +263,17 @@ namespace osmium {
233263 void operator ()(const std::string& data, bool last) {
234264 assert (data.size () < std::numeric_limits<int >::max ());
235265 if (XML_Parse (m_parser, data.data (), static_cast <int >(data.size ()), last) == XML_STATUS_ERROR) {
266+ if (m_exception_ptr) {
267+ std::rethrow_exception (m_exception_ptr);
268+ }
236269 throw osmium::xml_error{m_parser};
237270 }
238271 }
239272
240273 }; // class ExpatXMLParser
241274
275+ ExpatXMLParser* m_expat_xml_parser{nullptr };
276+
242277 template <typename T>
243278 static void check_attributes (const XML_Char** attrs, T&& check) {
244279 while (*attrs) {
@@ -739,6 +774,7 @@ namespace osmium {
739774 osmium::thread::set_thread_name (" _osmium_xml_in" );
740775
741776 ExpatXMLParser parser{this };
777+ m_expat_xml_parser = &parser;
742778
743779 while (!input_done ()) {
744780 const std::string data{get_input ()};
0 commit comments