VirtualBox

source: vbox/trunk/include/iprt/cpp/xml.h@ 69844

Last change on this file since 69844 was 69105, checked in by vboxsync, 7 years ago

include/iprt/: (C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.3 KB
Line 
1/** @file
2 * IPRT - XML Helper APIs.
3 */
4
5/*
6 * Copyright (C) 2007-2017 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef ___iprt_xml_h
27#define ___iprt_xml_h
28
29#ifndef IN_RING3
30# error "There are no XML APIs available in Ring-0 Context!"
31#endif
32
33#include <iprt/list.h>
34#include <iprt/cpp/exception.h>
35#include <iprt/cpp/utils.h>
36
37#include <list>
38#include <memory>
39
40
41/** @defgroup grp_rt_cpp_xml C++ XML support
42 * @ingroup grp_rt_cpp
43 * @{
44 */
45
46/* Forwards */
47typedef struct _xmlParserInput xmlParserInput;
48typedef xmlParserInput *xmlParserInputPtr;
49typedef struct _xmlParserCtxt xmlParserCtxt;
50typedef xmlParserCtxt *xmlParserCtxtPtr;
51typedef struct _xmlError xmlError;
52typedef xmlError *xmlErrorPtr;
53
54typedef struct _xmlAttr xmlAttr;
55typedef struct _xmlNode xmlNode;
56
57/** @} */
58
59namespace xml
60{
61
62/**
63 * @addtogroup grp_rt_cpp_xml
64 * @{
65 */
66
67// Exceptions
68//////////////////////////////////////////////////////////////////////////////
69
70class RT_DECL_CLASS LogicError : public RTCError
71{
72public:
73
74 LogicError(const char *aMsg = NULL)
75 : RTCError(aMsg)
76 {}
77
78 LogicError(RT_SRC_POS_DECL);
79};
80
81class RT_DECL_CLASS RuntimeError : public RTCError
82{
83public:
84
85 RuntimeError(const char *aMsg = NULL)
86 : RTCError(aMsg)
87 {}
88};
89
90class RT_DECL_CLASS XmlError : public RuntimeError
91{
92public:
93 XmlError(xmlErrorPtr aErr);
94
95 static char* Format(xmlErrorPtr aErr);
96};
97
98// Logical errors
99//////////////////////////////////////////////////////////////////////////////
100
101class RT_DECL_CLASS ENotImplemented : public LogicError
102{
103public:
104 ENotImplemented(const char *aMsg = NULL) : LogicError(aMsg) {}
105 ENotImplemented(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
106};
107
108class RT_DECL_CLASS EInvalidArg : public LogicError
109{
110public:
111 EInvalidArg(const char *aMsg = NULL) : LogicError(aMsg) {}
112 EInvalidArg(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
113};
114
115class RT_DECL_CLASS EDocumentNotEmpty : public LogicError
116{
117public:
118 EDocumentNotEmpty(const char *aMsg = NULL) : LogicError(aMsg) {}
119 EDocumentNotEmpty(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
120};
121
122class RT_DECL_CLASS ENodeIsNotElement : public LogicError
123{
124public:
125 ENodeIsNotElement(const char *aMsg = NULL) : LogicError(aMsg) {}
126 ENodeIsNotElement(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
127};
128
129// Runtime errors
130//////////////////////////////////////////////////////////////////////////////
131
132class RT_DECL_CLASS EIPRTFailure : public RuntimeError
133{
134public:
135
136 EIPRTFailure(int aRC, const char *pcszContext, ...);
137
138 int rc() const
139 {
140 return mRC;
141 }
142
143private:
144 int mRC;
145};
146
147/**
148 * The Stream class is a base class for I/O streams.
149 */
150class RT_DECL_CLASS Stream
151{
152public:
153
154 virtual ~Stream() {}
155
156 virtual const char *uri() const = 0;
157
158 /**
159 * Returns the current read/write position in the stream. The returned
160 * position is a zero-based byte offset from the beginning of the file.
161 *
162 * Throws ENotImplemented if this operation is not implemented for the
163 * given stream.
164 */
165 virtual uint64_t pos() const = 0;
166
167 /**
168 * Sets the current read/write position in the stream.
169 *
170 * @param aPos Zero-based byte offset from the beginning of the stream.
171 *
172 * Throws ENotImplemented if this operation is not implemented for the
173 * given stream.
174 */
175 virtual void setPos (uint64_t aPos) = 0;
176};
177
178/**
179 * The Input class represents an input stream.
180 *
181 * This input stream is used to read the settings tree from.
182 * This is an abstract class that must be subclassed in order to fill it with
183 * useful functionality.
184 */
185class RT_DECL_CLASS Input : virtual public Stream
186{
187public:
188
189 /**
190 * Reads from the stream to the supplied buffer.
191 *
192 * @param aBuf Buffer to store read data to.
193 * @param aLen Buffer length.
194 *
195 * @return Number of bytes read.
196 */
197 virtual int read (char *aBuf, int aLen) = 0;
198};
199
200/**
201 *
202 */
203class RT_DECL_CLASS Output : virtual public Stream
204{
205public:
206
207 /**
208 * Writes to the stream from the supplied buffer.
209 *
210 * @param aBuf Buffer to write data from.
211 * @param aLen Buffer length.
212 *
213 * @return Number of bytes written.
214 */
215 virtual int write (const char *aBuf, int aLen) = 0;
216
217 /**
218 * Truncates the stream from the current position and upto the end.
219 * The new file size will become exactly #pos() bytes.
220 *
221 * Throws ENotImplemented if this operation is not implemented for the
222 * given stream.
223 */
224 virtual void truncate() = 0;
225};
226
227
228//////////////////////////////////////////////////////////////////////////////
229
230/**
231 * The File class is a stream implementation that reads from and writes to
232 * regular files.
233 *
234 * The File class uses IPRT File API for file operations. Note that IPRT File
235 * API is not thread-safe. This means that if you pass the same RTFILE handle to
236 * different File instances that may be simultaneously used on different
237 * threads, you should care about serialization; otherwise you will get garbage
238 * when reading from or writing to such File instances.
239 */
240class RT_DECL_CLASS File : public Input, public Output
241{
242public:
243
244 /**
245 * Possible file access modes.
246 */
247 enum Mode { Mode_Read, Mode_WriteCreate, Mode_Overwrite, Mode_ReadWrite };
248
249 /**
250 * Opens a file with the given name in the given mode. If @a aMode is Read
251 * or ReadWrite, the file must exist. If @a aMode is Write, the file must
252 * not exist. Otherwise, an EIPRTFailure excetion will be thrown.
253 *
254 * @param aMode File mode.
255 * @param aFileName File name.
256 * @param aFlushIt Whether to flush a writable file before closing it.
257 */
258 File(Mode aMode, const char *aFileName, bool aFlushIt = false);
259
260 /**
261 * Uses the given file handle to perform file operations. This file
262 * handle must be already open in necessary mode (read, or write, or mixed).
263 *
264 * The read/write position of the given handle will be reset to the
265 * beginning of the file on success.
266 *
267 * Note that the given file handle will not be automatically closed upon
268 * this object destruction.
269 *
270 * @note It you pass the same RTFILE handle to more than one File instance,
271 * please make sure you have provided serialization in case if these
272 * instasnces are to be simultaneously used by different threads.
273 * Otherwise you may get garbage when reading or writing.
274 *
275 * @param aHandle Open file handle.
276 * @param aFileName File name (for reference).
277 * @param aFlushIt Whether to flush a writable file before closing it.
278 */
279 File(RTFILE aHandle, const char *aFileName = NULL, bool aFlushIt = false);
280
281 /**
282 * Destroys the File object. If the object was created from a file name
283 * the corresponding file will be automatically closed. If the object was
284 * created from a file handle, it will remain open.
285 */
286 virtual ~File();
287
288 const char *uri() const;
289
290 uint64_t pos() const;
291 void setPos(uint64_t aPos);
292
293 /**
294 * See Input::read(). If this method is called in wrong file mode,
295 * LogicError will be thrown.
296 */
297 int read(char *aBuf, int aLen);
298
299 /**
300 * See Output::write(). If this method is called in wrong file mode,
301 * LogicError will be thrown.
302 */
303 int write(const char *aBuf, int aLen);
304
305 /**
306 * See Output::truncate(). If this method is called in wrong file mode,
307 * LogicError will be thrown.
308 */
309 void truncate();
310
311private:
312
313 /* Obscure class data */
314 struct Data;
315 Data *m;
316
317 /* auto_ptr data doesn't have proper copy semantics */
318 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(File);
319};
320
321/**
322 * The MemoryBuf class represents a stream implementation that reads from the
323 * memory buffer.
324 */
325class RT_DECL_CLASS MemoryBuf : public Input
326{
327public:
328
329 MemoryBuf (const char *aBuf, size_t aLen, const char *aURI = NULL);
330
331 virtual ~MemoryBuf();
332
333 const char *uri() const;
334
335 int read(char *aBuf, int aLen);
336 uint64_t pos() const;
337 void setPos(uint64_t aPos);
338
339private:
340 /* Obscure class data */
341 struct Data;
342 Data *m;
343
344 /* auto_ptr data doesn't have proper copy semantics */
345 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(MemoryBuf);
346};
347
348
349/*
350 * GlobalLock
351 *
352 *
353 */
354
355typedef xmlParserInput* FNEXTERNALENTITYLOADER(const char *aURI,
356 const char *aID,
357 xmlParserCtxt *aCtxt);
358typedef FNEXTERNALENTITYLOADER *PFNEXTERNALENTITYLOADER;
359
360class RT_DECL_CLASS GlobalLock
361{
362public:
363 GlobalLock();
364 ~GlobalLock();
365
366 void setExternalEntityLoader(PFNEXTERNALENTITYLOADER pFunc);
367
368 static xmlParserInput* callDefaultLoader(const char *aURI,
369 const char *aID,
370 xmlParserCtxt *aCtxt);
371
372private:
373 /* Obscure class data. */
374 struct Data;
375 struct Data *m;
376};
377
378class ElementNode;
379typedef std::list<const ElementNode*> ElementNodesList;
380
381class AttributeNode;
382
383class ContentNode;
384
385/**
386 * Node base class.
387 *
388 * Cannot be used directly, but ElementNode, ContentNode and AttributeNode
389 * derive from this. This does implement useful public methods though.
390 *
391 *
392 */
393class RT_DECL_CLASS Node
394{
395public:
396 virtual ~Node();
397
398 const char *getName() const;
399 const char *getPrefix() const;
400 const char *getNamespaceURI() const;
401 bool nameEqualsNS(const char *pcszNamespace, const char *pcsz) const;
402 bool nameEquals(const char *pcsz) const
403 {
404 return nameEqualsNS(NULL, pcsz);
405 }
406 bool nameEqualsN(const char *pcsz, size_t cchMax, const char *pcszNamespace = NULL) const;
407
408 const char *getValue() const;
409 bool copyValue(int32_t &i) const;
410 bool copyValue(uint32_t &i) const;
411 bool copyValue(int64_t &i) const;
412 bool copyValue(uint64_t &i) const;
413
414 /** @name Introspection.
415 * @{ */
416 /** Is this an ElementNode instance.
417 * @returns true / false */
418 bool isElement() const
419 {
420 return m_Type == IsElement;
421 }
422
423 /** Is this an ContentNode instance.
424 * @returns true / false */
425 bool isContent() const
426 {
427 return m_Type == IsContent;
428 }
429
430 /** Is this an AttributeNode instance.
431 * @returns true / false */
432 bool isAttribute() const
433 {
434 return m_Type == IsElement;
435 }
436
437 int getLineNumber() const;
438 /** @} */
439
440 /** @name General tree enumeration.
441 *
442 * Use the introspection methods isElement() and isContent() before doing static
443 * casting. Parents are always or ElementNode type, but siblings and children
444 * can be of both ContentNode and ElementNode types.
445 *
446 * @remarks Attribute node are in the attributes list, while both content and
447 * element nodes are in the list of children. See ElementNode.
448 *
449 * @remarks Careful mixing tree walking with node removal!
450 * @{
451 */
452 /** Get the parent node
453 * @returns Pointer to the parent node, or NULL if root. */
454 const Node *getParent() const
455 {
456 return m_pParent;
457 }
458
459 /** Get the previous sibling.
460 * @returns Pointer to the previous sibling node, NULL if first child.
461 */
462 const Node *getPrevSibiling() const
463 {
464 if (!m_pParentListAnchor)
465 return NULL;
466 return RTListGetPrevCpp(m_pParentListAnchor, this, const Node, m_listEntry);
467 }
468
469 /** Get the next sibling.
470 * @returns Pointer to the next sibling node, NULL if last child. */
471 const Node *getNextSibiling() const
472 {
473 if (!m_pParentListAnchor)
474 return NULL;
475 return RTListGetNextCpp(m_pParentListAnchor, this, const Node, m_listEntry);
476 }
477 /** @} */
478
479protected:
480 /** Node types. */
481 typedef enum { IsElement, IsAttribute, IsContent } EnumType;
482
483 /** The type of node this is an instance of. */
484 EnumType m_Type;
485 /** The parent node (always an element), NULL if root. */
486 Node *m_pParent;
487
488 xmlNode *m_pLibNode; ///< != NULL if this is an element or content node
489 xmlAttr *m_pLibAttr; ///< != NULL if this is an attribute node
490 const char *m_pcszNamespacePrefix; ///< not always set
491 const char *m_pcszNamespaceHref; ///< full http:// spec
492 const char *m_pcszName; ///< element or attribute name, points either into pLibNode or pLibAttr;
493 ///< NULL if this is a content node
494
495 /** Child list entry of this node. (List head m_pParent->m_children.) */
496 RTLISTNODE m_listEntry;
497 /** Pointer to the parent list anchor.
498 * This allows us to use m_listEntry both for children and attributes. */
499 PRTLISTANCHOR m_pParentListAnchor;
500
501 // hide the default constructor so people use only our factory methods
502 Node(EnumType type,
503 Node *pParent,
504 PRTLISTANCHOR pListAnchor,
505 xmlNode *pLibNode,
506 xmlAttr *pLibAttr);
507 Node(const Node &x); // no copying
508
509 friend class AttributeNode;
510 friend class ElementNode; /* C list hack. */
511};
512
513/**
514 * Node subclass that represents an attribute of an element.
515 *
516 * For attributes, Node::getName() returns the attribute name, and Node::getValue()
517 * returns the attribute value, if any.
518 *
519 * Since the Node constructor is private, one can create new attribute nodes
520 * only through the following factory methods:
521 *
522 * -- ElementNode::setAttribute()
523 */
524class RT_DECL_CLASS AttributeNode : public Node
525{
526public:
527
528protected:
529 // hide the default constructor so people use only our factory methods
530 AttributeNode(const ElementNode *pElmRoot,
531 Node *pParent,
532 PRTLISTANCHOR pListAnchor,
533 xmlAttr *pLibAttr);
534 AttributeNode(const AttributeNode &x); // no copying
535
536 friend class Node;
537 friend class ElementNode;
538};
539
540/**
541 * Node subclass that represents an element.
542 *
543 * For elements, Node::getName() returns the element name, and Node::getValue()
544 * returns the text contents, if any.
545 *
546 * Since the Node constructor is private, one can create element nodes
547 * only through the following factory methods:
548 *
549 * -- Document::createRootElement()
550 * -- ElementNode::createChild()
551 */
552class RT_DECL_CLASS ElementNode : public Node
553{
554public:
555 int getChildElements(ElementNodesList &children, const char *pcszMatch = NULL) const;
556
557 const ElementNode *findChildElementNS(const char *pcszNamespace, const char *pcszMatch) const;
558 const ElementNode *findChildElement(const char *pcszMatch) const
559 {
560 return findChildElementNS(NULL, pcszMatch);
561 }
562 const ElementNode *findChildElementFromId(const char *pcszId) const;
563
564 /** Finds the first decendant matching the name at the end of @a pcszPath and
565 * optionally namespace.
566 *
567 * @returns Pointer to the child string value, NULL if not found or no value.
568 * @param pcszPath The attribute name. Slashes can be used to make a
569 * simple path to any decendant.
570 * @param pcszNamespace The namespace to match, NULL (default) match any
571 * namespace. When using a path, this matches all
572 * elements along the way.
573 * @see findChildElement, findChildElementP
574 */
575 const ElementNode *findChildElementP(const char *pcszPath, const char *pcszNamespace = NULL) const;
576
577 /** Finds the first child with matching the give name and optionally namspace,
578 * returning its value.
579 *
580 * @returns Pointer to the child string value, NULL if not found or no value.
581 * @param pcszPath The attribute name. Slashes can be used to make a
582 * simple path to any decendant.
583 * @param pcszNamespace The namespace to match, NULL (default) match any
584 * namespace. When using a path, this matches all
585 * elements along the way.
586 * @see findChildElement, findChildElementP
587 */
588 const char *findChildElementValueP(const char *pcszPath, const char *pcszNamespace = NULL) const
589 {
590 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
591 if (pElem)
592 return pElem->getValue();
593 return NULL;
594 }
595
596 /** Combines findChildElementP and findAttributeValue.
597 *
598 * @returns Pointer to attribute string value, NULL if either the element or
599 * the attribute was not found.
600 * @param pcszPath The attribute name. Slashes can be used to make a
601 * simple path to any decendant.
602 * @param pcszAttribute The attribute name.
603 * @param pcszPathNamespace The namespace to match @a pcszPath with, NULL
604 * (default) match any namespace. When using a
605 * path, this matches all elements along the way.
606 * @param pcszAttributeNamespace The namespace prefix to apply to the
607 * attribute, NULL (default) match any namespace.
608 * @see findChildElementP and findAttributeValue
609 */
610 const char *findChildElementAttributeValueP(const char *pcszPath, const char *pcszAttribute,
611 const char *pcszPathNamespace = NULL,
612 const char *pcszAttributeNamespace = NULL) const
613 {
614 const ElementNode *pElem = findChildElementP(pcszPath, pcszPathNamespace);
615 if (pElem)
616 return pElem->findAttributeValue(pcszAttribute, pcszAttributeNamespace);
617 return NULL;
618 }
619
620
621 /** @name Tree enumeration.
622 * @{ */
623
624 /** Get the next tree element in a full tree enumeration.
625 *
626 * By starting with the root node, this can be used to enumerate the entire tree
627 * (or sub-tree if @a pElmRoot is used).
628 *
629 * @returns Pointer to the next element in the tree, NULL if we're done.
630 * @param pElmRoot The root of the tree we're enumerating. NULL if
631 * it's the entire tree.
632 */
633 ElementNode const *getNextTreeElement(ElementNode const *pElmRoot = NULL) const;
634 RT_CPP_GETTER_UNCONST_RET(ElementNode *, ElementNode, getNextTreeElement, (const ElementNode *pElmRoot = NULL), (pElmRoot))
635
636 /** Get the first child node.
637 * @returns Pointer to the first child node, NULL if no children. */
638 const Node *getFirstChild() const
639 {
640 return RTListGetFirstCpp(&m_children, const Node, m_listEntry);
641 }
642 RT_CPP_GETTER_UNCONST_RET(Node *, ElementNode, getFirstChild,(),())
643
644 /** Get the last child node.
645 * @returns Pointer to the last child node, NULL if no children. */
646 const Node *getLastChild() const
647 {
648 return RTListGetLastCpp(&m_children, const Node, m_listEntry);
649 }
650
651 /** Get the first child node.
652 * @returns Pointer to the first child node, NULL if no children. */
653 const ElementNode *getFirstChildElement() const;
654
655 /** Get the last child node.
656 * @returns Pointer to the last child node, NULL if no children. */
657 const ElementNode *getLastChildElement() const;
658
659 /** Get the previous sibling element.
660 * @returns Pointer to the previous sibling element, NULL if first child
661 * element.
662 * @see getNextSibilingElement, getPrevSibling
663 */
664 const ElementNode *getPrevSibilingElement() const;
665
666 /** Get the next sibling element.
667 * @returns Pointer to the next sibling element, NULL if last child element.
668 * @see getPrevSibilingElement, getNextSibling
669 */
670 const ElementNode *getNextSibilingElement() const;
671
672 /** Find the previous element matching the given name and namespace (optionally).
673 * @returns Pointer to the previous sibling element, NULL if first child
674 * element.
675 * @param pcszName The element name to match.
676 * @param pcszNamespace The namespace name, default is NULL which means
677 * anything goes.
678 * @note Changed the order of the arguments.
679 */
680 const ElementNode *findPrevSibilingElement(const char *pcszName, const char *pcszNamespace = NULL) const;
681
682 /** Find the next element matching the given name and namespace (optionally).
683 * @returns Pointer to the previous sibling element, NULL if first child
684 * element.
685 * @param pcszName The element name to match.
686 * @param pcszNamespace The namespace name, default is NULL which means
687 * anything goes.
688 * @note Changed the order of the arguments.
689 */
690 const ElementNode *findNextSibilingElement(const char *pcszName, const char *pcszNamespace = NULL) const;
691 /** @} */
692
693
694 const AttributeNode *findAttribute(const char *pcszMatch, const char *pcszNamespace = NULL) const;
695 /** Find the first attribute with the given name, returning its value string.
696 * @returns Pointer to the attribute string value.
697 * @param pcszName The attribute name.
698 * @param pcszNamespace The namespace name, default is NULL which means
699 * anything goes.
700 * @see getAttributeValue
701 */
702 const char *findAttributeValue(const char *pcszName, const char *pcszNamespace = NULL) const
703 {
704 const AttributeNode *pAttr = findAttribute(pcszName, pcszNamespace);
705 if (pAttr)
706 return pAttr->getValue();
707 return NULL;
708 }
709
710 bool getAttributeValue(const char *pcszMatch, const char *&pcsz, const char *pcszNamespace = NULL) const
711 { return getAttributeValue(pcszMatch, &pcsz, pcszNamespace); }
712 bool getAttributeValue(const char *pcszMatch, RTCString &str, const char *pcszNamespace = NULL) const
713 { return getAttributeValue(pcszMatch, &str, pcszNamespace); }
714 bool getAttributeValuePath(const char *pcszMatch, RTCString &str, const char *pcszNamespace = NULL) const
715 { return getAttributeValue(pcszMatch, &str, pcszNamespace); }
716 bool getAttributeValue(const char *pcszMatch, int32_t &i, const char *pcszNamespace = NULL) const
717 { return getAttributeValue(pcszMatch, &i, pcszNamespace); }
718 bool getAttributeValue(const char *pcszMatch, uint32_t &i, const char *pcszNamespace = NULL) const
719 { return getAttributeValue(pcszMatch, &i, pcszNamespace); }
720 bool getAttributeValue(const char *pcszMatch, int64_t &i, const char *pcszNamespace = NULL) const
721 { return getAttributeValue(pcszMatch, &i, pcszNamespace); }
722 bool getAttributeValue(const char *pcszMatch, uint64_t &u, const char *pcszNamespace = NULL) const
723 { return getAttributeValue(pcszMatch, &u, pcszNamespace); }
724 bool getAttributeValue(const char *pcszMatch, bool &f, const char *pcszNamespace = NULL) const
725 { return getAttributeValue(pcszMatch, &f, pcszNamespace); }
726
727 /** @name Variants that for clarity does not use references for output params.
728 * @{ */
729 bool getAttributeValue(const char *pcszMatch, const char **ppcsz, const char *pcszNamespace = NULL) const;
730 bool getAttributeValue(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace = NULL) const;
731 bool getAttributeValuePath(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace = NULL) const;
732 bool getAttributeValue(const char *pcszMatch, int32_t *pi, const char *pcszNamespace = NULL) const;
733 bool getAttributeValue(const char *pcszMatch, uint32_t *pu, const char *pcszNamespace = NULL) const;
734 bool getAttributeValue(const char *pcszMatch, int64_t *piValue, const char *pcszNamespace = NULL) const;
735 bool getAttributeValue(const char *pcszMatch, uint64_t *pu, const char *pcszNamespace = NULL) const;
736 bool getAttributeValue(const char *pcszMatch, bool *pf, const char *pcszNamespace = NULL) const;
737 /** @} */
738
739 /** @name Convenience methods for convering the element value.
740 * @{ */
741 bool getElementValue(int32_t *piValue) const;
742 bool getElementValue(uint32_t *puValue) const;
743 bool getElementValue(int64_t *piValue) const;
744 bool getElementValue(uint64_t *puValue) const;
745 bool getElementValue(bool *pfValue) const;
746 /** @} */
747
748 /** @name Convenience findChildElementAttributeValueP and getElementValue.
749 * @{ */
750 bool getChildElementValueP(const char *pcszPath, int32_t *piValue, const char *pcszNamespace = NULL) const
751 {
752 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
753 return pElem && pElem->getElementValue(piValue);
754 }
755 bool getChildElementValueP(const char *pcszPath, uint32_t *puValue, const char *pcszNamespace = NULL) const
756 {
757 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
758 return pElem && pElem->getElementValue(puValue);
759 }
760 bool getChildElementValueP(const char *pcszPath, int64_t *piValue, const char *pcszNamespace = NULL) const
761 {
762 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
763 return pElem && pElem->getElementValue(piValue);
764 }
765 bool getChildElementValueP(const char *pcszPath, uint64_t *puValue, const char *pcszNamespace = NULL) const
766 {
767 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
768 return pElem && pElem->getElementValue(puValue);
769 }
770 bool getChildElementValueP(const char *pcszPath, bool *pfValue, const char *pcszNamespace = NULL) const
771 {
772 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
773 return pElem && pElem->getElementValue(pfValue);
774 }
775
776 /** @} */
777
778 /** @name Convenience findChildElementAttributeValueP and getElementValue with a
779 * default value being return if the child element isn't present.
780 *
781 * @remarks These will return false on conversion errors.
782 * @{ */
783 bool getChildElementValueDefP(const char *pcszPath, int32_t iDefault, int32_t *piValue, const char *pcszNamespace = NULL) const
784 {
785 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
786 if (pElem)
787 return pElem->getElementValue(piValue);
788 *piValue = iDefault;
789 return true;
790 }
791 bool getChildElementValueDefP(const char *pcszPath, uint32_t uDefault, uint32_t *puValue, const char *pcszNamespace = NULL) const
792 {
793 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
794 if (pElem)
795 return pElem->getElementValue(puValue);
796 *puValue = uDefault;
797 return true;
798 }
799 bool getChildElementValueDefP(const char *pcszPath, int64_t iDefault, int64_t *piValue, const char *pcszNamespace = NULL) const
800 {
801 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
802 if (pElem)
803 return pElem->getElementValue(piValue);
804 *piValue = iDefault;
805 return true;
806 }
807 bool getChildElementValueDefP(const char *pcszPath, uint64_t uDefault, uint64_t *puValue, const char *pcszNamespace = NULL) const
808 {
809 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
810 if (pElem)
811 return pElem->getElementValue(puValue);
812 *puValue = uDefault;
813 return true;
814 }
815 bool getChildElementValueDefP(const char *pcszPath, bool fDefault, bool *pfValue, const char *pcszNamespace = NULL) const
816 {
817 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
818 if (pElem)
819 return pElem->getElementValue(pfValue);
820 *pfValue = fDefault;
821 return true;
822 }
823 /** @} */
824
825 ElementNode *createChild(const char *pcszElementName);
826
827 ContentNode *addContent(const char *pcszContent);
828 ContentNode *addContent(const RTCString &strContent)
829 {
830 return addContent(strContent.c_str());
831 }
832
833 ContentNode *setContent(const char *pcszContent);
834 ContentNode *setContent(const RTCString &strContent)
835 {
836 return setContent(strContent.c_str());
837 }
838
839 AttributeNode *setAttribute(const char *pcszName, const char *pcszValue);
840 AttributeNode *setAttribute(const char *pcszName, const RTCString &strValue)
841 {
842 return setAttribute(pcszName, strValue.c_str());
843 }
844 AttributeNode *setAttributePath(const char *pcszName, const RTCString &strValue);
845 AttributeNode *setAttribute(const char *pcszName, int32_t i);
846 AttributeNode *setAttribute(const char *pcszName, uint32_t i);
847 AttributeNode *setAttribute(const char *pcszName, int64_t i);
848 AttributeNode *setAttribute(const char *pcszName, uint64_t i);
849 AttributeNode *setAttributeHex(const char *pcszName, uint32_t i);
850 AttributeNode *setAttribute(const char *pcszName, bool f);
851
852 virtual ~ElementNode();
853
854protected:
855 // hide the default constructor so people use only our factory methods
856 ElementNode(const ElementNode *pElmRoot, Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode);
857 ElementNode(const ElementNode &x); // no copying
858
859 /** We keep a pointer to the root element for attribute namespace handling. */
860 const ElementNode *m_pElmRoot;
861
862 /** List of child elements and content nodes. */
863 RTLISTANCHOR m_children;
864 /** List of attributes nodes. */
865 RTLISTANCHOR m_attributes;
866
867 static void buildChildren(ElementNode *pElmRoot);
868
869 friend class Node;
870 friend class Document;
871 friend class XmlFileParser;
872};
873
874/**
875 * Node subclass that represents content (non-element text).
876 *
877 * Since the Node constructor is private, one can create new content nodes
878 * only through the following factory methods:
879 *
880 * -- ElementNode::addContent()
881 */
882class RT_DECL_CLASS ContentNode : public Node
883{
884public:
885
886protected:
887 // hide the default constructor so people use only our factory methods
888 ContentNode(Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode);
889 ContentNode(const ContentNode &x); // no copying
890
891 friend class Node;
892 friend class ElementNode;
893};
894
895
896/**
897 * Handy helper class with which one can loop through all or some children
898 * of a particular element. See NodesLoop::forAllNodes() for details.
899 */
900class RT_DECL_CLASS NodesLoop
901{
902public:
903 NodesLoop(const ElementNode &node, const char *pcszMatch = NULL);
904 ~NodesLoop();
905 const ElementNode* forAllNodes() const;
906
907private:
908 /* Obscure class data */
909 struct Data;
910 Data *m;
911};
912
913/**
914 * The XML document class. An instance of this needs to be created by a user
915 * of the XML classes and then passed to
916 *
917 * -- XmlMemParser or XmlFileParser to read an XML document; those classes then
918 * fill the caller's Document with ElementNode, ContentNode and AttributeNode
919 * instances. The typical sequence then is:
920 * @code
921 Document doc;
922 XmlFileParser parser;
923 parser.read("file.xml", doc);
924 Element *pElmRoot = doc.getRootElement();
925 @endcode
926 *
927 * -- XmlMemWriter or XmlFileWriter to write out an XML document after it has
928 * been created and filled. Example:
929 *
930 * @code
931 Document doc;
932 Element *pElmRoot = doc.createRootElement();
933 // add children
934 xml::XmlFileWriter writer(doc);
935 writer.write("file.xml", true);
936 @endcode
937 */
938class RT_DECL_CLASS Document
939{
940public:
941 Document();
942 ~Document();
943
944 Document(const Document &x);
945 Document& operator=(const Document &x);
946
947 const ElementNode* getRootElement() const;
948 ElementNode* getRootElement();
949
950 ElementNode* createRootElement(const char *pcszRootElementName,
951 const char *pcszComment = NULL);
952
953private:
954 friend class XmlMemParser;
955 friend class XmlFileParser;
956 friend class XmlMemWriter;
957 friend class XmlStringWriter;
958 friend class XmlFileWriter;
959
960 void refreshInternals();
961
962 /* Obscure class data */
963 struct Data;
964 Data *m;
965};
966
967/*
968 * XmlParserBase
969 *
970 */
971
972class RT_DECL_CLASS XmlParserBase
973{
974protected:
975 XmlParserBase();
976 ~XmlParserBase();
977
978 xmlParserCtxtPtr m_ctxt;
979};
980
981/*
982 * XmlMemParser
983 *
984 */
985
986class RT_DECL_CLASS XmlMemParser : public XmlParserBase
987{
988public:
989 XmlMemParser();
990 ~XmlMemParser();
991
992 void read(const void* pvBuf, size_t cbSize, const RTCString &strFilename, Document &doc);
993};
994
995/*
996 * XmlFileParser
997 *
998 */
999
1000class RT_DECL_CLASS XmlFileParser : public XmlParserBase
1001{
1002public:
1003 XmlFileParser();
1004 ~XmlFileParser();
1005
1006 void read(const RTCString &strFilename, Document &doc);
1007
1008private:
1009 /* Obscure class data */
1010 struct Data;
1011 struct Data *m;
1012
1013 static int ReadCallback(void *aCtxt, char *aBuf, int aLen);
1014 static int CloseCallback (void *aCtxt);
1015};
1016
1017/**
1018 * XmlMemWriter
1019 */
1020class RT_DECL_CLASS XmlMemWriter
1021{
1022public:
1023 XmlMemWriter();
1024 ~XmlMemWriter();
1025
1026 void write(const Document &doc, void** ppvBuf, size_t *pcbSize);
1027
1028private:
1029 void* m_pBuf;
1030};
1031
1032
1033/**
1034 * XmlStringWriter - writes the XML to an RTCString instance.
1035 */
1036class RT_DECL_CLASS XmlStringWriter
1037{
1038public:
1039 XmlStringWriter();
1040
1041 int write(const Document &rDoc, RTCString *pStrDst);
1042
1043private:
1044 static int WriteCallbackForSize(void *pvUser, const char *pachBuf, int cbToWrite);
1045 static int WriteCallbackForReal(void *pvUser, const char *pachBuf, int cbToWrite);
1046 static int CloseCallback(void *pvUser);
1047
1048 /** Pointer to the destination string while we're in the write() call. */
1049 RTCString *m_pStrDst;
1050 /** Set by WriteCallback if we cannot grow the destination string. */
1051 bool m_fOutOfMemory;
1052};
1053
1054
1055/**
1056 * XmlFileWriter
1057 */
1058class RT_DECL_CLASS XmlFileWriter
1059{
1060public:
1061 XmlFileWriter(Document &doc);
1062 ~XmlFileWriter();
1063
1064 /**
1065 * Writes the XML document to the specified file.
1066 *
1067 * @param pcszFilename The name of the output file.
1068 * @param fSafe If @c true, some extra safety precautions will be
1069 * taken when writing the file:
1070 * -# The file is written with a '-tmp' suffix.
1071 * -# It is flushed to disk after writing.
1072 * -# Any original file is renamed to '-prev'.
1073 * -# The '-tmp' file is then renamed to the
1074 * specified name.
1075 * -# The directory changes are flushed to disk.
1076 * The suffixes are available via s_pszTmpSuff and
1077 * s_pszPrevSuff.
1078 */
1079 void write(const char *pcszFilename, bool fSafe);
1080
1081 static int WriteCallback(void *aCtxt, const char *aBuf, int aLen);
1082 static int CloseCallback(void *aCtxt);
1083
1084 /** The suffix used by XmlFileWriter::write() for the temporary file. */
1085 static const char * const s_pszTmpSuff;
1086 /** The suffix used by XmlFileWriter::write() for the previous (backup) file. */
1087 static const char * const s_pszPrevSuff;
1088
1089private:
1090 void writeInternal(const char *pcszFilename, bool fSafe);
1091
1092 /* Obscure class data */
1093 struct Data;
1094 Data *m;
1095};
1096
1097#if defined(_MSC_VER)
1098#pragma warning (default:4251)
1099#endif
1100
1101/** @} */
1102
1103} // end namespace xml
1104
1105#endif /* !___iprt_xml_h */
1106
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette