]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_xml.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rgw / rgw_xml.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #ifndef CEPH_RGW_XML_H
5 #define CEPH_RGW_XML_H
6
7 #include <map>
8 #include <string>
9 #include <iosfwd>
10 #include <include/types.h>
11 #include <common/Formatter.h>
12
13 class XMLObj;
14 class RGWXMLParser;
15
16 class XMLObjIter {
17 public:
18 typedef map<std::string, XMLObj *>::iterator map_iter_t;
19 typedef map<std::string, XMLObj *>::iterator const_map_iter_t;
20
21 XMLObjIter();
22 ~XMLObjIter();
23 void set(const XMLObjIter::const_map_iter_t &_cur, const XMLObjIter::const_map_iter_t &_end);
24 XMLObj *get_next();
25 bool get_name(std::string& name) const;
26
27 private:
28 map_iter_t cur;
29 map_iter_t end;
30 };
31
32 /**
33 * Represents a block of XML.
34 * Give the class an XML blob, and it will parse the blob into
35 * an attr_name->value map.
36 * It shouldn't be the start point for any parsing. Look at RGWXMLParser for that.
37 */
38 class XMLObj
39 {
40 private:
41 XMLObj *parent;
42 std::string obj_type;
43
44 protected:
45 std::string data;
46 std::multimap<std::string, XMLObj *> children;
47 std::map<std::string, std::string> attr_map;
48
49 // invoked at the beginning of the XML tag, and populate any attributes
50 bool xml_start(XMLObj *parent, const char *el, const char **attr);
51 // callback invoked at the end of the XML tag
52 // if objects are created while parsing, this should be overwritten in the drived class
53 virtual bool xml_end(const char *el);
54 // callback invoked for storing the data of the XML tag
55 // if data manipulation is needed this could be overwritten in the drived class
56 virtual void xml_handle_data(const char *s, int len);
57 // get the parent object
58 XMLObj *get_parent();
59 // add a child XML object
60 void add_child(const std::string& el, XMLObj *obj);
61
62 public:
63 XMLObj() : parent(nullptr) {}
64 virtual ~XMLObj();
65
66 // get the data (as string)
67 const std::string& get_data() const;
68 // get the type of the object (as string)
69 const std::string& get_obj_type() const;
70 bool get_attr(const std::string& name, std::string& attr) const;
71 // return a list of sub-tags matching the name
72 XMLObjIter find(const std::string& name);
73 // return the first sub-tag
74 XMLObjIter find_first();
75 // return the first sub-tags matching the name
76 XMLObj *find_first(const std::string& name);
77
78 friend ostream& operator<<(ostream &out, const XMLObj &obj);
79 friend RGWXMLParser;
80 };
81
82 struct XML_ParserStruct;
83
84 // an XML parser is an XML object without a parent (root of the tree)
85 // the parser could be used in 2 ways:
86 //
87 // (1) lazy object creation/intrusive API: usually used within the RGWXMLDecode namespace (as RGWXMLDecode::XMLParser)
88 // the parser will parse the input and store info, but will not generate the target object. The object can be allocated outside
89 // of the parser (stack or heap), and require to implement the decode_xml() API for the values to be populated.
90 // note that the decode_xml() calls may throw exceptions if parsing fails
91 //
92 // (2) object creation while parsing: a new class needs to be derived from RGWXMLParser and implement alloc_obj()
93 // API that should create a set of classes derived from XMLObj implementing xml_end() to create the actual target objects
94 //
95 // There could be a mix-and-match of the 2 types, control over that is in the alloc_obj() call
96 // deciding for which tags objects are allocate during parsing and for which tags object allocation is external
97
98 class RGWXMLParser : public XMLObj
99 {
100 private:
101 XML_ParserStruct *p;
102 char *buf;
103 int buf_len;
104 XMLObj *cur_obj;
105 std::vector<XMLObj *> objs;
106 std::list<XMLObj *> allocated_objs;
107 std::list<XMLObj> unallocated_objs;
108 bool success;
109 bool init_called;
110
111 // calls xml_start() on each parsed object
112 // passed as static callback to actual parser, passes itself as user_data
113 static void call_xml_start(void* user_data, const char *el, const char **attr);
114 // calls xml_end() on each parsed object
115 // passed as static callback to actual parser, passes itself as user_data
116 static void call_xml_end(void* user_data, const char *el);
117 // calls xml_handle_data() on each parsed object
118 // passed as static callback to actual parser, passes itself as user_data
119 static void call_xml_handle_data(void* user_data, const char *s, int len);
120
121 protected:
122 // if objects are created while parsing, this should be implemented in the derived class
123 // and be a factory for creating the classes derived from XMLObj
124 // note that not all sub-tags has to be constructed here, any such tag which is not
125 // constructed will be lazily created when decode_xml() is invoked on it
126 //
127 // note that in case of different tags sharing the same name at different levels
128 // this method should not be used
129 virtual XMLObj *alloc_obj(const char *el) {
130 return nullptr;
131 }
132
133 public:
134 RGWXMLParser();
135 ~RGWXMLParser() override;
136
137 // initialize the parser, must be called before parsing
138 bool init();
139 // parse the XML buffer (can be invoked multiple times for incremental parsing)
140 // receives the buffer to parse, its length, and boolean indication (0,1)
141 // whether this is the final chunk of the buffer
142 bool parse(const char *buf, int len, int done);
143 // get the XML blob being parsed
144 const char *get_xml() const { return buf; }
145 };
146
147 namespace RGWXMLDecoder {
148 struct err {
149 std::string message;
150
151 explicit err(const std::string& m) : message(m) {}
152 };
153
154 typedef RGWXMLParser XMLParser;
155
156 template<class T>
157 bool decode_xml(const char *name, T& val, XMLObj* obj, bool mandatory = false);
158
159 template<class T>
160 bool decode_xml(const char *name, std::vector<T>& v, XMLObj* obj, bool mandatory = false);
161
162 template<class C>
163 bool decode_xml(const char *name, C& container, void (*cb)(C&, XMLObj *obj), XMLObj *obj, bool mandatory = false);
164
165 template<class T>
166 void decode_xml(const char *name, T& val, T& default_val, XMLObj* obj);
167 }
168
169 static inline ostream& operator<<(ostream &out, RGWXMLDecoder::err& err)
170 {
171 return out << err.message;
172 }
173
174 template<class T>
175 void decode_xml_obj(T& val, XMLObj *obj)
176 {
177 val.decode_xml(obj);
178 }
179
180 static inline void decode_xml_obj(string& val, XMLObj *obj)
181 {
182 val = obj->get_data();
183 }
184
185 void decode_xml_obj(unsigned long long& val, XMLObj *obj);
186 void decode_xml_obj(long long& val, XMLObj *obj);
187 void decode_xml_obj(unsigned long& val, XMLObj *obj);
188 void decode_xml_obj(long& val, XMLObj *obj);
189 void decode_xml_obj(unsigned& val, XMLObj *obj);
190 void decode_xml_obj(int& val, XMLObj *obj);
191 void decode_xml_obj(bool& val, XMLObj *obj);
192 void decode_xml_obj(bufferlist& val, XMLObj *obj);
193 class utime_t;
194 void decode_xml_obj(utime_t& val, XMLObj *obj);
195
196 template<class T>
197 void do_decode_xml_obj(list<T>& l, const string& name, XMLObj *obj)
198 {
199 l.clear();
200
201 XMLObjIter iter = obj->find(name);
202 XMLObj *o;
203
204 while ((o = iter.get_next())) {
205 T val;
206 decode_xml_obj(val, o);
207 l.push_back(val);
208 }
209 }
210
211 template<class T>
212 bool RGWXMLDecoder::decode_xml(const char *name, T& val, XMLObj *obj, bool mandatory)
213 {
214 XMLObjIter iter = obj->find(name);
215 XMLObj *o = iter.get_next();
216 if (!o) {
217 if (mandatory) {
218 string s = "missing mandatory field " + string(name);
219 throw err(s);
220 }
221 val = T();
222 return false;
223 }
224
225 try {
226 decode_xml_obj(val, o);
227 } catch (err& e) {
228 string s = string(name) + ": ";
229 s.append(e.message);
230 throw err(s);
231 }
232
233 return true;
234 }
235
236 template<class T>
237 bool RGWXMLDecoder::decode_xml(const char *name, std::vector<T>& v, XMLObj *obj, bool mandatory)
238 {
239 XMLObjIter iter = obj->find(name);
240 XMLObj *o = iter.get_next();
241
242 v.clear();
243
244 if (!o) {
245 if (mandatory) {
246 string s = "missing mandatory field " + string(name);
247 throw err(s);
248 }
249 return false;
250 }
251
252 do {
253 T val;
254 try {
255 decode_xml_obj(val, o);
256 } catch (err& e) {
257 string s = string(name) + ": ";
258 s.append(e.message);
259 throw err(s);
260 }
261 v.push_back(val);
262 } while ((o = iter.get_next()));
263 return true;
264 }
265
266 template<class C>
267 bool RGWXMLDecoder::decode_xml(const char *name, C& container, void (*cb)(C&, XMLObj *), XMLObj *obj, bool mandatory)
268 {
269 container.clear();
270
271 XMLObjIter iter = obj->find(name);
272 XMLObj *o = iter.get_next();
273 if (!o) {
274 if (mandatory) {
275 string s = "missing mandatory field " + string(name);
276 throw err(s);
277 }
278 return false;
279 }
280
281 try {
282 decode_xml_obj(container, cb, o);
283 } catch (err& e) {
284 string s = string(name) + ": ";
285 s.append(e.message);
286 throw err(s);
287 }
288
289 return true;
290 }
291
292 template<class T>
293 void RGWXMLDecoder::decode_xml(const char *name, T& val, T& default_val, XMLObj *obj)
294 {
295 XMLObjIter iter = obj->find(name);
296 XMLObj *o = iter.get_next();
297 if (!o) {
298 val = default_val;
299 return;
300 }
301
302 try {
303 decode_xml_obj(val, o);
304 } catch (err& e) {
305 val = default_val;
306 string s = string(name) + ": ";
307 s.append(e.message);
308 throw err(s);
309 }
310 }
311
312 template<class T>
313 static void encode_xml(const char *name, const T& val, ceph::Formatter *f)
314 {
315 f->open_object_section(name);
316 val.dump_xml(f);
317 f->close_section();
318 }
319
320 template<class T>
321 static void encode_xml(const char *name, const char *ns, const T& val, ceph::Formatter *f)
322 {
323 f->open_object_section_in_ns(name, ns);
324 val.dump_xml(f);
325 f->close_section();
326 }
327
328 void encode_xml(const char *name, const string& val, ceph::Formatter *f);
329 void encode_xml(const char *name, const char *val, ceph::Formatter *f);
330 void encode_xml(const char *name, bool val, ceph::Formatter *f);
331 void encode_xml(const char *name, int val, ceph::Formatter *f);
332 void encode_xml(const char *name, unsigned val, ceph::Formatter *f);
333 void encode_xml(const char *name, long val, ceph::Formatter *f);
334 void encode_xml(const char *name, unsigned long val, ceph::Formatter *f);
335 void encode_xml(const char *name, long long val, ceph::Formatter *f);
336 void encode_xml(const char *name, const utime_t& val, ceph::Formatter *f);
337 void encode_xml(const char *name, const bufferlist& bl, ceph::Formatter *f);
338 void encode_xml(const char *name, long long unsigned val, ceph::Formatter *f);
339
340 template<class T>
341 static void do_encode_xml(const char *name, const std::list<T>& l, const char *entry_name, ceph::Formatter *f)
342 {
343 f->open_array_section(name);
344 for (typename std::list<T>::const_iterator iter = l.begin(); iter != l.end(); ++iter) {
345 encode_xml(entry_name, *iter, f);
346 }
347 f->close_section();
348 }
349
350
351
352 #endif