// Standard C++ #include #include #include #include // Project #include "xml.hpp" // Expat XML Parser #include "expat.h" using namespace std; void XML::parse(istream& ins) { unique_ptr parser(::XML_ParserCreate(nullptr), ::XML_ParserFree); if ( !parser ) { throw bad_alloc(); } // setup expat ::XML_SetUserData(parser.get(), this); ::XML_SetElementHandler(parser.get(), tag_start, tag_end); ::XML_SetCdataSectionHandler(parser.get(), cdata_start, cdata_end); ::XML_SetCharacterDataHandler(parser.get(), data); constexpr auto buffer_size = 2048; array buffer{}; for ( bool done = false; !done; ) { ins.read(buffer.data(), buffer_size); done = ins.gcount() < buffer_size; if ( ::XML_Parse(parser.get(), buffer.data(), static_cast(ins.gcount()), static_cast(done)) != XML_STATUS_OK ) { stringstream msg; msg << ::XML_ErrorString(XML_GetErrorCode(parser.get())); msg << " in line " << ::XML_GetCurrentLineNumber(parser.get()); throw runtime_error(msg.str()); } } } void XML::tag_start(void* self, const char* name, const char** attr) { vector> attr_temp; for ( auto i = 0; attr[i] != nullptr; i += 2 ) { attr_temp.emplace_back(attr[i], attr[i + 1]); } static_cast(self)->handle_start(name, attr_temp); } void XML::tag_end(void* self, const char* name) { static_cast(self)->handle_end(name); } void XML::cdata_start(void* self) { static_cast(self)->handle_cdata_start(); } void XML::cdata_end(void* self) { static_cast(self)->handle_cdata_end(); } void XML::data(void* self, const char* dat, int len) { static_cast(self)->handle_character_data({ dat, static_cast(len) }); }