Files
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

1073 lines
23 KiB
C++

//========================================================================
//
// Zoox.cc
//
//========================================================================
#include <aconf.h>
#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "gmem.h"
#include "gmempp.h"
#include "GString.h"
#include "GList.h"
#include "GHash.h"
#include "Zoox.h"
//~ all of this code assumes the encoding is UTF-8 or ASCII or something
//~ similar (ISO-8859-*)
//------------------------------------------------------------------------
static char nameStartChar[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // 30
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 50
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 70
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // a0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // b0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // c0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // d0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // e0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // f0
};
static char nameChar[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // 20
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 30
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 50
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 70
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // a0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // b0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // c0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // d0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // e0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // f0
};
//------------------------------------------------------------------------
ZxNode::ZxNode() {
next = NULL;
parent = NULL;
firstChild = lastChild = NULL;
}
ZxNode::~ZxNode() {
ZxNode *child;
while (firstChild) {
child = firstChild;
firstChild = firstChild->next;
delete child;
}
}
ZxNode *ZxNode::deleteChild(ZxNode *child) {
ZxNode *p1, *p2;
for (p1 = NULL, p2 = firstChild;
p2 && p2 != child;
p1 = p2, p2 = p2->next) ;
if (!p2) {
return NULL;
}
if (p1) {
p1->next = child->next;
} else {
firstChild = child->next;
}
child->parent = NULL;
child->next = NULL;
return child;
}
void ZxNode::appendChild(ZxNode *child) {
ZxNode *p1;
if (child->parent || child->next) {
return;
}
if (firstChild) {
for (p1 = firstChild; p1->next; p1 = p1->next) ;
p1->next = child;
} else {
firstChild = child;
}
child->parent = this;
}
void ZxNode::insertChildAfter(ZxNode *child, ZxNode *prev) {
if (child->parent || child->next || (prev && prev->parent != this)) {
return;
}
if (prev) {
child->next = prev->next;
prev->next = child;
} else {
child->next = firstChild;
firstChild = child;
}
child->parent = this;
}
ZxElement *ZxNode::findFirstElement(const char *type) {
ZxNode *child;
ZxElement *result;
if (isElement(type)) {
return (ZxElement *)this;
}
for (child = firstChild; child; child = child->next) {
if ((result = child->findFirstElement(type))) {
return result;
}
}
return NULL;
}
ZxElement *ZxNode::findFirstChildElement(const char *type) {
ZxNode *child;
for (child = firstChild; child; child = child->next) {
if (child->isElement(type)) {
return (ZxElement *)child;
}
}
return NULL;
}
GList *ZxNode::findAllElements(const char *type) {
GList *results;
results = new GList();
findAllElements(type, results);
return results;
}
void ZxNode::findAllElements(const char *type, GList *results) {
ZxNode *child;
if (isElement(type)) {
results->append(this);
}
for (child = firstChild; child; child = child->next) {
child->findAllElements(type, results);
}
}
GList *ZxNode::findAllChildElements(const char *type) {
GList *results;
ZxNode *child;
results = new GList();
for (child = firstChild; child; child = child->next) {
if (child->isElement(type)) {
results->append(child);
}
}
return results;
}
void ZxNode::addChild(ZxNode *child) {
if (lastChild) {
lastChild->next = child;
lastChild = child;
} else {
firstChild = lastChild = child;
}
child->parent = this;
child->next = NULL;
}
//------------------------------------------------------------------------
ZxDoc::ZxDoc() {
xmlDecl = NULL;
docTypeDecl = NULL;
root = NULL;
}
ZxDoc *ZxDoc::loadMem(const char *data, Guint dataLen) {
ZxDoc *doc;
doc = new ZxDoc();
if (!doc->parse(data, dataLen)) {
delete doc;
return NULL;
}
return doc;
}
ZxDoc *ZxDoc::loadFile(const char *fileName) {
ZxDoc *doc;
FILE *f;
char *data;
Guint dataLen;
if (!(f = fopen(fileName, "rb"))) {
return NULL;
}
fseek(f, 0, SEEK_END);
dataLen = (Guint)ftell(f);
if (!dataLen) {
fclose(f);
return NULL;
}
fseek(f, 0, SEEK_SET);
data = (char *)gmalloc(dataLen);
if (fread(data, 1, dataLen, f) != dataLen) {
fclose(f);
gfree(data);
return NULL;
}
fclose(f);
doc = loadMem(data, dataLen);
gfree(data);
return doc;
}
ZxDoc::~ZxDoc() {
}
static bool writeToFileFunc(void *stream, const char *data, int length) {
return (int)fwrite(data, 1, length, (FILE *)stream) == length;
}
bool ZxDoc::writeFile(const char *fileName) {
FILE *f;
if (!(f = fopen(fileName, "wb"))) {
return false;
}
write(&writeToFileFunc, f);
fclose(f);
return true;
}
void ZxDoc::addChild(ZxNode *node) {
if (node->isXMLDecl() && !xmlDecl) {
xmlDecl = (ZxXMLDecl *)node;
} else if (node->isDocTypeDecl() && !docTypeDecl) {
docTypeDecl = (ZxDocTypeDecl *)node;
} else if (node->isElement() && !root) {
root = (ZxElement *)node;
}
ZxNode::addChild(node);
}
bool ZxDoc::parse(const char *data, Guint dataLen) {
parsePtr = data;
parseEnd = data + dataLen;
parseSpace();
parseXMLDecl(this);
parseMisc(this);
parseDocTypeDecl(this);
parseMisc(this);
if (match("<")) {
parseElement(this);
}
parseMisc(this);
return root != NULL;
}
void ZxDoc::parseXMLDecl(ZxNode *par) {
GString *version, *encoding, *s;
bool standalone;
if (!match("<?xml")) {
return;
}
parsePtr += 5;
parseSpace();
// version
version = NULL;
if (match("version")) {
parsePtr += 7;
parseSpace();
if (match("=")) {
++parsePtr;
parseSpace();
version = parseQuotedString();
}
}
if (!version) {
version = new GString("1.0");
}
parseSpace();
// encoding
encoding = NULL;
if (match("encoding")) {
parsePtr += 8;
parseSpace();
if (match("=")) {
++parsePtr;
parseSpace();
encoding = parseQuotedString();
}
}
parseSpace();
// standalone
standalone = false;
if (match("standalone")) {
parsePtr += 10;
parseSpace();
if (match("=")) {
++parsePtr;
parseSpace();
s = parseQuotedString();
standalone = !s->cmp("yes");
delete s;
}
}
parseSpace();
if (match("?>")) {
parsePtr += 2;
}
par->addChild(new ZxXMLDecl(version, encoding, standalone));
}
//~ this just skips everything after the name
void ZxDoc::parseDocTypeDecl(ZxNode *par) {
GString *name;
int state;
char c, quote;
if (!match("<!DOCTYPE")) {
return;
}
parsePtr += 9;
parseSpace();
name = parseName();
parseSpace();
state = 0;
quote = '\0';
while (parsePtr < parseEnd && state < 4) {
c = *parsePtr++;
switch (state) {
case 0: // not in square brackets; not in quotes
if (c == '>') {
state = 4;
} else if (c == '"' || c == '\'') {
state = 1;
} else if (c == '[') {
state = 2;
}
break;
case 1: // not in square brackets; in quotes
if (c == quote) {
state = 0;
}
break;
case 2: // in square brackets; not in quotes
if (c == ']') {
state = 0;
} else if (c == '"' || c == '\'') {
state = 3;
}
break;
case 3: // in square brackets; in quotes
if (c == quote) {
state = 2;
}
break;
}
}
par->addChild(new ZxDocTypeDecl(name));
}
// assumes match("<")
void ZxDoc::parseElement(ZxNode *par) {
GString *type;
ZxElement *elem;
ZxAttr *attr;
++parsePtr;
type = parseName();
elem = new ZxElement(type);
parseSpace();
while ((attr = parseAttr())) {
elem->addAttr(attr);
parseSpace();
}
if (match("/>")) {
parsePtr += 2;
} else if (match(">")) {
++parsePtr;
parseContent(elem);
}
par->addChild(elem);
}
ZxAttr *ZxDoc::parseAttr() {
GString *name, *value;
const char *start;
char quote, c;
unsigned int x;
int n;
name = parseName();
parseSpace();
if (!match("=")) {
delete name;
return NULL;
}
++parsePtr;
parseSpace();
if (!(parsePtr < parseEnd && (*parsePtr == '"' || *parsePtr == '\''))) {
delete name;
return NULL;
}
quote = *parsePtr++;
value = new GString();
while (parsePtr < parseEnd && *parsePtr != quote) {
if (*parsePtr == '&') {
++parsePtr;
if (parsePtr < parseEnd && *parsePtr == '#') {
++parsePtr;
if (parsePtr < parseEnd && *parsePtr == 'x') {
++parsePtr;
x = 0;
while (parsePtr < parseEnd) {
c = *parsePtr;
if (c >= '0' && c <= '9') {
x = (x << 4) + (c - '0');
} else if (c >= 'a' && c <= 'f') {
x = (x << 4) + (10 + c - 'a');
} else if (c >= 'A' && c <= 'F') {
x = (x << 4) + (10 + c - 'A');
} else {
break;
}
++parsePtr;
}
if (parsePtr < parseEnd && *parsePtr == ';') {
++parsePtr;
}
appendUTF8(value, x);
} else {
x = 0;
while (parsePtr < parseEnd) {
c = *parsePtr;
if (c >= '0' && c <= '9') {
x = x * 10 + (c - '0');
} else {
break;
}
++parsePtr;
}
if (parsePtr < parseEnd && *parsePtr == ';') {
++parsePtr;
}
appendUTF8(value, x);
}
} else {
start = parsePtr;
for (++parsePtr;
parsePtr < parseEnd && *parsePtr != ';' &&
*parsePtr != quote && *parsePtr != '&';
++parsePtr) ;
n = (int)(parsePtr - start);
if (parsePtr < parseEnd && *parsePtr == ';') {
++parsePtr;
}
if (n == 2 && !strncmp(start, "lt", 2)) {
value->append('<');
} else if (n == 2 && !strncmp(start, "gt", 2)) {
value->append('>');
} else if (n == 3 && !strncmp(start, "amp", 3)) {
value->append('&');
} else if (n == 4 && !strncmp(start, "apos", 4)) {
value->append('\'');
} else if (n == 4 && !strncmp(start, "quot", 4)) {
value->append('"');
} else {
value->append(start - 1, (int)(parsePtr - start) + 1);
}
}
} else {
start = parsePtr;
for (++parsePtr;
parsePtr < parseEnd && *parsePtr != quote && *parsePtr != '&';
++parsePtr) ;
value->append(start, (int)(parsePtr - start));
}
}
if (parsePtr < parseEnd && *parsePtr == quote) {
++parsePtr;
}
return new ZxAttr(name, value);
}
// this consumes the end tag
void ZxDoc::parseContent(ZxElement *par) {
GString *endType;
endType = (new GString("</"))->append(par->getType());
while (parsePtr < parseEnd) {
if (match(endType->getCString())) {
parsePtr += endType->getLength();
parseSpace();
if (match(">")) {
++parsePtr;
}
break;
} else if (match("<?")) {
parsePI(par);
} else if (match("<![CDATA[")) {
parseCDSect(par);
} else if (match("<!--")) {
parseComment(par);
} else if (match("<")) {
parseElement(par);
} else {
parseCharData(par);
}
}
delete endType;
}
void ZxDoc::parseCharData(ZxElement *par) {
GString *data;
const char *start;
char c;
unsigned int x;
int n;
data = new GString();
while (parsePtr < parseEnd && *parsePtr != '<') {
if (*parsePtr == '&') {
++parsePtr;
if (parsePtr < parseEnd && *parsePtr == '#') {
++parsePtr;
if (parsePtr < parseEnd && *parsePtr == 'x') {
++parsePtr;
x = 0;
while (parsePtr < parseEnd) {
c = *parsePtr;
if (c >= '0' && c <= '9') {
x = (x << 4) + (c - '0');
} else if (c >= 'a' && c <= 'f') {
x = (x << 4) + (10 + c - 'a');
} else if (c >= 'A' && c <= 'F') {
x = (x << 4) + (10 + c - 'A');
} else {
break;
}
++parsePtr;
}
if (parsePtr < parseEnd && *parsePtr == ';') {
++parsePtr;
}
appendUTF8(data, x);
} else {
x = 0;
while (parsePtr < parseEnd) {
c = *parsePtr;
if (c >= '0' && c <= '9') {
x = x * 10 + (c - '0');
} else {
break;
}
++parsePtr;
}
if (parsePtr < parseEnd && *parsePtr == ';') {
++parsePtr;
}
appendUTF8(data, x);
}
} else {
start = parsePtr;
for (++parsePtr;
parsePtr < parseEnd && *parsePtr != ';' &&
*parsePtr != '<' && *parsePtr != '&';
++parsePtr) ;
n = (int)(parsePtr - start);
if (parsePtr < parseEnd && *parsePtr == ';') {
++parsePtr;
}
if (n == 2 && !strncmp(start, "lt", 2)) {
data->append('<');
} else if (n == 2 && !strncmp(start, "gt", 2)) {
data->append('>');
} else if (n == 3 && !strncmp(start, "amp", 3)) {
data->append('&');
} else if (n == 4 && !strncmp(start, "apos", 4)) {
data->append('\'');
} else if (n == 4 && !strncmp(start, "quot", 4)) {
data->append('"');
} else {
data->append(start - 1, (int)(parsePtr - start) + 1);
}
}
} else {
start = parsePtr;
for (++parsePtr;
parsePtr < parseEnd && *parsePtr != '<' && *parsePtr != '&';
++parsePtr) ;
data->append(start, (int)(parsePtr - start));
}
}
par->addChild(new ZxCharData(data, true));
}
void ZxDoc::appendUTF8(GString *s, unsigned int c) {
if (c <= 0x7f) {
s->append((char)c);
} else if (c <= 0x7ff) {
s->append((char)(0xc0 + (c >> 6)));
s->append((char)(0x80 + (c & 0x3f)));
} else if (c <= 0xffff) {
s->append((char)(0xe0 + (c >> 12)));
s->append((char)(0x80 + ((c >> 6) & 0x3f)));
s->append((char)(0x80 + (c & 0x3f)));
} else if (c <= 0x1fffff) {
s->append((char)(0xf0 + (c >> 18)));
s->append((char)(0x80 + ((c >> 12) & 0x3f)));
s->append((char)(0x80 + ((c >> 6) & 0x3f)));
s->append((char)(0x80 + (c & 0x3f)));
} else if (c <= 0x3ffffff) {
s->append((char)(0xf8 + (c >> 24)));
s->append((char)(0x80 + ((c >> 18) & 0x3f)));
s->append((char)(0x80 + ((c >> 12) & 0x3f)));
s->append((char)(0x80 + ((c >> 6) & 0x3f)));
s->append((char)(0x80 + (c & 0x3f)));
} else if (c <= 0x7fffffff) {
s->append((char)(0xfc + (c >> 30)));
s->append((char)(0x80 + ((c >> 24) & 0x3f)));
s->append((char)(0x80 + ((c >> 18) & 0x3f)));
s->append((char)(0x80 + ((c >> 12) & 0x3f)));
s->append((char)(0x80 + ((c >> 6) & 0x3f)));
s->append((char)(0x80 + (c & 0x3f)));
}
}
// assumes match("<![CDATA[")
void ZxDoc::parseCDSect(ZxNode *par) {
const char *start;
parsePtr += 9;
start = parsePtr;
while (parsePtr < parseEnd - 3) {
if (!strncmp(parsePtr, "]]>", 3)) {
par->addChild(new ZxCharData(new GString(start, (int)(parsePtr - start)),
false));
parsePtr += 3;
return;
}
++parsePtr;
}
parsePtr = parseEnd;
par->addChild(new ZxCharData(new GString(start, (int)(parsePtr - start)),
false));
}
void ZxDoc::parseMisc(ZxNode *par) {
while (1) {
if (match("<!--")) {
parseComment(par);
} else if (match("<?")) {
parsePI(par);
} else if (parsePtr < parseEnd && (*parsePtr == '\x20' ||
*parsePtr == '\x09' ||
*parsePtr == '\x0d' ||
*parsePtr == '\x0a')) {
++parsePtr;
} else {
break;
}
}
}
// assumes match("<!--")
void ZxDoc::parseComment(ZxNode *par) {
const char *start;
parsePtr += 4;
start = parsePtr;
while (parsePtr <= parseEnd - 3) {
if (!strncmp(parsePtr, "-->", 3)) {
par->addChild(new ZxComment(new GString(start, (int)(parsePtr - start))));
parsePtr += 3;
return;
}
++parsePtr;
}
parsePtr = parseEnd;
}
// assumes match("<?")
void ZxDoc::parsePI(ZxNode *par) {
GString *target;
const char *start;
parsePtr += 2;
target = parseName();
parseSpace();
start = parsePtr;
while (parsePtr <= parseEnd - 2) {
if (!strncmp(parsePtr, "?>", 2)) {
par->addChild(new ZxPI(target, new GString(start,
(int)(parsePtr - start))));
parsePtr += 2;
return;
}
++parsePtr;
}
parsePtr = parseEnd;
par->addChild(new ZxPI(target, new GString(start, (int)(parsePtr - start))));
}
//~ this accepts all chars >= 0x80
//~ this doesn't check for properly-formed UTF-8
GString *ZxDoc::parseName() {
GString *name;
name = new GString();
if (parsePtr < parseEnd && nameStartChar[*parsePtr & 0xff]) {
name->append(*parsePtr++);
while (parsePtr < parseEnd && nameChar[*parsePtr & 0xff]) {
name->append(*parsePtr++);
}
}
return name;
}
GString *ZxDoc::parseQuotedString() {
GString *s;
const char *start;
char quote;
if (parsePtr < parseEnd && (*parsePtr == '"' || *parsePtr == '\'')) {
quote = *parsePtr++;
start = parsePtr;
while (parsePtr < parseEnd && *parsePtr != quote) {
++parsePtr;
}
s = new GString(start, (int)(parsePtr - start));
if (parsePtr < parseEnd && *parsePtr == quote) {
++parsePtr;
}
} else {
s = new GString();
}
return s;
}
void ZxDoc::parseSpace() {
while (parsePtr < parseEnd && (*parsePtr == '\x20' ||
*parsePtr == '\x09' ||
*parsePtr == '\x0d' ||
*parsePtr == '\x0a')) {
++parsePtr;
}
}
bool ZxDoc::match(const char *s) {
int n;
n = (int)strlen(s);
return parseEnd - parsePtr >= n && !strncmp(parsePtr, s, n);
}
bool ZxDoc::write(ZxWriteFunc writeFunc, void *stream) {
ZxNode *child;
for (child = getFirstChild(); child; child = child->getNextChild()) {
if (!child->write(writeFunc, stream)) {
return false;
}
if (!(*writeFunc)(stream, "\n", 1)) {
return false;
}
}
return true;
}
//------------------------------------------------------------------------
ZxXMLDecl::ZxXMLDecl(GString *versionA, GString *encodingA, bool standaloneA) {
version = versionA;
encoding = encodingA;
standalone = standaloneA;
}
ZxXMLDecl::~ZxXMLDecl() {
delete version;
if (encoding) {
delete encoding;
}
}
bool ZxXMLDecl::write(ZxWriteFunc writeFunc, void *stream) {
GString *s;
bool ok;
s = new GString("<?xml version=\"");
s->append(version);
s->append("\"");
if (encoding) {
s->append(" encoding=\"");
s->append(encoding);
s->append("\"");
}
if (standalone) {
s->append(" standlone=\"yes\"");
}
s->append("?>");
ok = (*writeFunc)(stream, s->getCString(), s->getLength());
delete s;
return ok;
}
//------------------------------------------------------------------------
ZxDocTypeDecl::ZxDocTypeDecl(GString *nameA) {
name = nameA;
}
ZxDocTypeDecl::~ZxDocTypeDecl() {
delete name;
}
bool ZxDocTypeDecl::write(ZxWriteFunc writeFunc, void *stream) {
GString *s;
bool ok;
s = new GString("<!DOCTYPE ");
s->append(name);
s->append(">");
ok = (*writeFunc)(stream, s->getCString(), s->getLength());
delete s;
return ok;
}
//------------------------------------------------------------------------
ZxComment::ZxComment(GString *textA) {
text = textA;
}
ZxComment::~ZxComment() {
delete text;
}
bool ZxComment::write(ZxWriteFunc writeFunc, void *stream) {
GString *s;
bool ok;
s = new GString("<!--");
s->append(text);
s->append("-->");
ok = (*writeFunc)(stream, s->getCString(), s->getLength());
delete s;
return ok;
}
//------------------------------------------------------------------------
ZxPI::ZxPI(GString *targetA, GString *textA) {
target = targetA;
text = textA;
}
ZxPI::~ZxPI() {
delete target;
delete text;
}
bool ZxPI::write(ZxWriteFunc writeFunc, void *stream) {
GString *s;
bool ok;
s = new GString("<?");
s->append(target);
s->append(" ");
s->append(text);
s->append("?>");
ok = (*writeFunc)(stream, s->getCString(), s->getLength());
delete s;
return ok;
}
//------------------------------------------------------------------------
ZxElement::ZxElement(GString *typeA) {
type = typeA;
attrs = new GHash();
firstAttr = lastAttr = NULL;
}
ZxElement::~ZxElement() {
delete type;
deleteGHash(attrs, ZxAttr);
}
bool ZxElement::isElement(const char *typeA) {
return !type->cmp(typeA);
}
ZxAttr *ZxElement::findAttr(const char *attrName) {
return (ZxAttr *)attrs->lookup(attrName);
}
void ZxElement::addAttr(ZxAttr *attr) {
attrs->add(attr->getName(), attr);
if (lastAttr) {
lastAttr->next = attr;
lastAttr= attr;
} else {
firstAttr = lastAttr = attr;
}
attr->parent = this;
attr->next = NULL;
}
bool ZxElement::write(ZxWriteFunc writeFunc, void *stream) {
GString *s;
ZxAttr *attr;
ZxNode *child;
bool ok;
s = new GString("<");
s->append(type);
for (attr = firstAttr; attr; attr = attr->getNextAttr()) {
s->append(" ");
s->append(attr->name);
s->append("=\"");
appendEscapedAttrValue(s, attr->value);
s->append("\"");
}
if ((child = getFirstChild())) {
s->append(">");
} else {
s->append("/>");
}
ok = (*writeFunc)(stream, s->getCString(), s->getLength());
delete s;
if (!ok) {
return false;
}
if (child) {
for (; child; child = child->getNextChild()) {
if (!child->write(writeFunc, stream)) {
return false;
}
}
s = new GString();
s->append("</");
s->append(type);
s->append(">");
ok = (*writeFunc)(stream, s->getCString(), s->getLength());
delete s;
if (!ok) {
return false;
}
}
return true;
}
void ZxElement::appendEscapedAttrValue(GString *out, GString *s) {
char c;
int i;
for (i = 0; i < s->getLength(); ++i) {
c = s->getChar(i);
if (c == '<') {
out->append("&lt;");
} else if (c == '>') {
out->append("&gt;");
} else if (c == '&') {
out->append("&amp;");
} else if (c == '"') {
out->append("&quot;");
} else {
out->append(c);
}
}
}
//------------------------------------------------------------------------
ZxAttr::ZxAttr(GString *nameA, GString *valueA) {
name = nameA;
value = valueA;
parent = NULL;
next = NULL;
}
ZxAttr::~ZxAttr() {
delete name;
delete value;
}
//------------------------------------------------------------------------
ZxCharData::ZxCharData(GString *dataA, bool parsedA) {
data = dataA;
parsed = parsedA;
}
ZxCharData::~ZxCharData() {
delete data;
}
bool ZxCharData::write(ZxWriteFunc writeFunc, void *stream) {
GString *s;
char c;
int i;
bool ok;
s = new GString();
if (parsed) {
for (i = 0; i < data->getLength(); ++i) {
c = data->getChar(i);
if (c == '<') {
s->append("&lt;");
} else if (c == '>') {
s->append("&gt;");
} else if (c == '&') {
s->append("&amp;");
} else {
s->append(c);
}
}
} else {
s->append("<![CDATA[");
s->append(data);
s->append("]]>");
}
ok = (*writeFunc)(stream, s->getCString(), s->getLength());
delete s;
return ok;
}