////////////////////////////////////////////////// // expat [XMLReader.cpp] ////////////////////////////////////////////////// #include "XMLReader.h" #include #include #include #include XMLReader::XMLReader() { _parser = NULL; _xml_entity = NULL; _curr_entity = NULL; _curr_character_data = ""; _please_reset = false; // Create parser _parser = XML_ParserCreate(NULL); if (_parser) { XML_SetUserData(_parser, this); XML_SetElementHandler(_parser, _StaticOnStartTag, _StaticOnEndTag); XML_SetCharacterDataHandler(_parser, _StaticOnCharacterData); } } XMLReader::~XMLReader() { if (_parser) XML_ParserFree(_parser); delete _xml_entity; //if (_xml_entity != _curr_entity) { // delete _curr_entity; //} } void XMLReader::Reset() { _please_reset = true; } void XMLReader::FeedData(const char *data, int len) { // do we need to reset? if (_please_reset) { XML_ParserFree(_parser); _parser = NULL; delete _xml_entity; _xml_entity = NULL; _curr_entity = NULL; _curr_character_data = ""; _please_reset = false; // Create parser _parser = XML_ParserCreate(NULL); if (_parser) { XML_SetUserData(_parser, this); XML_SetElementHandler(_parser, _StaticOnStartTag, _StaticOnEndTag); XML_SetCharacterDataHandler(_parser, _StaticOnCharacterData); } } // weed out if (_parser && !XML_Parse(_parser, data, len, 0)) { _please_reset = true; } } void XMLReader::_StaticOnStartTag(void *userData, const char *name, const char **atts) { ((XMLReader *)userData)->_OnStartTag(name, atts); } void XMLReader::_StaticOnEndTag(void *userData, const char *name) { ((XMLReader *)userData)->_OnEndTag(name); } void XMLReader::_StaticOnCharacterData(void *userData, const XML_Char *data, int len) { ((XMLReader *)userData)->_OnCharacterData(data, len); } void XMLReader::_OnStartTag(const char *name, const char **atts) { // ignore ?xml if (!strcasecmp(name, "?xml")) { return; } // clear character data _curr_character_data = ""; // Make new entity: if current is NULL, set it (current)...else, make child XMLEntity *new_entity = new XMLEntity(name, atts); if (_xml_entity == NULL) { _curr_entity = _xml_entity = new_entity; } else { // Add child _curr_entity->AddChild(new_entity); // New current entry _curr_entity = new_entity; } // Callback OnStartTag(_curr_entity); } void XMLReader::_OnEndTag(__attribute__((unused)) const char *name) { // Add existing character data to entity if (_curr_character_data.size() > 0) _curr_entity->SetCharacterData(_curr_character_data.c_str()); // Close it off _curr_entity->SetCompleted(true); // Clean character data buffer _curr_character_data = ""; // Callback OnEndTag(_curr_entity); // end here if we've been reset if (_xml_entity == NULL) { return; } // Revert current entity to parent if (_curr_entity && (_curr_entity == _xml_entity)) { // Transfer XMLEntity tree to user. (They must delete) XMLEntity *completed_entity = _xml_entity; _curr_entity = _xml_entity = NULL; // Serve up the current tree (USER deletes) OnEndEntity(completed_entity); } else { _curr_entity = _curr_entity->Parent(); } } void XMLReader::_OnCharacterData(const XML_Char *data, int len) { // Populate current entity character data char *new_data = (char *)malloc((len + 1) * sizeof(char)); strncpy(new_data, data, len); new_data[len] = '\0'; if (!new_data || *new_data == 0) { return; } // Clean up character data string added_data = new_data; if (_curr_character_data.size() == 0) while (added_data.size() > 0 && (added_data[0] == ' ' || added_data[0] == '\n')) added_data.erase(0, 1); size_t replacement; while ((replacement = _curr_character_data.find("'")) != string::npos) { _curr_character_data.replace(replacement, 6, "&"); } while ((replacement = _curr_character_data.find("<")) != string::npos) { _curr_character_data.replace(replacement, 4, "<"); } while ((replacement = _curr_character_data.find(">")) != string::npos) { _curr_character_data.replace(replacement, 4, ">"); } // Add to current running data // TBD: put data in curr_entity instead _curr_character_data += added_data; free(new_data); }