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 
17 {
18  data.clear();
19  name.clear();
20  attributes.clear();
21  elements.clear();
22 }
23 
25 {
26  xml.data.swap(data);
28  xml.elements.swap(elements);
29  xml.name.swap(name);
30 }
31 
32 void xmlt::output(std::ostream &out, unsigned indent) const
33 {
34  // 'name' needs to be set, or we produce mal-formed
35  // XML.
36 
37  if(name=="")
38  return;
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 }
Thrown when failing to deserialize a value from some low level format, like JSON or raw bytes...
static int8_t r
Definition: irep_hash.h:59
attributest attributes
Definition: xml.h:32
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
std::string name
Definition: xml.h:30
xmlt xml(const source_locationt &location)
Definition: xml_expr.cpp:26
void clear()
Definition: xml.cpp:16
elementst elements
Definition: xml.h:33
void swap(xmlt &xml)
Definition: xml.cpp:24
elementst::const_iterator find(const std::string &key) const
Definition: xml.cpp:153
void set_attribute(const std::string &attribute, unsigned value)
Definition: xml.cpp:175
Definition: xml.h:18
std::string data
Definition: xml.h:30
static std::string unescape(const std::string &s)
takes a string and unescapes any xml style escaped symbols
Definition: xml.cpp:214
static void do_indent(std::ostream &out, unsigned indent)
Definition: xml.cpp:148
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
int unsafe_string2int(const std::string &str, int base)
Definition: string2int.cpp:64
Definition: kdev_t.h:24
void output(std::ostream &out, unsigned indent=0) const
Definition: xml.cpp:32