Renga/jabber/XMLReader.cpp

184 lines
4.3 KiB
C++

//////////////////////////////////////////////////
// expat [XMLReader.cpp]
//////////////////////////////////////////////////
#include "XMLReader.h"
#include <cstdio>
#include <string>
#include <string.h>
#include <stdlib.h>
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("&apos;")) != string::npos) {
_curr_character_data.replace(replacement, 6, "&");
}
while ((replacement = _curr_character_data.find("&lt;")) != string::npos) {
_curr_character_data.replace(replacement, 4, "<");
}
while ((replacement = _curr_character_data.find("&gt;")) != 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);
}