]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
9f95a23c | 2 | // vim: ts=8 sw=2 smarttab ft=cpp |
7c673cae FG |
3 | |
4 | #include <string.h> | |
5 | ||
6 | #include <iostream> | |
7 | #include <map> | |
8 | ||
9 | #include <expat.h> | |
10 | ||
11 | #include "include/types.h" | |
11fdf7f2 | 12 | #include "include/utime.h" |
7c673cae | 13 | |
7c673cae FG |
14 | #include "rgw_xml.h" |
15 | ||
7c673cae FG |
16 | XMLObjIter:: |
17 | XMLObjIter() | |
18 | { | |
19 | } | |
20 | ||
21 | XMLObjIter:: | |
22 | ~XMLObjIter() | |
23 | { | |
24 | } | |
25 | ||
26 | void XMLObjIter:: | |
27 | set(const XMLObjIter::map_iter_t &_cur, const XMLObjIter::map_iter_t &_end) | |
28 | { | |
29 | cur = _cur; | |
30 | end = _end; | |
31 | } | |
32 | ||
33 | XMLObj *XMLObjIter:: | |
34 | get_next() | |
35 | { | |
36 | XMLObj *obj = NULL; | |
37 | if (cur != end) { | |
38 | obj = cur->second; | |
39 | ++cur; | |
40 | } | |
41 | return obj; | |
42 | } | |
43 | ||
11fdf7f2 TL |
44 | bool XMLObjIter::get_name(std::string& name) const |
45 | { | |
46 | if (cur == end) { | |
47 | return false; | |
48 | } | |
49 | ||
50 | name = cur->first; | |
51 | return true; | |
52 | } | |
53 | ||
7c673cae FG |
54 | ostream& operator<<(ostream &out, const XMLObj &obj) { |
55 | out << obj.obj_type << ": " << obj.data; | |
56 | return out; | |
57 | } | |
58 | ||
59 | XMLObj:: | |
60 | ~XMLObj() | |
61 | { | |
62 | } | |
63 | ||
64 | bool XMLObj:: | |
65 | xml_start(XMLObj *parent, const char *el, const char **attr) | |
66 | { | |
67 | this->parent = parent; | |
68 | obj_type = el; | |
69 | for (int i = 0; attr[i]; i += 2) { | |
11fdf7f2 | 70 | attr_map[attr[i]] = std::string(attr[i + 1]); |
7c673cae FG |
71 | } |
72 | return true; | |
73 | } | |
74 | ||
75 | bool XMLObj:: | |
76 | xml_end(const char *el) | |
77 | { | |
78 | return true; | |
79 | } | |
80 | ||
81 | void XMLObj:: | |
82 | xml_handle_data(const char *s, int len) | |
83 | { | |
84 | data.append(s, len); | |
85 | } | |
86 | ||
11fdf7f2 TL |
87 | const std::string& XMLObj:: |
88 | XMLObj::get_data() const | |
7c673cae FG |
89 | { |
90 | return data; | |
91 | } | |
92 | ||
11fdf7f2 TL |
93 | const std::string& XMLObj:: |
94 | XMLObj::get_obj_type() const | |
95 | { | |
96 | return obj_type; | |
97 | } | |
98 | ||
7c673cae FG |
99 | XMLObj *XMLObj:: |
100 | XMLObj::get_parent() | |
101 | { | |
102 | return parent; | |
103 | } | |
104 | ||
105 | void XMLObj:: | |
11fdf7f2 | 106 | add_child(const std::string& el, XMLObj *obj) |
7c673cae | 107 | { |
11fdf7f2 | 108 | children.insert(std::pair<std::string, XMLObj *>(el, obj)); |
7c673cae FG |
109 | } |
110 | ||
111 | bool XMLObj:: | |
11fdf7f2 | 112 | get_attr(const std::string& name, std::string& attr) const |
7c673cae | 113 | { |
11fdf7f2 | 114 | const std::map<std::string, std::string>::const_iterator iter = attr_map.find(name); |
7c673cae FG |
115 | if (iter == attr_map.end()) |
116 | return false; | |
117 | attr = iter->second; | |
118 | return true; | |
119 | } | |
120 | ||
121 | XMLObjIter XMLObj:: | |
11fdf7f2 | 122 | find(const std::string& name) |
7c673cae FG |
123 | { |
124 | XMLObjIter iter; | |
11fdf7f2 TL |
125 | const XMLObjIter::const_map_iter_t first = children.find(name); |
126 | XMLObjIter::const_map_iter_t last; | |
7c673cae FG |
127 | if (first != children.end()) { |
128 | last = children.upper_bound(name); | |
129 | }else | |
130 | last = children.end(); | |
131 | iter.set(first, last); | |
132 | return iter; | |
133 | } | |
134 | ||
11fdf7f2 | 135 | XMLObjIter XMLObj::find_first() |
7c673cae FG |
136 | { |
137 | XMLObjIter iter; | |
11fdf7f2 TL |
138 | const XMLObjIter::const_map_iter_t first = children.begin(); |
139 | const XMLObjIter::const_map_iter_t last = children.end(); | |
140 | iter.set(first, last); | |
141 | return iter; | |
7c673cae | 142 | } |
7c673cae | 143 | |
11fdf7f2 TL |
144 | XMLObj *XMLObj:: |
145 | find_first(const std::string& name) | |
146 | { | |
147 | const XMLObjIter::const_map_iter_t first = children.find(name); | |
148 | if (first != children.end()) | |
149 | return first->second; | |
150 | return nullptr; | |
7c673cae FG |
151 | } |
152 | ||
153 | RGWXMLParser:: | |
11fdf7f2 | 154 | RGWXMLParser() : buf(nullptr), buf_len(0), cur_obj(nullptr), success(true), init_called(false) |
7c673cae | 155 | { |
11fdf7f2 | 156 | p = XML_ParserCreate(nullptr); |
7c673cae FG |
157 | } |
158 | ||
159 | RGWXMLParser:: | |
160 | ~RGWXMLParser() | |
161 | { | |
162 | XML_ParserFree(p); | |
163 | ||
164 | free(buf); | |
11fdf7f2 | 165 | std::list<XMLObj *>::const_iterator iter; |
7c673cae FG |
166 | for (iter = allocated_objs.begin(); iter != allocated_objs.end(); ++iter) { |
167 | XMLObj *obj = *iter; | |
168 | delete obj; | |
169 | } | |
170 | } | |
171 | ||
11fdf7f2 TL |
172 | void RGWXMLParser::call_xml_start(void* user_data, const char *el, const char **attr) { |
173 | RGWXMLParser *handler = static_cast<RGWXMLParser *>(user_data); | |
174 | XMLObj * obj = handler->alloc_obj(el); | |
7c673cae | 175 | if (!obj) { |
11fdf7f2 TL |
176 | handler->unallocated_objs.push_back(XMLObj()); |
177 | obj = &handler->unallocated_objs.back(); | |
7c673cae | 178 | } else { |
11fdf7f2 | 179 | handler->allocated_objs.push_back(obj); |
7c673cae | 180 | } |
11fdf7f2 TL |
181 | if (!obj->xml_start(handler->cur_obj, el, attr)) { |
182 | handler->success = false; | |
183 | return; | |
184 | } | |
185 | if (handler->cur_obj) { | |
186 | handler->cur_obj->add_child(el, obj); | |
7c673cae | 187 | } else { |
11fdf7f2 | 188 | handler->children.insert(std::pair<std::string, XMLObj *>(el, obj)); |
7c673cae | 189 | } |
11fdf7f2 | 190 | handler->cur_obj = obj; |
7c673cae | 191 | |
11fdf7f2 | 192 | handler->objs.push_back(obj); |
7c673cae FG |
193 | } |
194 | ||
11fdf7f2 TL |
195 | void RGWXMLParser::call_xml_end(void* user_data, const char *el) { |
196 | RGWXMLParser *handler = static_cast<RGWXMLParser *>(user_data); | |
197 | XMLObj *parent_obj = handler->cur_obj->get_parent(); | |
198 | if (!handler->cur_obj->xml_end(el)) { | |
199 | handler->success = false; | |
200 | return; | |
201 | } | |
202 | handler->cur_obj = parent_obj; | |
7c673cae FG |
203 | } |
204 | ||
11fdf7f2 | 205 | void RGWXMLParser::call_xml_handle_data(void* user_data, const char *s, int len) |
7c673cae | 206 | { |
11fdf7f2 TL |
207 | RGWXMLParser *handler = static_cast<RGWXMLParser *>(user_data); |
208 | handler->cur_obj->xml_handle_data(s, len); | |
7c673cae FG |
209 | } |
210 | ||
7c673cae FG |
211 | bool RGWXMLParser::init() |
212 | { | |
213 | if (!p) { | |
214 | return false; | |
215 | } | |
11fdf7f2 TL |
216 | init_called = true; |
217 | XML_SetElementHandler(p, RGWXMLParser::call_xml_start, RGWXMLParser::call_xml_end); | |
218 | XML_SetCharacterDataHandler(p, RGWXMLParser::call_xml_handle_data); | |
7c673cae FG |
219 | XML_SetUserData(p, (void *)this); |
220 | return true; | |
221 | } | |
222 | ||
223 | bool RGWXMLParser::parse(const char *_buf, int len, int done) | |
224 | { | |
11fdf7f2 | 225 | ceph_assert(init_called); |
7c673cae FG |
226 | int pos = buf_len; |
227 | char *tmp_buf; | |
228 | tmp_buf = (char *)realloc(buf, buf_len + len); | |
229 | if (tmp_buf == NULL){ | |
230 | free(buf); | |
231 | buf = NULL; | |
232 | return false; | |
233 | } else { | |
234 | buf = tmp_buf; | |
235 | } | |
236 | ||
237 | memcpy(&buf[buf_len], _buf, len); | |
238 | buf_len += len; | |
239 | ||
240 | success = true; | |
241 | if (!XML_Parse(p, &buf[pos], len, done)) { | |
242 | fprintf(stderr, "Parse error at line %d:\n%s\n", | |
243 | (int)XML_GetCurrentLineNumber(p), | |
244 | XML_ErrorString(XML_GetErrorCode(p))); | |
245 | success = false; | |
246 | } | |
247 | ||
248 | return success; | |
249 | } | |
250 | ||
251 | void decode_xml_obj(unsigned long& val, XMLObj *obj) | |
252 | { | |
11fdf7f2 | 253 | auto& s = obj->get_data(); |
7c673cae FG |
254 | const char *start = s.c_str(); |
255 | char *p; | |
256 | ||
257 | errno = 0; | |
258 | val = strtoul(start, &p, 10); | |
259 | ||
260 | /* Check for various possible errors */ | |
261 | ||
262 | if ((errno == ERANGE && val == ULONG_MAX) || | |
263 | (errno != 0 && val == 0)) { | |
264 | throw RGWXMLDecoder::err("failed to number"); | |
265 | } | |
266 | ||
267 | if (p == start) { | |
268 | throw RGWXMLDecoder::err("failed to parse number"); | |
269 | } | |
270 | ||
271 | while (*p != '\0') { | |
272 | if (!isspace(*p)) { | |
273 | throw RGWXMLDecoder::err("failed to parse number"); | |
274 | } | |
275 | p++; | |
276 | } | |
277 | } | |
278 | ||
279 | ||
280 | void decode_xml_obj(long& val, XMLObj *obj) | |
281 | { | |
11fdf7f2 | 282 | const std::string s = obj->get_data(); |
7c673cae FG |
283 | const char *start = s.c_str(); |
284 | char *p; | |
285 | ||
286 | errno = 0; | |
287 | val = strtol(start, &p, 10); | |
288 | ||
289 | /* Check for various possible errors */ | |
290 | ||
291 | if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || | |
292 | (errno != 0 && val == 0)) { | |
293 | throw RGWXMLDecoder::err("failed to parse number"); | |
294 | } | |
295 | ||
296 | if (p == start) { | |
297 | throw RGWXMLDecoder::err("failed to parse number"); | |
298 | } | |
299 | ||
300 | while (*p != '\0') { | |
301 | if (!isspace(*p)) { | |
302 | throw RGWXMLDecoder::err("failed to parse number"); | |
303 | } | |
304 | p++; | |
305 | } | |
306 | } | |
307 | ||
308 | void decode_xml_obj(long long& val, XMLObj *obj) | |
309 | { | |
11fdf7f2 | 310 | const std::string s = obj->get_data(); |
7c673cae FG |
311 | const char *start = s.c_str(); |
312 | char *p; | |
313 | ||
314 | errno = 0; | |
315 | val = strtoll(start, &p, 10); | |
316 | ||
317 | /* Check for various possible errors */ | |
318 | ||
319 | if ((errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) || | |
320 | (errno != 0 && val == 0)) { | |
321 | throw RGWXMLDecoder::err("failed to parse number"); | |
322 | } | |
323 | ||
324 | if (p == start) { | |
325 | throw RGWXMLDecoder::err("failed to parse number"); | |
326 | } | |
327 | ||
328 | while (*p != '\0') { | |
329 | if (!isspace(*p)) { | |
330 | throw RGWXMLDecoder::err("failed to parse number"); | |
331 | } | |
332 | p++; | |
333 | } | |
334 | } | |
335 | ||
336 | void decode_xml_obj(unsigned long long& val, XMLObj *obj) | |
337 | { | |
11fdf7f2 | 338 | const std::string s = obj->get_data(); |
7c673cae FG |
339 | const char *start = s.c_str(); |
340 | char *p; | |
341 | ||
342 | errno = 0; | |
343 | val = strtoull(start, &p, 10); | |
344 | ||
345 | /* Check for various possible errors */ | |
346 | ||
347 | if ((errno == ERANGE && val == ULLONG_MAX) || | |
348 | (errno != 0 && val == 0)) { | |
11fdf7f2 | 349 | throw RGWXMLDecoder::err("failed to parse number"); |
7c673cae FG |
350 | } |
351 | ||
352 | if (p == start) { | |
353 | throw RGWXMLDecoder::err("failed to parse number"); | |
354 | } | |
355 | ||
356 | while (*p != '\0') { | |
357 | if (!isspace(*p)) { | |
358 | throw RGWXMLDecoder::err("failed to parse number"); | |
359 | } | |
360 | p++; | |
361 | } | |
362 | } | |
363 | ||
364 | void decode_xml_obj(int& val, XMLObj *obj) | |
365 | { | |
366 | long l; | |
367 | decode_xml_obj(l, obj); | |
368 | #if LONG_MAX > INT_MAX | |
369 | if (l > INT_MAX || l < INT_MIN) { | |
370 | throw RGWXMLDecoder::err("integer out of range"); | |
371 | } | |
372 | #endif | |
373 | ||
374 | val = (int)l; | |
375 | } | |
376 | ||
377 | void decode_xml_obj(unsigned& val, XMLObj *obj) | |
378 | { | |
379 | unsigned long l; | |
380 | decode_xml_obj(l, obj); | |
381 | #if ULONG_MAX > UINT_MAX | |
382 | if (l > UINT_MAX) { | |
383 | throw RGWXMLDecoder::err("unsigned integer out of range"); | |
384 | } | |
385 | #endif | |
386 | ||
387 | val = (unsigned)l; | |
388 | } | |
389 | ||
390 | void decode_xml_obj(bool& val, XMLObj *obj) | |
391 | { | |
11fdf7f2 TL |
392 | const std::string s = obj->get_data(); |
393 | if (strncasecmp(s.c_str(), "true", 8) == 0) { | |
7c673cae FG |
394 | val = true; |
395 | return; | |
396 | } | |
11fdf7f2 | 397 | if (strncasecmp(s.c_str(), "false", 8) == 0) { |
7c673cae FG |
398 | val = false; |
399 | return; | |
400 | } | |
401 | int i; | |
402 | decode_xml_obj(i, obj); | |
403 | val = (bool)i; | |
404 | } | |
405 | ||
406 | void decode_xml_obj(bufferlist& val, XMLObj *obj) | |
407 | { | |
11fdf7f2 | 408 | const std::string s = obj->get_data(); |
7c673cae FG |
409 | |
410 | bufferlist bl; | |
411 | bl.append(s.c_str(), s.size()); | |
412 | try { | |
413 | val.decode_base64(bl); | |
414 | } catch (buffer::error& err) { | |
415 | throw RGWXMLDecoder::err("failed to decode base64"); | |
416 | } | |
417 | } | |
418 | ||
419 | void decode_xml_obj(utime_t& val, XMLObj *obj) | |
420 | { | |
11fdf7f2 | 421 | const std::string s = obj->get_data(); |
7c673cae FG |
422 | uint64_t epoch; |
423 | uint64_t nsec; | |
424 | int r = utime_t::parse_date(s, &epoch, &nsec); | |
425 | if (r == 0) { | |
426 | val = utime_t(epoch, nsec); | |
427 | } else { | |
428 | throw RGWXMLDecoder::err("failed to decode utime_t"); | |
429 | } | |
430 | } | |
431 | ||
432 | void encode_xml(const char *name, const string& val, Formatter *f) | |
433 | { | |
434 | f->dump_string(name, val); | |
435 | } | |
436 | ||
437 | void encode_xml(const char *name, const char *val, Formatter *f) | |
438 | { | |
439 | f->dump_string(name, val); | |
440 | } | |
441 | ||
442 | void encode_xml(const char *name, bool val, Formatter *f) | |
443 | { | |
11fdf7f2 | 444 | std::string s; |
7c673cae FG |
445 | if (val) |
446 | s = "True"; | |
447 | else | |
448 | s = "False"; | |
449 | ||
450 | f->dump_string(name, s); | |
451 | } | |
452 | ||
453 | void encode_xml(const char *name, int val, Formatter *f) | |
454 | { | |
455 | f->dump_int(name, val); | |
456 | } | |
457 | ||
458 | void encode_xml(const char *name, long val, Formatter *f) | |
459 | { | |
460 | f->dump_int(name, val); | |
461 | } | |
462 | ||
463 | void encode_xml(const char *name, unsigned val, Formatter *f) | |
464 | { | |
465 | f->dump_unsigned(name, val); | |
466 | } | |
467 | ||
468 | void encode_xml(const char *name, unsigned long val, Formatter *f) | |
469 | { | |
470 | f->dump_unsigned(name, val); | |
471 | } | |
472 | ||
473 | void encode_xml(const char *name, unsigned long long val, Formatter *f) | |
474 | { | |
475 | f->dump_unsigned(name, val); | |
476 | } | |
477 | ||
478 | void encode_xml(const char *name, long long val, Formatter *f) | |
479 | { | |
480 | f->dump_int(name, val); | |
481 | } | |
482 | ||
483 | void encode_xml(const char *name, const utime_t& val, Formatter *f) | |
484 | { | |
485 | val.gmtime(f->dump_stream(name)); | |
486 | } | |
487 | ||
488 | void encode_xml(const char *name, const bufferlist& bl, Formatter *f) | |
489 | { | |
490 | /* need to copy data from bl, as it is const bufferlist */ | |
491 | bufferlist src = bl; | |
492 | ||
493 | bufferlist b64; | |
494 | src.encode_base64(b64); | |
495 | ||
11fdf7f2 | 496 | const std::string s(b64.c_str(), b64.length()); |
7c673cae FG |
497 | |
498 | encode_xml(name, s, f); | |
499 | } | |
500 |