1 /***************************************************************************
2                           xml.cpp  -  description
3                              -------------------
4     begin                : Fri Aug 9 2002
5     copyright            : (C) 2002 by ARRL
6     author               : Jon Bloom
7     email                : jbloom@arrl.org
8     revision             : $Id$
9  ***************************************************************************/
10 
11 #define TQSLLIB_DEF
12 
13 #include "xml.h"
14 #ifdef _WIN32
15 #include "tqsllib.h"
16 #include <fcntl.h>
17 #endif
18 #include <string.h>
19 #include <zlib.h>
20 #include <stack>
21 #include <fstream>
22 #include <utility>
23 #include <string>
24 
25 using std::pair;
26 using std::string;
27 using std::ostream;
28 using std::map;
29 
30 namespace tqsllib {
31 
32 pair<string, bool>
getAttribute(const string & key)33 XMLElement::getAttribute(const string& key) {
34 	string s;
35 	XMLElementAttributeList::iterator pos;
36 	pos = _attributes.find(key);
37 	pair<string, bool> rval;
38 	if (pos == _attributes.end()) {
39 		rval.second = false;
40 	} else {
41 		rval.first = pos->second;
42 		rval.second = true;
43 	}
44 	return rval;
45 }
46 
47 void
xml_start(void * data,const XML_Char * name,const XML_Char ** atts)48 XMLElement::xml_start(void *data, const XML_Char *name, const XML_Char **atts) {
49 	XMLElement *el = reinterpret_cast<XMLElement *>(data);
50 	XMLElement *new_el = new XMLElement(name);
51 //cout << "Element: " << name << endl;
52 	for (int i = 0; atts[i]; i += 2) {
53 		new_el->setAttribute(atts[i], atts[i+1]);
54 	}
55 	if (el->_parsingStack.empty()) {
56 		el->_parsingStack.push_back(el->addElement(new_el));
57 	} else {
58 		new_el->setPretext(el->_parsingStack.back()->second->getText());
59 		el->_parsingStack.back()->second->setText("");
60 		el->_parsingStack.push_back(el->_parsingStack.back()->second->addElement(new_el));
61 	}
62 }
63 
64 void
xml_end(void * data,const XML_Char * name)65 XMLElement::xml_end(void *data, const XML_Char *name) {
66 	XMLElement *el = reinterpret_cast<XMLElement *>(data);
67 	if (!(el->_parsingStack.empty()))
68 		el->_parsingStack.pop_back();
69 }
70 
71 void
xml_text(void * data,const XML_Char * text,int len)72 XMLElement::xml_text(void *data, const XML_Char *text, int len) {
73 	XMLElement *el = reinterpret_cast<XMLElement *>(data);
74 	el->_parsingStack.back()->second->_text.append(text, len);
75 }
76 
77 int
parseString(const char * xmlstring)78 XMLElement::parseString(const char *xmlstring) {
79 	XML_Parser xp = XML_ParserCreate(0);
80 	XML_SetUserData(xp, reinterpret_cast<void *>(this));
81 	XML_SetStartElementHandler(xp, &XMLElement::xml_start);
82 	XML_SetEndElementHandler(xp, &XMLElement::xml_end);
83 	XML_SetCharacterDataHandler(xp, &XMLElement::xml_text);
84 
85 	_parsingStack.clear();
86 	// Process the XML
87 	if (XML_Parse(xp, xmlstring, strlen(xmlstring), 1) == 0) {
88 		XML_ParserFree(xp);
89 		return XML_PARSE_SYNTAX_ERROR;
90 	}
91 	XML_ParserFree(xp);
92 	return XML_PARSE_NO_ERROR;
93 }
94 
95 int
parseFile(const char * filename)96 XMLElement::parseFile(const char *filename) {
97 	gzFile in = NULL;
98 #ifdef _WIN32
99 	wchar_t* fn = utf8_to_wchar(filename);
100 	int fd = _wopen(fn, _O_RDONLY|_O_BINARY);
101 	free_wchar(fn);
102 	if (fd != -1)
103 		in = gzdopen(fd, "rb");
104 #else
105 	in = gzopen(filename, "rb");
106 #endif
107 
108 	if (!in)
109 		return XML_PARSE_SYSTEM_ERROR;	// Failed to open file
110 	char buf[256];
111 	XML_Parser xp = XML_ParserCreate(0);
112 	XML_SetUserData(xp, reinterpret_cast<void *>(this));
113 	XML_SetStartElementHandler(xp, &XMLElement::xml_start);
114 	XML_SetEndElementHandler(xp, &XMLElement::xml_end);
115 	XML_SetCharacterDataHandler(xp, &XMLElement::xml_text);
116 
117 	_parsingStack.clear();
118 	int rcount;
119 	while ((rcount = gzread(in, buf, sizeof buf)) > 0) {
120 		// Process the XML
121 		if (XML_Parse(xp, buf, rcount, 0) == 0) {
122 			gzclose(in);
123 			XML_ParserFree(xp);
124 			return XML_PARSE_SYNTAX_ERROR;
125 		}
126 	}
127 	gzclose(in);
128 	bool rval = (rcount == 0);
129 	if (rval)
130 		rval = (XML_Parse(xp, "", 0, 1) != 0);
131 	XML_ParserFree(xp);
132 	return (rval ? XML_PARSE_NO_ERROR : XML_PARSE_SYNTAX_ERROR);
133 }
134 
135 
136 static struct {
137 	char c;
138 	const char *ent;
139 } xml_entity_table[] = {
140 	{ '"', "&quot;" },
141 	{ '\'', "&apos;" },
142 	{ '>', "&gt;" },
143 	{ '<', "&lt;" }
144 };
145 
146 static string
xml_entities(const string & s)147 xml_entities(const string& s) {
148 	string ns = s;
149 	string::size_type idx = 0;
150 	while ((idx = ns.find('&', idx)) != string::npos) {
151 		ns.replace(idx, 1, "&amp;");
152 		idx++;
153 	}
154 	for (int i = 0; i < static_cast<int>((sizeof xml_entity_table / sizeof xml_entity_table[0])); i++) {
155 		while ((idx = ns.find(xml_entity_table[i].c)) != string::npos)
156 			ns.replace(idx, 1, xml_entity_table[i].ent);
157 	}
158 	return ns;
159 }
160 
161 /* Stream out an XMLElement as XML text */
162 ostream&
operator <<(ostream & stream,XMLElement & el)163 operator<< (ostream& stream, XMLElement& el) {
164 	bool ok;
165 	XMLElement subel;
166 	if (el.getElementName() != "") {
167 		stream << "<" << el.getElementName();
168 		string key, val;
169 		bool ok = el.getFirstAttribute(key, val);
170 		while (ok) {
171 			stream << " " << key << "=\"" << xml_entities(val) << "\"";
172 			ok = el.getNextAttribute(key, val);
173 		}
174 		if (el.getText() == "" && !el.getFirstElement(subel)) {
175 			stream << " />";
176 			return stream;
177 		} else {
178 			stream << ">";
179 		}
180 	}
181 	ok = el.getFirstElement(subel);
182 	while (ok) {
183 		string s = subel.getPretext();
184 		if (s != "")
185 			stream << xml_entities(s);
186 		stream << subel;
187 		ok = el.getNextElement(subel);
188 	}
189 	if (el.getText() != "")
190 		stream << xml_entities(el.getText());
191 	if (el.getElementName() != "")
192 		stream << "</" << el.getElementName() << ">";
193 	return stream;
194 }
195 
196 }	// namespace tqsllib
197