377 lines
7.0 KiB
C++
377 lines
7.0 KiB
C++
//////////////////////////////////////////////////
|
|
// expat [XMLEntity.cpp]
|
|
//////////////////////////////////////////////////
|
|
|
|
#include "XMLEntity.h"
|
|
|
|
#include <cstring>
|
|
#include <stdlib.h>
|
|
|
|
XMLEntity::XMLEntity(const char *name, const char **atts) {
|
|
_parent = NULL;
|
|
_children = new vector<XMLEntity *>;
|
|
|
|
_name = strdup(name);
|
|
_atts = NULL;
|
|
_character_data = NULL;
|
|
_is_complete = false;
|
|
|
|
SetAttributes(atts);
|
|
}
|
|
|
|
XMLEntity::~XMLEntity() {
|
|
// delete all children (depth first)
|
|
for (vector<XMLEntity *>::iterator i=_children->begin(); i != _children->end(); ++i) {
|
|
delete *i;
|
|
}
|
|
|
|
// delete self
|
|
delete _children;
|
|
free(_name);
|
|
|
|
// delete attributes
|
|
if (_atts != NULL) {
|
|
for (int i=0; i<(CountAttributes() + 2); ++i) {
|
|
free(_atts[i]);
|
|
}
|
|
|
|
free(_atts);
|
|
}
|
|
|
|
free(_character_data);
|
|
}
|
|
|
|
XMLEntity *XMLEntity::Parent() {
|
|
return _parent;
|
|
}
|
|
|
|
XMLEntity *XMLEntity::Child(int index) {
|
|
return (*_children)[index];
|
|
}
|
|
|
|
XMLEntity *XMLEntity::Child(const char *name) {
|
|
if (name) {
|
|
for (int i=0; i<CountChildren(); ++i)
|
|
if (!strcasecmp(Child(i)->Name(), name))
|
|
return Child(i);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const char *XMLEntity::Name() {
|
|
return _name;
|
|
}
|
|
|
|
const char *XMLEntity::Attribute(const char *key) {
|
|
if (_atts)
|
|
for(int i=0; _atts[i] && *_atts[i]; i+=2)
|
|
if (!strcasecmp(_atts[i], key))
|
|
return _atts[i+1];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const char *XMLEntity::AttributeKey(int index) {
|
|
return _atts[index << 1];
|
|
}
|
|
|
|
const char *XMLEntity::AttributeValue(int index) {
|
|
return _atts[(index << 1) + 1];
|
|
}
|
|
|
|
const char *XMLEntity::CharacterData() {
|
|
if (_character_data && *_character_data)
|
|
return _character_data;
|
|
else
|
|
return "";
|
|
}
|
|
|
|
const char *XMLEntity::ChildData(const char *name) {
|
|
XMLEntity *child = Child(name);
|
|
|
|
// if the child exists
|
|
if (child)
|
|
return child->Data();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const char *XMLEntity::Data() {
|
|
return CharacterData();
|
|
}
|
|
|
|
char *XMLEntity::ToString(bool encoded, int level) {
|
|
// piece together text-version XML from XMLEntity
|
|
string text = "";
|
|
|
|
// assemble indent size
|
|
string indent = "";
|
|
|
|
string character_data = EscapeText(CharacterData());
|
|
|
|
for(int i=0; i<level; ++i)
|
|
indent += "\t";
|
|
|
|
// starting tag
|
|
text = indent;
|
|
text += "<";
|
|
text += Name();
|
|
|
|
// attributes
|
|
for(int i=0; i < CountAttributes(); ++i) {
|
|
text += " ";
|
|
text += AttributeKey(i);
|
|
text += "=";
|
|
text += "\"";
|
|
text += EscapeText(AttributeValue(i));
|
|
text += "\"";
|
|
}
|
|
|
|
// is this a starting/closing combo tag?
|
|
if (character_data.size() == 0 && CountChildren() == 0)
|
|
text += "/";
|
|
|
|
text += ">";
|
|
|
|
// character data
|
|
text += character_data;
|
|
|
|
// children
|
|
if (CountChildren() > 0) {
|
|
text += "\n";
|
|
|
|
for (int i=0; i < CountChildren(); ++i) {
|
|
char *str = Child(i)->ToString(encoded, level + 1);
|
|
if (str) {
|
|
text += str;
|
|
free(str);
|
|
}
|
|
}
|
|
|
|
text += indent;
|
|
}
|
|
|
|
// closing tag
|
|
if (CountChildren() > 0 || character_data.size() > 0) {
|
|
text += "</";
|
|
text += Name();
|
|
text += ">";
|
|
}
|
|
|
|
// end
|
|
text += "\n";
|
|
|
|
// possible point of memory leak - needs resolution
|
|
return strdup(text.c_str());
|
|
}
|
|
|
|
char *XMLEntity::StartToString(__attribute__((unused)) bool encoded) {
|
|
// piece together text-version XML from XMLEntity
|
|
string text = "";
|
|
|
|
// starting tag
|
|
text += "<";
|
|
text += Name();
|
|
|
|
// attributes
|
|
for(int i=0; i < CountAttributes(); ++i) {
|
|
text += " ";
|
|
text += AttributeKey(i);
|
|
text += "=";
|
|
text += "\"";
|
|
text += EscapeText(AttributeValue(i));
|
|
text += "\"";
|
|
}
|
|
|
|
text += ">";
|
|
|
|
// possible point of memory leak - needs resolution
|
|
return strdup(text.c_str());
|
|
}
|
|
|
|
char *XMLEntity::EndToString() {
|
|
// piece together text-version XML from XMLEntity
|
|
string text = "";
|
|
|
|
// closing tag
|
|
text += "</";
|
|
text += Name();
|
|
text += ">";
|
|
|
|
// possible point of memory leak - needs resolution
|
|
return strdup(text.c_str());
|
|
}
|
|
|
|
int XMLEntity::CountChildren() {
|
|
return _children->size();
|
|
}
|
|
|
|
int XMLEntity::CountAttributes() {
|
|
if (!_atts)
|
|
return 0;
|
|
|
|
int i = 0;
|
|
|
|
for(i=0; _atts[i] != NULL; i+=2);
|
|
|
|
return (i >> 1);
|
|
}
|
|
|
|
bool XMLEntity::IsCompleted() {
|
|
return _is_complete;
|
|
}
|
|
void XMLEntity::SetName(const char *new_name) {
|
|
if (_name) {
|
|
free(_name);
|
|
_name = NULL;
|
|
}
|
|
|
|
_name = strdup(new_name);
|
|
}
|
|
|
|
void XMLEntity::SetParent(XMLEntity *entity) {
|
|
_parent = entity;
|
|
}
|
|
|
|
void XMLEntity::AddChild(XMLEntity *entity) {
|
|
// automatically set parent of target child
|
|
entity->SetParent(this);
|
|
|
|
// add child
|
|
_children->push_back(entity);
|
|
}
|
|
|
|
void XMLEntity::AddChild(const char *name, const char **atts, const char *data) {
|
|
XMLEntity *entity = new XMLEntity(name, atts);
|
|
entity->SetCharacterData(data);
|
|
AddChild(entity);
|
|
}
|
|
|
|
void XMLEntity::RemoveChild(const char *name) {
|
|
for (vector<XMLEntity *>::iterator i=_children->begin(); i != _children->end(); ++i) {
|
|
if (!strcasecmp((*i)->Name(), name)) {
|
|
delete *i;
|
|
_children->erase(i);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void XMLEntity::RemoveChild(XMLEntity *entity) {
|
|
for (vector<XMLEntity *>::iterator i=_children->begin(); i != _children->end(); ++i)
|
|
if ((*i) == entity) {
|
|
delete *i;
|
|
_children->erase(i);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
void XMLEntity::RemoveSelf() {
|
|
if(Parent()) {
|
|
Parent()->RemoveChild(this);
|
|
} else {
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
void XMLEntity::SetAttributes(const char **atts) {
|
|
// delete attributes
|
|
if (_atts != NULL) {
|
|
for (int i=0; i<(CountAttributes() + 2); ++i) {
|
|
delete[] _atts[i];
|
|
}
|
|
|
|
delete[] _atts;
|
|
|
|
_atts = NULL;
|
|
}
|
|
|
|
if (atts == NULL)
|
|
return;
|
|
|
|
// initialize attributes
|
|
int i;
|
|
|
|
for (i=0; atts[i] && *atts[i] && atts[i+1]; i+=2);
|
|
|
|
if (i > 0) {
|
|
_atts = (char **)malloc((i+2) * sizeof(char *));
|
|
|
|
for(int j=0; j<i; j+=2) {
|
|
_atts[j] = strdup(atts[j]);
|
|
_atts[j+1] = strdup(atts[j+1]);
|
|
}
|
|
|
|
_atts[i] = NULL;
|
|
_atts[i+1] = NULL;
|
|
}
|
|
}
|
|
|
|
void XMLEntity::SetCharacterData(const char *data) {
|
|
// clear data?
|
|
if (data && *data) {
|
|
if (_character_data) {
|
|
free(_character_data);
|
|
_character_data = NULL;
|
|
}
|
|
|
|
_character_data = strdup(data);
|
|
} else {
|
|
_character_data = NULL;
|
|
}
|
|
}
|
|
|
|
void XMLEntity::SetData(const char *data) {
|
|
SetCharacterData(data);
|
|
}
|
|
|
|
void XMLEntity::SetCompleted(bool is_complete) {
|
|
_is_complete = is_complete;
|
|
}
|
|
|
|
string XMLEntity::EscapeText(string text) {
|
|
size_t replacement;
|
|
|
|
replacement = 0;
|
|
while ((replacement = text.find("&", replacement)) != string::npos) {
|
|
text.replace(replacement++, 1, "&");
|
|
}
|
|
|
|
replacement = 0;
|
|
while ((replacement = text.find("<", replacement)) != string::npos) {
|
|
text.replace(replacement++, 1, "<");
|
|
}
|
|
|
|
replacement = 0;
|
|
while ((replacement = text.find(">", replacement)) != string::npos) {
|
|
text.replace(replacement++, 1, ">");
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
string XMLEntity::DeEscapeText(string text) {
|
|
size_t replacement;
|
|
|
|
replacement = 0;
|
|
while ((replacement = text.find("&", replacement)) != string::npos) {
|
|
text.replace(replacement++, 5, "&");
|
|
}
|
|
|
|
replacement = 0;
|
|
while ((replacement = text.find("<", replacement)) != string::npos) {
|
|
text.replace(replacement++, 4, "<");
|
|
}
|
|
|
|
replacement = 0;
|
|
while ((replacement = text.find(">", replacement)) != string::npos) {
|
|
text.replace(replacement++, 4, ">");
|
|
}
|
|
|
|
return text;
|
|
|
|
}
|