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