VirtualBox

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

Last change on this file since 36499 was 36499, checked in by vboxsync, 14 years ago

Doc-IPRT: add a RT C++ group to the docu

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.9 KB
Line 
1/** @file
2 * IPRT - XML Helper APIs.
3 */
4
5/*
6 * Copyright (C) 2007-2011 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.215389.xyz. 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 <list>
34#include <memory>
35
36#include <iprt/cpp/exception.h>
37
38/**
39 * @defgroup grp_rt_cpp_xml C++ XML support
40 * @ingroup grp_rt_cpp
41 * @{
42 */
43
44/* Forwards */
45typedef struct _xmlParserInput xmlParserInput;
46typedef xmlParserInput *xmlParserInputPtr;
47typedef struct _xmlParserCtxt xmlParserCtxt;
48typedef xmlParserCtxt *xmlParserCtxtPtr;
49typedef struct _xmlError xmlError;
50typedef xmlError *xmlErrorPtr;
51
52typedef struct _xmlAttr xmlAttr;
53typedef struct _xmlNode xmlNode;
54
55/** @} */
56
57namespace xml
58{
59
60/**
61 * @addtogroup grp_rt_cpp_xml
62 * @{
63 */
64
65// Exceptions
66//////////////////////////////////////////////////////////////////////////////
67
68class RT_DECL_CLASS LogicError : public iprt::Error
69{
70public:
71
72 LogicError(const char *aMsg = NULL)
73 : iprt::Error(aMsg)
74 {}
75
76 LogicError(RT_SRC_POS_DECL);
77};
78
79class RT_DECL_CLASS RuntimeError : public iprt::Error
80{
81public:
82
83 RuntimeError(const char *aMsg = NULL)
84 : iprt::Error(aMsg)
85 {}
86};
87
88class RT_DECL_CLASS XmlError : public RuntimeError
89{
90public:
91 XmlError(xmlErrorPtr aErr);
92
93 static char* Format(xmlErrorPtr aErr);
94};
95
96// Logical errors
97//////////////////////////////////////////////////////////////////////////////
98
99class RT_DECL_CLASS ENotImplemented : public LogicError
100{
101public:
102 ENotImplemented(const char *aMsg = NULL) : LogicError(aMsg) {}
103 ENotImplemented(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
104};
105
106class RT_DECL_CLASS EInvalidArg : public LogicError
107{
108public:
109 EInvalidArg(const char *aMsg = NULL) : LogicError(aMsg) {}
110 EInvalidArg(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
111};
112
113class RT_DECL_CLASS EDocumentNotEmpty : public LogicError
114{
115public:
116 EDocumentNotEmpty(const char *aMsg = NULL) : LogicError(aMsg) {}
117 EDocumentNotEmpty(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
118};
119
120class RT_DECL_CLASS ENodeIsNotElement : public LogicError
121{
122public:
123 ENodeIsNotElement(const char *aMsg = NULL) : LogicError(aMsg) {}
124 ENodeIsNotElement(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
125};
126
127// Runtime errors
128//////////////////////////////////////////////////////////////////////////////
129
130class RT_DECL_CLASS EIPRTFailure : public RuntimeError
131{
132public:
133
134 EIPRTFailure(int aRC, const char *pcszContext, ...);
135
136 int rc() const
137 {
138 return mRC;
139 }
140
141private:
142 int mRC;
143};
144
145/**
146 * The Stream class is a base class for I/O streams.
147 */
148class RT_DECL_CLASS Stream
149{
150public:
151
152 virtual ~Stream() {}
153
154 virtual const char *uri() const = 0;
155
156 /**
157 * Returns the current read/write position in the stream. The returned
158 * position is a zero-based byte offset from the beginning of the file.
159 *
160 * Throws ENotImplemented if this operation is not implemented for the
161 * given stream.
162 */
163 virtual uint64_t pos() const = 0;
164
165 /**
166 * Sets the current read/write position in the stream.
167 *
168 * @param aPos Zero-based byte offset from the beginning of the stream.
169 *
170 * Throws ENotImplemented if this operation is not implemented for the
171 * given stream.
172 */
173 virtual void setPos (uint64_t aPos) = 0;
174};
175
176/**
177 * The Input class represents an input stream.
178 *
179 * This input stream is used to read the settings tree from.
180 * This is an abstract class that must be subclassed in order to fill it with
181 * useful functionality.
182 */
183class RT_DECL_CLASS Input : virtual public Stream
184{
185public:
186
187 /**
188 * Reads from the stream to the supplied buffer.
189 *
190 * @param aBuf Buffer to store read data to.
191 * @param aLen Buffer length.
192 *
193 * @return Number of bytes read.
194 */
195 virtual int read (char *aBuf, int aLen) = 0;
196};
197
198/**
199 *
200 */
201class RT_DECL_CLASS Output : virtual public Stream
202{
203public:
204
205 /**
206 * Writes to the stream from the supplied buffer.
207 *
208 * @param aBuf Buffer to write data from.
209 * @param aLen Buffer length.
210 *
211 * @return Number of bytes written.
212 */
213 virtual int write (const char *aBuf, int aLen) = 0;
214
215 /**
216 * Truncates the stream from the current position and upto the end.
217 * The new file size will become exactly #pos() bytes.
218 *
219 * Throws ENotImplemented if this operation is not implemented for the
220 * given stream.
221 */
222 virtual void truncate() = 0;
223};
224
225
226//////////////////////////////////////////////////////////////////////////////
227
228/**
229 * The File class is a stream implementation that reads from and writes to
230 * regular files.
231 *
232 * The File class uses IPRT File API for file operations. Note that IPRT File
233 * API is not thread-safe. This means that if you pass the same RTFILE handle to
234 * different File instances that may be simultaneously used on different
235 * threads, you should care about serialization; otherwise you will get garbage
236 * when reading from or writing to such File instances.
237 */
238class RT_DECL_CLASS File : public Input, public Output
239{
240public:
241
242 /**
243 * Possible file access modes.
244 */
245 enum Mode { Mode_Read, Mode_WriteCreate, Mode_Overwrite, Mode_ReadWrite };
246
247 /**
248 * Opens a file with the given name in the given mode. If @a aMode is Read
249 * or ReadWrite, the file must exist. If @a aMode is Write, the file must
250 * not exist. Otherwise, an EIPRTFailure excetion will be thrown.
251 *
252 * @param aMode File mode.
253 * @param aFileName File name.
254 * @param aFlushIt Whether to flush a writable file before closing it.
255 */
256 File(Mode aMode, const char *aFileName, bool aFlushIt = false);
257
258 /**
259 * Uses the given file handle to perform file operations. This file
260 * handle must be already open in necessary mode (read, or write, or mixed).
261 *
262 * The read/write position of the given handle will be reset to the
263 * beginning of the file on success.
264 *
265 * Note that the given file handle will not be automatically closed upon
266 * this object destruction.
267 *
268 * @note It you pass the same RTFILE handle to more than one File instance,
269 * please make sure you have provided serialization in case if these
270 * instasnces are to be simultaneously used by different threads.
271 * Otherwise you may get garbage when reading or writing.
272 *
273 * @param aHandle Open file handle.
274 * @param aFileName File name (for reference).
275 * @param aFlushIt Whether to flush a writable file before closing it.
276 */
277 File(RTFILE aHandle, const char *aFileName = NULL, bool aFlushIt = false);
278
279 /**
280 * Destroys the File object. If the object was created from a file name
281 * the corresponding file will be automatically closed. If the object was
282 * created from a file handle, it will remain open.
283 */
284 virtual ~File();
285
286 const char *uri() const;
287
288 uint64_t pos() const;
289 void setPos(uint64_t aPos);
290
291 /**
292 * See Input::read(). If this method is called in wrong file mode,
293 * LogicError will be thrown.
294 */
295 int read(char *aBuf, int aLen);
296
297 /**
298 * See Output::write(). If this method is called in wrong file mode,
299 * LogicError will be thrown.
300 */
301 int write(const char *aBuf, int aLen);
302
303 /**
304 * See Output::truncate(). If this method is called in wrong file mode,
305 * LogicError will be thrown.
306 */
307 void truncate();
308
309private:
310
311 /* Obscure class data */
312 struct Data;
313 Data *m;
314
315 /* auto_ptr data doesn't have proper copy semantics */
316 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (File)
317};
318
319/**
320 * The MemoryBuf class represents a stream implementation that reads from the
321 * memory buffer.
322 */
323class RT_DECL_CLASS MemoryBuf : public Input
324{
325public:
326
327 MemoryBuf (const char *aBuf, size_t aLen, const char *aURI = NULL);
328
329 virtual ~MemoryBuf();
330
331 const char *uri() const;
332
333 int read(char *aBuf, int aLen);
334 uint64_t pos() const;
335 void setPos(uint64_t aPos);
336
337private:
338 /* Obscure class data */
339 struct Data;
340 Data *m;
341
342 /* auto_ptr data doesn't have proper copy semantics */
343 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(MemoryBuf)
344};
345
346
347/*
348 * GlobalLock
349 *
350 *
351 */
352
353typedef xmlParserInput* FNEXTERNALENTITYLOADER(const char *aURI,
354 const char *aID,
355 xmlParserCtxt *aCtxt);
356typedef FNEXTERNALENTITYLOADER *PFNEXTERNALENTITYLOADER;
357
358class RT_DECL_CLASS GlobalLock
359{
360public:
361 GlobalLock();
362 ~GlobalLock();
363
364 void setExternalEntityLoader(PFNEXTERNALENTITYLOADER pFunc);
365
366 static xmlParserInput* callDefaultLoader(const char *aURI,
367 const char *aID,
368 xmlParserCtxt *aCtxt);
369
370private:
371 /* Obscure class data. */
372 struct Data;
373 struct Data *m;
374};
375
376class ElementNode;
377typedef std::list<const ElementNode*> ElementNodesList;
378
379class AttributeNode;
380
381class ContentNode;
382
383/**
384 * Node base class. Cannot be used directly, but ElementNode, ContentNode and
385 * AttributeNode derive from this. This does implement useful public methods though.
386 */
387class RT_DECL_CLASS Node
388{
389public:
390 ~Node();
391
392 const char* getName() const;
393 bool nameEquals(const char *pcszNamespace, const char *pcsz) const;
394 bool nameEquals(const char *pcsz) const
395 {
396 return nameEquals(NULL, pcsz);
397 }
398
399 const char* getValue() const;
400 bool copyValue(int32_t &i) const;
401 bool copyValue(uint32_t &i) const;
402 bool copyValue(int64_t &i) const;
403 bool copyValue(uint64_t &i) const;
404
405 int getLineNumber() const;
406
407 int isElement() const
408 {
409 return m_Type == IsElement;
410 }
411
412protected:
413 typedef enum {IsElement, IsAttribute, IsContent} EnumType;
414
415 EnumType m_Type;
416 Node *m_pParent;
417 xmlNode *m_plibNode; // != NULL if this is an element or content node
418 xmlAttr *m_plibAttr; // != NULL if this is an attribute node
419 const char *m_pcszNamespacePrefix; // not always set
420 const char *m_pcszNamespaceHref; // full http:// spec
421 const char *m_pcszName; // element or attribute name, points either into plibNode or plibAttr;
422 // NULL if this is a content node
423
424 // hide the default constructor so people use only our factory methods
425 Node(EnumType type,
426 Node *pParent,
427 xmlNode *plibNode,
428 xmlAttr *plibAttr);
429 Node(const Node &x); // no copying
430
431 void buildChildren(const ElementNode &elmRoot);
432
433 /* Obscure class data */
434 struct Data;
435 Data *m;
436
437 friend class AttributeNode;
438};
439
440/**
441 * Node subclass that represents an element.
442 *
443 * For elements, Node::getName() returns the element name, and Node::getValue()
444 * returns the text contents, if any.
445 *
446 * Since the Node constructor is private, one can create element nodes
447 * only through the following factory methods:
448 *
449 * -- Document::createRootElement()
450 * -- ElementNode::createChild()
451 */
452class RT_DECL_CLASS ElementNode : public Node
453{
454public:
455 int getChildElements(ElementNodesList &children,
456 const char *pcszMatch = NULL) const;
457
458 const ElementNode* findChildElement(const char *pcszNamespace,
459 const char *pcszMatch) const;
460 const ElementNode* findChildElement(const char *pcszMatch) const
461 {
462 return findChildElement(NULL, pcszMatch);
463 }
464 const ElementNode* findChildElementFromId(const char *pcszId) const;
465
466 const AttributeNode* findAttribute(const char *pcszMatch) const;
467 bool getAttributeValue(const char *pcszMatch, const char *&ppcsz) const;
468 bool getAttributeValue(const char *pcszMatch, iprt::MiniString &str) const;
469 bool getAttributeValuePath(const char *pcszMatch, iprt::MiniString &str) const;
470 bool getAttributeValue(const char *pcszMatch, int32_t &i) const;
471 bool getAttributeValue(const char *pcszMatch, uint32_t &i) const;
472 bool getAttributeValue(const char *pcszMatch, int64_t &i) const;
473 bool getAttributeValue(const char *pcszMatch, uint64_t &i) const;
474 bool getAttributeValue(const char *pcszMatch, bool &f) const;
475
476 ElementNode* createChild(const char *pcszElementName);
477
478 ContentNode* addContent(const char *pcszContent);
479 ContentNode* addContent(const iprt::MiniString &strContent)
480 {
481 return addContent(strContent.c_str());
482 }
483
484 AttributeNode* setAttribute(const char *pcszName, const char *pcszValue);
485 AttributeNode* setAttribute(const char *pcszName, const iprt::MiniString &strValue)
486 {
487 return setAttribute(pcszName, strValue.c_str());
488 }
489 AttributeNode* setAttributePath(const char *pcszName, const iprt::MiniString &strValue);
490 AttributeNode* setAttribute(const char *pcszName, int32_t i);
491 AttributeNode* setAttribute(const char *pcszName, uint32_t i);
492 AttributeNode* setAttribute(const char *pcszName, int64_t i);
493 AttributeNode* setAttribute(const char *pcszName, uint64_t i);
494 AttributeNode* setAttributeHex(const char *pcszName, uint32_t i);
495 AttributeNode* setAttribute(const char *pcszName, bool f);
496
497protected:
498 // hide the default constructor so people use only our factory methods
499 ElementNode(const ElementNode *pelmRoot, Node *pParent, xmlNode *plibNode);
500 ElementNode(const ElementNode &x); // no copying
501
502 const ElementNode *m_pelmRoot;
503
504 friend class Node;
505 friend class Document;
506 friend class XmlFileParser;
507};
508
509/**
510 * Node subclass that represents content (non-element text).
511 *
512 * Since the Node constructor is private, one can create new content nodes
513 * only through the following factory methods:
514 *
515 * -- ElementNode::addContent()
516 */
517class RT_DECL_CLASS ContentNode : public Node
518{
519public:
520
521protected:
522 // hide the default constructor so people use only our factory methods
523 ContentNode(Node *pParent, xmlNode *plibNode);
524 ContentNode(const ContentNode &x); // no copying
525
526 friend class Node;
527 friend class ElementNode;
528};
529
530/**
531 * Node subclass that represents an attribute of an element.
532 *
533 * For attributes, Node::getName() returns the attribute name, and Node::getValue()
534 * returns the attribute value, if any.
535 *
536 * Since the Node constructor is private, one can create new attribute nodes
537 * only through the following factory methods:
538 *
539 * -- ElementNode::setAttribute()
540 */
541class RT_DECL_CLASS AttributeNode : public Node
542{
543public:
544
545protected:
546 // hide the default constructor so people use only our factory methods
547 AttributeNode(const ElementNode &elmRoot,
548 Node *pParent,
549 xmlAttr *plibAttr,
550 const char **ppcszKey);
551 AttributeNode(const AttributeNode &x); // no copying
552
553 iprt::MiniString m_strKey;
554
555 friend class Node;
556 friend class ElementNode;
557};
558
559/**
560 * Handy helper class with which one can loop through all or some children
561 * of a particular element. See NodesLoop::forAllNodes() for details.
562 */
563class RT_DECL_CLASS NodesLoop
564{
565public:
566 NodesLoop(const ElementNode &node, const char *pcszMatch = NULL);
567 ~NodesLoop();
568 const ElementNode* forAllNodes() const;
569
570private:
571 /* Obscure class data */
572 struct Data;
573 Data *m;
574};
575
576/**
577 * The XML document class. An instance of this needs to be created by a user
578 * of the XML classes and then passed to
579 *
580 * -- XmlMemParser or XmlFileParser to read an XML document; those classes then
581 * fill the caller's Document with ElementNode, ContentNode and AttributeNode
582 * instances. The typical sequence then is:
583 * @code
584 Document doc;
585 XmlFileParser parser;
586 parser.read("file.xml", doc);
587 Element *pelmRoot = doc.getRootElement();
588 @endcode
589 *
590 * -- XmlMemWriter or XmlFileWriter to write out an XML document after it has
591 * been created and filled. Example:
592 *
593 * @code
594 Document doc;
595 Element *pelmRoot = doc.createRootElement();
596 // add children
597 xml::XmlFileWriter writer(doc);
598 writer.write("file.xml", true);
599 @endcode
600 */
601class RT_DECL_CLASS Document
602{
603public:
604 Document();
605 ~Document();
606
607 Document(const Document &x);
608 Document& operator=(const Document &x);
609
610 const ElementNode* getRootElement() const;
611 ElementNode* getRootElement();
612
613 ElementNode* createRootElement(const char *pcszRootElementName,
614 const char *pcszComment = NULL);
615
616private:
617 friend class XmlMemParser;
618 friend class XmlFileParser;
619 friend class XmlMemWriter;
620 friend class XmlFileWriter;
621
622 void refreshInternals();
623
624 /* Obscure class data */
625 struct Data;
626 Data *m;
627};
628
629/*
630 * XmlParserBase
631 *
632 */
633
634class RT_DECL_CLASS XmlParserBase
635{
636protected:
637 XmlParserBase();
638 ~XmlParserBase();
639
640 xmlParserCtxtPtr m_ctxt;
641};
642
643/*
644 * XmlMemParser
645 *
646 */
647
648class RT_DECL_CLASS XmlMemParser : public XmlParserBase
649{
650public:
651 XmlMemParser();
652 ~XmlMemParser();
653
654 void read(const void* pvBuf, size_t cbSize, const iprt::MiniString &strFilename, Document &doc);
655};
656
657/*
658 * XmlFileParser
659 *
660 */
661
662class RT_DECL_CLASS XmlFileParser : public XmlParserBase
663{
664public:
665 XmlFileParser();
666 ~XmlFileParser();
667
668 void read(const iprt::MiniString &strFilename, Document &doc);
669
670private:
671 /* Obscure class data */
672 struct Data;
673 struct Data *m;
674
675 static int ReadCallback(void *aCtxt, char *aBuf, int aLen);
676 static int CloseCallback (void *aCtxt);
677};
678
679/*
680 * XmlMemParser
681 *
682 */
683
684class RT_DECL_CLASS XmlMemWriter
685{
686public:
687 XmlMemWriter();
688 ~XmlMemWriter();
689
690 void write(const Document &doc, void** ppvBuf, size_t *pcbSize);
691
692private:
693 void* m_pBuf;
694};
695
696/*
697 * XmlFileWriter
698 *
699 */
700
701class RT_DECL_CLASS XmlFileWriter
702{
703public:
704 XmlFileWriter(Document &doc);
705 ~XmlFileWriter();
706
707 /**
708 * Writes the XML document to the specified file.
709 *
710 * @param pcszFilename The name of the output file.
711 * @param fSafe If @c true, some extra safety precautions will be
712 * taken when writing the file:
713 * -# The file is written with a '-tmp' suffix.
714 * -# It is flushed to disk after writing.
715 * -# Any original file is renamed to '-prev'.
716 * -# The '-tmp' file is then renamed to the
717 * specified name.
718 * -# The directory changes are flushed to disk.
719 * The suffixes are available via s_pszTmpSuff and
720 * s_pszPrevSuff.
721 */
722 void write(const char *pcszFilename, bool fSafe);
723
724 static int WriteCallback(void *aCtxt, const char *aBuf, int aLen);
725 static int CloseCallback(void *aCtxt);
726
727 /** The suffix used by XmlFileWriter::write() for the temporary file. */
728 static const char * const s_pszTmpSuff;
729 /** The suffix used by XmlFileWriter::write() for the previous (backup) file. */
730 static const char * const s_pszPrevSuff;
731
732private:
733 void writeInternal(const char *pcszFilename, bool fSafe);
734
735 /* Obscure class data */
736 struct Data;
737 Data *m;
738};
739
740#if defined(_MSC_VER)
741#pragma warning (default:4251)
742#endif
743
744/** @} */
745
746} // end namespace xml
747
748#endif /* !___iprt_xml_h */
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