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 "string2int.h"
14 
16 {
17  data.clear();
18  name.clear();
19  attributes.clear();
20  elements.clear();
21 }
22 
24 {
25  xml.data.swap(data);
27  xml.elements.swap(elements);
28  xml.name.swap(name);
29 }
30 
31 void xmlt::output(std::ostream &out, unsigned indent) const
32 {
33  // 'name' needs to be set, or we produce mal-formed
34  // XML.
35 
36  if(name=="")
37  return;
38 
39  do_indent(out, indent);
40 
41  out << '<' << name;
42 
43  for(const auto &attribute : attributes)
44  {
45  // it.first needs to be non-empty
46  if(attribute.first.empty())
47  continue;
48  out << ' ' << attribute.first
49  << '=' << '"';
50  escape_attribute(attribute.second, out);
51  out << '"';
52  }
53 
54  if(elements.empty() && data.empty())
55  {
56  out << "/>" << "\n";
57  return;
58  }
59 
60  out << '>';
61 
62  if(elements.empty())
63  escape(data, out);
64  else
65  {
66  out << "\n";
67 
68  for(const auto &element : elements)
69  element.output(out, indent+2);
70 
71  do_indent(out, indent);
72  }
73 
74  out << '<' << '/' << name << '>' << "\n";
75 }
76 
78 void xmlt::escape(const std::string &s, std::ostream &out)
79 {
80  for(const auto ch : s)
81  {
82  switch(ch)
83  {
84  case '&':
85  out << "&amp;";
86  break;
87 
88  case '<':
89  out << "&lt;";
90  break;
91 
92  case '>':
93  out << "&gt;";
94  break;
95 
96  case '\r':
97  break; // drop!
98 
99  case '\n':
100  out << '\n';
101  break;
102 
103  default:
104  // &#0; isn't allowed, but what shall we do?
105  if((ch>=0 && ch<' ') || ch==127)
106  out << "&#"+std::to_string((unsigned char)ch)+";";
107  else
108  out << ch;
109  }
110  }
111 }
112 
115 void xmlt::escape_attribute(const std::string &s, std::ostream &out)
116 {
117  for(const auto ch : s)
118  {
119  switch(ch)
120  {
121  case '&':
122  out << "&amp;";
123  break;
124 
125  case '<':
126  out << "&lt;";
127  break;
128 
129  case '>':
130  out << "&gt;";
131  break;
132 
133  case '"':
134  out << "&quot;";
135  break;
136 
137  default:
138  // &#0; isn't allowed, but what shall we do?
139  if((ch>=0 && ch<' ') || ch==127)
140  out << "&#"+std::to_string((unsigned char)ch)+";";
141  else
142  out << ch;
143  }
144  }
145 }
146 
147 void xmlt::do_indent(std::ostream &out, unsigned indent)
148 {
149  out << std::string(indent, ' ');
150 }
151 
152 xmlt::elementst::const_iterator xmlt::find(const std::string &name) const
153 {
154  for(elementst::const_iterator it=elements.begin();
155  it!=elements.end();
156  it++)
157  if(it->name==name)
158  return it;
159 
160  return elements.end();
161 }
162 
163 xmlt::elementst::iterator xmlt::find(const std::string &name)
164 {
165  for(elementst::iterator it=elements.begin();
166  it!=elements.end();
167  it++)
168  if(it->name==name)
169  return it;
170 
171  return elements.end();
172 }
173 
175  const std::string &attribute,
176  unsigned value)
177 {
178  set_attribute(attribute, std::to_string(value));
179 }
180 
182  const std::string &attribute,
183  unsigned long value)
184 {
185  set_attribute(attribute, std::to_string(value));
186 }
187 
189  const std::string &attribute,
190  unsigned long long value)
191 {
192  set_attribute(attribute, std::to_string(value));
193 }
194 
196  const std::string &attribute,
197  const std::string &value)
198 {
199  if((value[0]=='\"' && value[value.size()-1]=='\"') ||
200  (value[0]=='\'' && value[value.size()-1]=='\''))
201  {
202  attributes[attribute]=value.substr(1, value.size()-2);
203  }
204  else
205  {
206  attributes[attribute]=value;
207  }
208 }
209 
213 std::string xmlt::unescape(const std::string &str)
214 {
215  std::string result("");
216 
217  result.reserve(str.size());
218 
219  for(std::string::const_iterator it=str.begin();
220  it!=str.end();
221  it++)
222  {
223  if(*it=='&')
224  {
225  std::string tmp;
226  it++;
227 
228  while(it!=str.end() && *it!=';')
229  tmp+=*it++;
230 
231  if(tmp=="gt")
232  result+='>';
233  else if(tmp=="lt")
234  result+='<';
235  else if(tmp=="amp")
236  result+='&';
237  else if(tmp[0]=='#' && tmp[1]!='x')
238  {
239  char c=unsafe_string2int(tmp.substr(1, tmp.size()-1));
240  result+=c;
241  }
242  else
243  throw "XML escape code not implemented"; // NOLINT(readability/throw)
244  }
245  else
246  result+=*it;
247  }
248 
249  return result;
250 }
static int8_t r
Definition: irep_hash.h:59
attributest attributes
Definition: xml.h:32
elementst::const_iterator find(const std::string &name) const
Definition: xml.cpp:152
std::string name
Definition: xml.h:30
xmlt xml(const source_locationt &location)
Definition: xml_expr.cpp:25
void clear()
Definition: xml.cpp:15
elementst elements
Definition: xml.h:33
void swap(xmlt &xml)
Definition: xml.cpp:23
void set_attribute(const std::string &attribute, unsigned value)
Definition: xml.cpp:174
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:213
static void do_indent(std::ostream &out, unsigned indent)
Definition: xml.cpp:147
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:115
int unsafe_string2int(const std::string &str, int base)
Definition: string2int.cpp:61
Definition: kdev_t.h:24
void output(std::ostream &out, unsigned indent=0) const
Definition: xml.cpp:31