1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
11 #include <include/types.h>
12 #include <common/Formatter.h>
19 typedef std::map
<std::string
, XMLObj
*>::iterator map_iter_t
;
20 typedef std::map
<std::string
, XMLObj
*>::iterator const_map_iter_t
;
24 void set(const XMLObjIter::const_map_iter_t
&_cur
, const XMLObjIter::const_map_iter_t
&_end
);
26 bool get_name(std::string
& name
) const;
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.
47 std::multimap
<std::string
, XMLObj
*> children
;
48 std::map
<std::string
, std::string
> attr_map
;
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
60 // add a child XML object
61 void add_child(const std::string
& el
, XMLObj
*obj
);
64 XMLObj() : parent(nullptr) {}
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
);
79 friend std::ostream
& operator<<(std::ostream
&out
, const XMLObj
&obj
);
83 struct XML_ParserStruct
;
85 // an XML parser is an XML object without a parent (root of the tree)
86 // the parser could be used in 2 ways:
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
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
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
99 class RGWXMLParser
: public XMLObj
106 std::vector
<XMLObj
*> objs
;
107 std::list
<XMLObj
*> allocated_objs
;
108 std::list
<XMLObj
> unallocated_objs
;
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
);
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
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
) {
136 ~RGWXMLParser() override
;
138 // initialize the parser, must be called before parsing
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
; }
148 namespace RGWXMLDecoder
{
149 struct err
: std::runtime_error
{
150 using runtime_error::runtime_error
;
153 typedef RGWXMLParser XMLParser
;
156 bool decode_xml(const char *name
, T
& val
, XMLObj
* obj
, bool mandatory
= false);
159 bool decode_xml(const char *name
, std::vector
<T
>& v
, XMLObj
* obj
, bool mandatory
= false);
162 bool decode_xml(const char *name
, C
& container
, void (*cb
)(C
&, XMLObj
*obj
), XMLObj
*obj
, bool mandatory
= false);
165 void decode_xml(const char *name
, T
& val
, T
& default_val
, XMLObj
* obj
);
168 static inline std::ostream
& operator<<(std::ostream
&out
, RGWXMLDecoder::err
& err
)
170 return out
<< err
.what();
174 void decode_xml_obj(T
& val
, XMLObj
*obj
)
179 static inline void decode_xml_obj(std::string
& val
, XMLObj
*obj
)
181 val
= obj
->get_data();
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
);
193 void decode_xml_obj(utime_t
& val
, XMLObj
*obj
);
196 void decode_xml_obj(std::optional
<T
>& val
, XMLObj
*obj
)
199 decode_xml_obj(*val
, obj
);
203 void do_decode_xml_obj(std::list
<T
>& l
, const std::string
& name
, XMLObj
*obj
)
207 XMLObjIter iter
= obj
->find(name
);
210 while ((o
= iter
.get_next())) {
212 decode_xml_obj(val
, o
);
218 bool RGWXMLDecoder::decode_xml(const char *name
, T
& val
, XMLObj
*obj
, bool mandatory
)
220 XMLObjIter iter
= obj
->find(name
);
221 XMLObj
*o
= iter
.get_next();
224 std::string s
= "missing mandatory field " + std::string(name
);
232 decode_xml_obj(val
, o
);
233 } catch (const err
& e
) {
234 std::string s
= std::string(name
) + ": ";
243 bool RGWXMLDecoder::decode_xml(const char *name
, std::vector
<T
>& v
, XMLObj
*obj
, bool mandatory
)
245 XMLObjIter iter
= obj
->find(name
);
246 XMLObj
*o
= iter
.get_next();
252 std::string s
= "missing mandatory field " + std::string(name
);
261 decode_xml_obj(val
, o
);
262 } catch (const err
& e
) {
263 std::string s
= std::string(name
) + ": ";
268 } while ((o
= iter
.get_next()));
273 bool RGWXMLDecoder::decode_xml(const char *name
, C
& container
, void (*cb
)(C
&, XMLObj
*), XMLObj
*obj
, bool mandatory
)
277 XMLObjIter iter
= obj
->find(name
);
278 XMLObj
*o
= iter
.get_next();
281 std::string s
= "missing mandatory field " + std::string(name
);
288 decode_xml_obj(container
, cb
, o
);
289 } catch (const err
& e
) {
290 std::string s
= std::string(name
) + ": ";
299 void RGWXMLDecoder::decode_xml(const char *name
, T
& val
, T
& default_val
, XMLObj
*obj
)
301 XMLObjIter iter
= obj
->find(name
);
302 XMLObj
*o
= iter
.get_next();
309 decode_xml_obj(val
, o
);
310 } catch (const err
& e
) {
312 std::string s
= std::string(name
) + ": ";
319 static void encode_xml(const char *name
, const T
& val
, ceph::Formatter
*f
)
321 f
->open_object_section(name
);
327 static void encode_xml(const char *name
, const char *ns
, const T
& val
, ceph::Formatter
*f
)
329 f
->open_object_section_in_ns(name
, ns
);
334 void encode_xml(const char *name
, const std::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
);
347 static void do_encode_xml(const char *name
, const std::list
<T
>& l
, const char *entry_name
, ceph::Formatter
*f
)
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
);
357 static void encode_xml(const char *name
, const std::vector
<T
>& l
, ceph::Formatter
*f
)
359 for (typename
std::vector
<T
>::const_iterator iter
= l
.begin(); iter
!= l
.end(); ++iter
) {
360 encode_xml(name
, *iter
, f
);
365 static void encode_xml(const char *name
, const std::optional
<T
>& o
, ceph::Formatter
*f
)
371 encode_xml(name
, *o
, f
);