CBMC
Loading...
Searching...
No Matches
xml.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
9#include "xml.h"
10
11#include <ostream>
12
13#include "exception_utils.h"
14#include "string2int.h"
15#include "structured_data.h"
16
18{
19 data.clear();
20 name.clear();
23}
24
26{
27 xml.data.swap(data);
29 xml.elements.swap(elements);
30 xml.name.swap(name);
31}
32
33void xmlt::output(std::ostream &out, unsigned indent) const
34{
35 // 'name' needs to be set, or we produce mal-formed
36 // XML.
37
38 PRECONDITION(!name.empty());
39
40 do_indent(out, indent);
41
42 out << '<' << name;
43
44 for(const auto &attribute : attributes)
45 {
46 // it.first needs to be non-empty
47 if(attribute.first.empty())
48 continue;
49 out << ' ' << attribute.first
50 << '=' << '"';
51 escape_attribute(attribute.second, out);
52 out << '"';
53 }
54
55 if(elements.empty() && data.empty())
56 {
57 out << "/>" << "\n";
58 return;
59 }
60
61 out << '>';
62
63 if(elements.empty())
64 escape(data, out);
65 else
66 {
67 out << "\n";
68
69 for(const auto &element : elements)
70 element.output(out, indent+2);
71
72 do_indent(out, indent);
73 }
74
75 out << '<' << '/' << name << '>' << "\n";
76}
77
79void xmlt::escape(const std::string &s, std::ostream &out)
80{
81 for(const auto ch : s)
82 {
83 switch(ch)
84 {
85 case '&':
86 out << "&amp;";
87 break;
88
89 case '<':
90 out << "&lt;";
91 break;
92
93 case '>':
94 out << "&gt;";
95 break;
96
97 case '\r':
98 break; // drop!
99
100 case '\n':
101 out << '\n';
102 break;
103
104 case 0x9: // TAB
105 case 0x7F: // DEL
106 out << "&#" << std::to_string((unsigned char)ch) << ';';
107 break;
108
109 default:
111 static_cast<unsigned char>(ch) >= 32u,
112 "XML does not support escaping non-printable character " +
113 std::to_string((unsigned char)ch));
114 out << ch;
115 }
116 }
117}
118
121void xmlt::escape_attribute(const std::string &s, std::ostream &out)
122{
123 for(const auto ch : s)
124 {
125 switch(ch)
126 {
127 case '&':
128 out << "&amp;";
129 break;
130
131 case '<':
132 out << "&lt;";
133 break;
134
135 case '>':
136 out << "&gt;";
137 break;
138
139 case '"':
140 out << "&quot;";
141 break;
142
143 case 0x9: // TAB
144 case 0xA: // LF
145 case 0xD: // CR
146 case 0x7F: // DEL
147 out << "&#" << std::to_string((unsigned char)ch) << ';';
148 break;
149
150 default:
152 static_cast<unsigned char>(ch) >= 32u,
153 "XML does not support escaping non-printable character " +
154 std::to_string((unsigned char)ch));
155 out << ch;
156 }
157 }
158}
159
160bool xmlt::is_printable_xml(const std::string &s)
161{
162 for(const auto ch : s)
163 {
164 if(ch < 0x20 && ch != 0x9 && ch != 0xA && ch != 0xD)
165 return false;
166 }
167
168 return true;
169}
170
171void xmlt::do_indent(std::ostream &out, unsigned indent)
172{
173 out << std::string(indent, ' ');
174}
175
176xmlt::elementst::const_iterator xmlt::find(const std::string &key) const
177{
178 for(elementst::const_iterator it=elements.begin();
179 it!=elements.end();
180 it++)
181 if(it->name == key)
182 return it;
183
184 return elements.end();
185}
186
187xmlt::elementst::iterator xmlt::find(const std::string &key)
188{
189 for(elementst::iterator it=elements.begin();
190 it!=elements.end();
191 it++)
192 if(it->name == key)
193 return it;
194
195 return elements.end();
196}
197
199 const std::string &attribute,
200 unsigned value)
201{
202 set_attribute(attribute, std::to_string(value));
203}
204
206 const std::string &attribute,
207 unsigned long value)
208{
209 set_attribute(attribute, std::to_string(value));
210}
211
213 const std::string &attribute,
214 unsigned long long value)
215{
216 set_attribute(attribute, std::to_string(value));
217}
218
220 const std::string &attribute,
221 const std::string &value)
222{
223 if((value[0]=='\"' && value[value.size()-1]=='\"') ||
224 (value[0]=='\'' && value[value.size()-1]=='\''))
225 {
226 attributes[attribute]=value.substr(1, value.size()-2);
227 }
228 else
229 {
230 attributes[attribute]=value;
231 }
232}
233
237std::string xmlt::unescape(const std::string &str)
238{
239 std::string result;
240
241 result.reserve(str.size());
242
243 for(std::string::const_iterator it=str.begin();
244 it!=str.end();
245 it++)
246 {
247 if(*it=='&')
248 {
249 std::string tmp;
250 it++;
251
252 while(it!=str.end() && *it!=';')
253 tmp+=*it++;
254
255 if(tmp=="gt")
256 result+='>';
257 else if(tmp=="lt")
258 result+='<';
259 else if(tmp=="amp")
260 result+='&';
261 else if(tmp[0]=='#' && tmp[1]!='x')
262 {
263 char c=unsafe_string2int(tmp.substr(1, tmp.size()-1));
264 result+=c;
265 }
266 else
267 throw deserialization_exceptiont("unknown XML escape code: " + tmp);
268 }
269 else
270 result+=*it;
271 }
272
273 return result;
274}
275bool operator==(const xmlt &a, const xmlt &b)
276{
277 return a.name == b.name && a.data == b.data && a.elements == b.elements &&
278 a.attributes == b.attributes;
279}
280bool operator!=(const xmlt &a, const xmlt &b)
281{
282 return !(a == b);
283}
284
285xmlt xml_node(const std::pair<labelt, structured_data_entryt> &entry)
286{
287 const labelt &label = entry.first;
288 const structured_data_entryt &data = entry.second;
289 xmlt output_data{label.kebab_case()};
290 if(data.is_leaf())
291 {
292 output_data.data = data.leaf_data();
293 }
294 else
295 {
296 const auto &children = data.children();
297 output_data.elements =
298 make_range(children).map(xml_node).collect<std::list<xmlt>>();
299 }
300 return output_data;
301}
302
304{
305 if(data.data().size() == 0)
306 return xmlt{};
307 if(data.data().size() == 1)
308 {
309 return xml_node(*data.data().begin());
310 }
311 else
312 {
313 xmlt root{"root"};
314 root.elements =
315 make_range(data.data()).map(xml_node).collect<std::list<xmlt>>();
316 return root;
317 }
318}
virtual void clear()
Reset the abstract state.
Definition ai.h:265
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Thrown when failing to deserialize a value from some low level format, like JSON or raw bytes.
A way of representing nested key/value data.
const std::map< labelt, structured_data_entryt > & data() const
Definition xml.h:21
static std::string unescape(const std::string &s)
takes a string and unescapes any xml style escaped symbols
Definition xml.cpp:237
void set_attribute(const std::string &attribute, unsigned value)
Definition xml.cpp:198
void swap(xmlt &xml)
Definition xml.cpp:25
attributest attributes
Definition xml.h:41
void clear()
Definition xml.cpp:17
elementst elements
Definition xml.h:42
std::string data
Definition xml.h:39
static bool is_printable_xml(const std::string &s)
Determine whether s does not contain any characters that cannot be escaped in XML 1....
Definition xml.cpp:160
elementst::const_iterator find(const std::string &key) const
Definition xml.cpp:176
void output(std::ostream &out, unsigned indent=0) const
Definition xml.cpp:33
static void escape(const std::string &s, std::ostream &out)
escaping for XML elements
Definition xml.cpp:79
static void escape_attribute(const std::string &s, std::ostream &out)
escaping for XML attributes, assuming that double quotes " are used consistently, not single quotes
Definition xml.cpp:121
std::string name
Definition xml.h:39
static void do_indent(std::ostream &out, unsigned indent)
Definition xml.cpp:171
xmlt xml(const irep_idt &property_id, const property_infot &property_info)
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition range.h:522
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition invariant.h:534
#define PRECONDITION(CONDITION)
Definition invariant.h:463
int unsafe_string2int(const std::string &str, int base)
std::string kebab_case() const
std::string leaf_data() const
const std::map< labelt, structured_data_entryt > & children() const
xmlt to_xml(const structured_datat &data)
Convert the structured_datat into an xml object.
Definition xml.cpp:303
bool operator==(const xmlt &a, const xmlt &b)
Definition xml.cpp:275
bool operator!=(const xmlt &a, const xmlt &b)
Definition xml.cpp:280
xmlt xml_node(const std::pair< labelt, structured_data_entryt > &entry)
Definition xml.cpp:285