Skip to content
Permalink
master
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
500 lines (415 sloc) 9.75 KB
// -*- 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);
}