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 { '"', """ },
141 { '\'', "'" },
142 { '>', ">" },
143 { '<', "<" }
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, "&");
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