cprover
xml.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: 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();
21  attributes.clear();
22  elements.clear();
23 }
24 
26 {
27  xml.data.swap(data);
29  xml.elements.swap(elements);
30  xml.name.swap(name);
31 }
32 
33 void 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 
79 void 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  default:
105  // &#0; isn't allowed, but what shall we do?
106  if((ch>=0 && ch<' ') || ch==127)
107  out << "&#"+std::to_string((unsigned char)ch)+";";
108  else
109  out << ch;
110  }
111  }
112 }
113 
116 void xmlt::escape_attribute(const std::string &s, std::ostream &out)
117 {
118  for(const auto ch : s)
119  {
120  switch(ch)
121  {
122  case '&':
123  out << "&amp;";
124  break;
125 
126  case '<':
127  out << "&lt;";
128  break;
129 
130  case '>':
131  out << "&gt;";
132  break;
133 
134  case '"':
135  out << "&quot;";
136  break;
137 
138  default:
139  // &#0; isn't allowed, but what shall we do?
140  if((ch>=0 && ch<' ') || ch==127)
141  out << "&#"+std::to_string((unsigned char)ch)+";";
142  else
143  out << ch;
144  }
145  }
146 }
147 
148 void xmlt::do_indent(std::ostream &out, unsigned indent)
149 {
150  out << std::string(indent, ' ');
151 }
152 
153 xmlt::elementst::const_iterator xmlt::find(const std::string &key) const
154 {
155  for(elementst::const_iterator it=elements.begin();
156  it!=elements.end();
157  it++)
158  if(it->name == key)
159  return it;
160 
161  return elements.end();
162 }
163 
164 xmlt::elementst::iterator xmlt::find(const std::string &key)
165 {
166  for(elementst::iterator it=elements.begin();
167  it!=elements.end();
168  it++)
169  if(it->name == key)
170  return it;
171 
172  return elements.end();
173 }
174 
176  const std::string &attribute,
177  unsigned value)
178 {
179  set_attribute(attribute, std::to_string(value));
180 }
181 
183  const std::string &attribute,
184  unsigned long value)
185 {
186  set_attribute(attribute, std::to_string(value));
187 }
188 
190  const std::string &attribute,
191  unsigned long long value)
192 {
193  set_attribute(attribute, std::to_string(value));
194 }
195 
197  const std::string &attribute,
198  const std::string &value)
199 {
200  if((value[0]=='\"' && value[value.size()-1]=='\"') ||
201  (value[0]=='\'' && value[value.size()-1]=='\''))
202  {
203  attributes[attribute]=value.substr(1, value.size()-2);
204  }
205  else
206  {
207  attributes[attribute]=value;
208  }
209 }
210 
214 std::string xmlt::unescape(const std::string &str)
215 {
216  std::string result;
217 
218  result.reserve(str.size());
219 
220  for(std::string::const_iterator it=str.begin();
221  it!=str.end();
222  it++)
223  {
224  if(*it=='&')
225  {
226  std::string tmp;
227  it++;
228 
229  while(it!=str.end() && *it!=';')
230  tmp+=*it++;
231 
232  if(tmp=="gt")
233  result+='>';
234  else if(tmp=="lt")
235  result+='<';
236  else if(tmp=="amp")
237  result+='&';
238  else if(tmp[0]=='#' && tmp[1]!='x')
239  {
240  char c=unsafe_string2int(tmp.substr(1, tmp.size()-1));
241  result+=c;
242  }
243  else
244  throw deserialization_exceptiont("unknown XML escape code: " + tmp);
245  }
246  else
247  result+=*it;
248  }
249 
250  return result;
251 }
252 bool operator==(const xmlt &a, const xmlt &b)
253 {
254  return a.name == b.name && a.data == b.data && a.elements == b.elements &&
255  a.attributes == b.attributes;
256 }
257 bool operator!=(const xmlt &a, const xmlt &b)
258 {
259  return !(a == b);
260 }
261 
262 xmlt xml_node(const std::pair<labelt, structured_data_entryt> &entry)
263 {
264  const labelt &label = entry.first;
265  const structured_data_entryt &data = entry.second;
266  xmlt output_data{label.kebab_case()};
267  if(data.is_leaf())
268  {
269  output_data.data = data.leaf_data();
270  }
271  else
272  {
273  const auto &children = data.children();
274  output_data.elements =
275  make_range(children).map(xml_node).collect<std::list<xmlt>>();
276  }
277  return output_data;
278 }
279 
281 {
282  if(data.data().size() == 0)
283  return xmlt{};
284  if(data.data().size() == 1)
285  {
286  return xml_node(*data.data().begin());
287  }
288  else
289  {
290  xmlt root{"root"};
291  root.elements =
292  make_range(data.data()).map(xml_node).collect<std::list<xmlt>>();
293  return root;
294  }
295 }
exception_utils.h
xmlt::elements
elementst elements
Definition: xml.h:42
structured_data_entryt
Definition: structured_data.h:33
deserialization_exceptiont
Thrown when failing to deserialize a value from some low level format, like JSON or raw bytes.
Definition: exception_utils.h:73
data
Definition: kdev_t.h:24
to_string
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
Definition: string_constraint.cpp:55
to_xml
xmlt to_xml(const structured_datat &data)
Convert the structured_datat into an xml object.
Definition: xml.cpp:280
xml.h
xml_node
xmlt xml_node(const std::pair< labelt, structured_data_entryt > &entry)
Definition: xml.cpp:262
xmlt::output
void output(std::ostream &out, unsigned indent=0) const
Definition: xml.cpp:33
string2int.h
operator==
bool operator==(const xmlt &a, const xmlt &b)
Definition: xml.cpp:252
xml
xmlt xml(const irep_idt &property_id, const property_infot &property_info)
Definition: properties.cpp:105
xmlt::name
std::string name
Definition: xml.h:39
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:464
data::size
int size
Definition: kdev_t.h:25
labelt
Definition: structured_data.h:17
xmlt::do_indent
static void do_indent(std::ostream &out, unsigned indent)
Definition: xml.cpp:148
xmlt::escape_attribute
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:116
xmlt::clear
void clear()
Definition: xml.cpp:17
xmlt
Definition: xml.h:21
structured_datat
A way of representing nested key/value data.
Definition: structured_data.h:74
xmlt::find
elementst::const_iterator find(const std::string &key) const
Definition: xml.cpp:153
xmlt::set_attribute
void set_attribute(const std::string &attribute, unsigned value)
Definition: xml.cpp:175
operator!=
bool operator!=(const xmlt &a, const xmlt &b)
Definition: xml.cpp:257
labelt::kebab_case
std::string kebab_case() const
Definition: structured_data.cpp:40
xmlt::swap
void swap(xmlt &xml)
Definition: xml.cpp:25
xmlt::attributes
attributest attributes
Definition: xml.h:41
structured_data.h
r
static int8_t r
Definition: irep_hash.h:59
xmlt::data
std::string data
Definition: xml.h:39
xmlt::unescape
static std::string unescape(const std::string &s)
takes a string and unescapes any xml style escaped symbols
Definition: xml.cpp:214
make_range
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition: range.h:524
unsafe_string2int
int unsafe_string2int(const std::string &str, int base)
Definition: string2int.cpp:33