Permalink
Cannot retrieve contributors at this time
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- | |
// vim: ts=8 sw=2 smarttab ft=cpp | |
#include <string.h> | |
#include <iostream> | |
#include <map> | |
#include <expat.h> | |
#include "include/types.h" | |
#include "include/utime.h" | |
#include "rgw_xml.h" | |
XMLObjIter:: | |
XMLObjIter() | |
{ | |
} | |
XMLObjIter:: | |
~XMLObjIter() | |
{ | |
} | |
void XMLObjIter:: | |
set(const XMLObjIter::map_iter_t &_cur, const XMLObjIter::map_iter_t &_end) | |
{ | |
cur = _cur; | |
end = _end; | |
} | |
XMLObj *XMLObjIter:: | |
get_next() | |
{ | |
XMLObj *obj = NULL; | |
if (cur != end) { | |
obj = cur->second; | |
++cur; | |
} | |
return obj; | |
} | |
bool XMLObjIter::get_name(std::string& name) const | |
{ | |
if (cur == end) { | |
return false; | |
} | |
name = cur->first; | |
return true; | |
} | |
ostream& operator<<(ostream &out, const XMLObj &obj) { | |
out << obj.obj_type << ": " << obj.data; | |
return out; | |
} | |
XMLObj:: | |
~XMLObj() | |
{ | |
} | |
bool XMLObj:: | |
xml_start(XMLObj *parent, const char *el, const char **attr) | |
{ | |
this->parent = parent; | |
obj_type = el; | |
for (int i = 0; attr[i]; i += 2) { | |
attr_map[attr[i]] = std::string(attr[i + 1]); | |
} | |
return true; | |
} | |
bool XMLObj:: | |
xml_end(const char *el) | |
{ | |
return true; | |
} | |
void XMLObj:: | |
xml_handle_data(const char *s, int len) | |
{ | |
data.append(s, len); | |
} | |
const std::string& XMLObj:: | |
XMLObj::get_data() const | |
{ | |
return data; | |
} | |
const std::string& XMLObj:: | |
XMLObj::get_obj_type() const | |
{ | |
return obj_type; | |
} | |
XMLObj *XMLObj:: | |
XMLObj::get_parent() | |
{ | |
return parent; | |
} | |
void XMLObj:: | |
add_child(const std::string& el, XMLObj *obj) | |
{ | |
children.insert(std::pair<std::string, XMLObj *>(el, obj)); | |
} | |
bool XMLObj:: | |
get_attr(const std::string& name, std::string& attr) const | |
{ | |
const std::map<std::string, std::string>::const_iterator iter = attr_map.find(name); | |
if (iter == attr_map.end()) | |
return false; | |
attr = iter->second; | |
return true; | |
} | |
XMLObjIter XMLObj:: | |
find(const std::string& name) | |
{ | |
XMLObjIter iter; | |
const XMLObjIter::const_map_iter_t first = children.find(name); | |
XMLObjIter::const_map_iter_t last; | |
if (first != children.end()) { | |
last = children.upper_bound(name); | |
}else | |
last = children.end(); | |
iter.set(first, last); | |
return iter; | |
} | |
XMLObjIter XMLObj::find_first() | |
{ | |
XMLObjIter iter; | |
const XMLObjIter::const_map_iter_t first = children.begin(); | |
const XMLObjIter::const_map_iter_t last = children.end(); | |
iter.set(first, last); | |
return iter; | |
} | |
XMLObj *XMLObj:: | |
find_first(const std::string& name) | |
{ | |
const XMLObjIter::const_map_iter_t first = children.find(name); | |
if (first != children.end()) | |
return first->second; | |
return nullptr; | |
} | |
RGWXMLParser:: | |
RGWXMLParser() : buf(nullptr), buf_len(0), cur_obj(nullptr), success(true), init_called(false) | |
{ | |
p = XML_ParserCreate(nullptr); | |
} | |
RGWXMLParser:: | |
~RGWXMLParser() | |
{ | |
XML_ParserFree(p); | |
free(buf); | |
std::list<XMLObj *>::const_iterator iter; | |
for (iter = allocated_objs.begin(); iter != allocated_objs.end(); ++iter) { | |
XMLObj *obj = *iter; | |
delete obj; | |
} | |
} | |
void RGWXMLParser::call_xml_start(void* user_data, const char *el, const char **attr) { | |
RGWXMLParser *handler = static_cast<RGWXMLParser *>(user_data); | |
XMLObj * obj = handler->alloc_obj(el); | |
if (!obj) { | |
handler->unallocated_objs.push_back(XMLObj()); | |
obj = &handler->unallocated_objs.back(); | |
} else { | |
handler->allocated_objs.push_back(obj); | |
} | |
if (!obj->xml_start(handler->cur_obj, el, attr)) { | |
handler->success = false; | |
return; | |
} | |
if (handler->cur_obj) { | |
handler->cur_obj->add_child(el, obj); | |
} else { | |
handler->children.insert(std::pair<std::string, XMLObj *>(el, obj)); | |
} | |
handler->cur_obj = obj; | |
handler->objs.push_back(obj); | |
} | |
void RGWXMLParser::call_xml_end(void* user_data, const char *el) { | |
RGWXMLParser *handler = static_cast<RGWXMLParser *>(user_data); | |
XMLObj *parent_obj = handler->cur_obj->get_parent(); | |
if (!handler->cur_obj->xml_end(el)) { | |
handler->success = false; | |
return; | |
} | |
handler->cur_obj = parent_obj; | |
} | |
void RGWXMLParser::call_xml_handle_data(void* user_data, const char *s, int len) | |
{ | |
RGWXMLParser *handler = static_cast<RGWXMLParser *>(user_data); | |
handler->cur_obj->xml_handle_data(s, len); | |
} | |
bool RGWXMLParser::init() | |
{ | |
if (!p) { | |
return false; | |
} | |
init_called = true; | |
XML_SetElementHandler(p, RGWXMLParser::call_xml_start, RGWXMLParser::call_xml_end); | |
XML_SetCharacterDataHandler(p, RGWXMLParser::call_xml_handle_data); | |
XML_SetUserData(p, (void *)this); | |
return true; | |
} | |
bool RGWXMLParser::parse(const char *_buf, int len, int done) | |
{ | |
ceph_assert(init_called); | |
int pos = buf_len; | |
char *tmp_buf; | |
tmp_buf = (char *)realloc(buf, buf_len + len); | |
if (tmp_buf == NULL){ | |
free(buf); | |
buf = NULL; | |
return false; | |
} else { | |
buf = tmp_buf; | |
} | |
memcpy(&buf[buf_len], _buf, len); | |
buf_len += len; | |
success = true; | |
if (!XML_Parse(p, &buf[pos], len, done)) { | |
fprintf(stderr, "Parse error at line %d:\n%s\n", | |
(int)XML_GetCurrentLineNumber(p), | |
XML_ErrorString(XML_GetErrorCode(p))); | |
success = false; | |
} | |
return success; | |
} | |
void decode_xml_obj(unsigned long& val, XMLObj *obj) | |
{ | |
auto& s = obj->get_data(); | |
const char *start = s.c_str(); | |
char *p; | |
errno = 0; | |
val = strtoul(start, &p, 10); | |
/* Check for various possible errors */ | |
if ((errno == ERANGE && val == ULONG_MAX) || | |
(errno != 0 && val == 0)) { | |
throw RGWXMLDecoder::err("failed to number"); | |
} | |
if (p == start) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
while (*p != '\0') { | |
if (!isspace(*p)) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
p++; | |
} | |
} | |
void decode_xml_obj(long& val, XMLObj *obj) | |
{ | |
const std::string s = obj->get_data(); | |
const char *start = s.c_str(); | |
char *p; | |
errno = 0; | |
val = strtol(start, &p, 10); | |
/* Check for various possible errors */ | |
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || | |
(errno != 0 && val == 0)) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
if (p == start) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
while (*p != '\0') { | |
if (!isspace(*p)) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
p++; | |
} | |
} | |
void decode_xml_obj(long long& val, XMLObj *obj) | |
{ | |
const std::string s = obj->get_data(); | |
const char *start = s.c_str(); | |
char *p; | |
errno = 0; | |
val = strtoll(start, &p, 10); | |
/* Check for various possible errors */ | |
if ((errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) || | |
(errno != 0 && val == 0)) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
if (p == start) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
while (*p != '\0') { | |
if (!isspace(*p)) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
p++; | |
} | |
} | |
void decode_xml_obj(unsigned long long& val, XMLObj *obj) | |
{ | |
const std::string s = obj->get_data(); | |
const char *start = s.c_str(); | |
char *p; | |
errno = 0; | |
val = strtoull(start, &p, 10); | |
/* Check for various possible errors */ | |
if ((errno == ERANGE && val == ULLONG_MAX) || | |
(errno != 0 && val == 0)) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
if (p == start) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
while (*p != '\0') { | |
if (!isspace(*p)) { | |
throw RGWXMLDecoder::err("failed to parse number"); | |
} | |
p++; | |
} | |
} | |
void decode_xml_obj(int& val, XMLObj *obj) | |
{ | |
long l; | |
decode_xml_obj(l, obj); | |
#if LONG_MAX > INT_MAX | |
if (l > INT_MAX || l < INT_MIN) { | |
throw RGWXMLDecoder::err("integer out of range"); | |
} | |
#endif | |
val = (int)l; | |
} | |
void decode_xml_obj(unsigned& val, XMLObj *obj) | |
{ | |
unsigned long l; | |
decode_xml_obj(l, obj); | |
#if ULONG_MAX > UINT_MAX | |
if (l > UINT_MAX) { | |
throw RGWXMLDecoder::err("unsigned integer out of range"); | |
} | |
#endif | |
val = (unsigned)l; | |
} | |
void decode_xml_obj(bool& val, XMLObj *obj) | |
{ | |
const std::string s = obj->get_data(); | |
if (strncasecmp(s.c_str(), "true", 8) == 0) { | |
val = true; | |
return; | |
} | |
if (strncasecmp(s.c_str(), "false", 8) == 0) { | |
val = false; | |
return; | |
} | |
int i; | |
decode_xml_obj(i, obj); | |
val = (bool)i; | |
} | |
void decode_xml_obj(bufferlist& val, XMLObj *obj) | |
{ | |
const std::string s = obj->get_data(); | |
bufferlist bl; | |
bl.append(s.c_str(), s.size()); | |
try { | |
val.decode_base64(bl); | |
} catch (buffer::error& err) { | |
throw RGWXMLDecoder::err("failed to decode base64"); | |
} | |
} | |
void decode_xml_obj(utime_t& val, XMLObj *obj) | |
{ | |
const std::string s = obj->get_data(); | |
uint64_t epoch; | |
uint64_t nsec; | |
int r = utime_t::parse_date(s, &epoch, &nsec); | |
if (r == 0) { | |
val = utime_t(epoch, nsec); | |
} else { | |
throw RGWXMLDecoder::err("failed to decode utime_t"); | |
} | |
} | |
void encode_xml(const char *name, const string& val, Formatter *f) | |
{ | |
f->dump_string(name, val); | |
} | |
void encode_xml(const char *name, const char *val, Formatter *f) | |
{ | |
f->dump_string(name, val); | |
} | |
void encode_xml(const char *name, bool val, Formatter *f) | |
{ | |
std::string s; | |
if (val) | |
s = "True"; | |
else | |
s = "False"; | |
f->dump_string(name, s); | |
} | |
void encode_xml(const char *name, int val, Formatter *f) | |
{ | |
f->dump_int(name, val); | |
} | |
void encode_xml(const char *name, long val, Formatter *f) | |
{ | |
f->dump_int(name, val); | |
} | |
void encode_xml(const char *name, unsigned val, Formatter *f) | |
{ | |
f->dump_unsigned(name, val); | |
} | |
void encode_xml(const char *name, unsigned long val, Formatter *f) | |
{ | |
f->dump_unsigned(name, val); | |
} | |
void encode_xml(const char *name, unsigned long long val, Formatter *f) | |
{ | |
f->dump_unsigned(name, val); | |
} | |
void encode_xml(const char *name, long long val, Formatter *f) | |
{ | |
f->dump_int(name, val); | |
} | |
void encode_xml(const char *name, const utime_t& val, Formatter *f) | |
{ | |
val.gmtime(f->dump_stream(name)); | |
} | |
void encode_xml(const char *name, const bufferlist& bl, Formatter *f) | |
{ | |
/* need to copy data from bl, as it is const bufferlist */ | |
bufferlist src = bl; | |
bufferlist b64; | |
src.encode_base64(b64); | |
const std::string s(b64.c_str(), b64.length()); | |
encode_xml(name, s, f); | |
} | |