diff options
Diffstat (limited to '')
-rwxr-xr-x | src/rgw/rgw_xml.cc | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/src/rgw/rgw_xml.cc b/src/rgw/rgw_xml.cc new file mode 100755 index 00000000..4ecd9d66 --- /dev/null +++ b/src/rgw/rgw_xml.cc @@ -0,0 +1,500 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#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); +} + |