VirtualBox

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

Last change on this file since 79569 was 79569, checked in by vboxsync, 6 years ago

iprt/cpp/xml.h: Added more optimial helper for getting attributes of immediate children. bugref:9288

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

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