VirtualBox

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

Last change on this file since 43902 was 43902, checked in by vboxsync, 12 years ago

IPRT/xml: Add getPrefix() method to get a prefix a xml node (pref:name returns pref as the prefix)

  • 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.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 <list>
34#include <memory>
35
36#include <iprt/cpp/exception.h>
37
38/** @defgroup grp_rt_cpp_xml C++ XML support
39 * @ingroup grp_rt_cpp
40 * @{
41 */
42
43/* Forwards */
44typedef struct _xmlParserInput xmlParserInput;
45typedef xmlParserInput *xmlParserInputPtr;
46typedef struct _xmlParserCtxt xmlParserCtxt;
47typedef xmlParserCtxt *xmlParserCtxtPtr;
48typedef struct _xmlError xmlError;
49typedef xmlError *xmlErrorPtr;
50
51typedef struct _xmlAttr xmlAttr;
52typedef struct _xmlNode xmlNode;
53
54/** @} */
55
56namespace xml
57{
58
59/**
60 * @addtogroup grp_rt_cpp_xml
61 * @{
62 */
63
64// Exceptions
65//////////////////////////////////////////////////////////////////////////////
66
67class RT_DECL_CLASS LogicError : public RTCError
68{
69public:
70
71 LogicError(const char *aMsg = NULL)
72 : RTCError(aMsg)
73 {}
74
75 LogicError(RT_SRC_POS_DECL);
76};
77
78class RT_DECL_CLASS RuntimeError : public RTCError
79{
80public:
81
82 RuntimeError(const char *aMsg = NULL)
83 : RTCError(aMsg)
84 {}
85};
86
87class RT_DECL_CLASS XmlError : public RuntimeError
88{
89public:
90 XmlError(xmlErrorPtr aErr);
91
92 static char* Format(xmlErrorPtr aErr);
93};
94
95// Logical errors
96//////////////////////////////////////////////////////////////////////////////
97
98class RT_DECL_CLASS ENotImplemented : public LogicError
99{
100public:
101 ENotImplemented(const char *aMsg = NULL) : LogicError(aMsg) {}
102 ENotImplemented(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
103};
104
105class RT_DECL_CLASS EInvalidArg : public LogicError
106{
107public:
108 EInvalidArg(const char *aMsg = NULL) : LogicError(aMsg) {}
109 EInvalidArg(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
110};
111
112class RT_DECL_CLASS EDocumentNotEmpty : public LogicError
113{
114public:
115 EDocumentNotEmpty(const char *aMsg = NULL) : LogicError(aMsg) {}
116 EDocumentNotEmpty(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
117};
118
119class RT_DECL_CLASS ENodeIsNotElement : public LogicError
120{
121public:
122 ENodeIsNotElement(const char *aMsg = NULL) : LogicError(aMsg) {}
123 ENodeIsNotElement(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
124};
125
126// Runtime errors
127//////////////////////////////////////////////////////////////////////////////
128
129class RT_DECL_CLASS EIPRTFailure : public RuntimeError
130{
131public:
132
133 EIPRTFailure(int aRC, const char *pcszContext, ...);
134
135 int rc() const
136 {
137 return mRC;
138 }
139
140private:
141 int mRC;
142};
143
144/**
145 * The Stream class is a base class for I/O streams.
146 */
147class RT_DECL_CLASS Stream
148{
149public:
150
151 virtual ~Stream() {}
152
153 virtual const char *uri() const = 0;
154
155 /**
156 * Returns the current read/write position in the stream. The returned
157 * position is a zero-based byte offset from the beginning of the file.
158 *
159 * Throws ENotImplemented if this operation is not implemented for the
160 * given stream.
161 */
162 virtual uint64_t pos() const = 0;
163
164 /**
165 * Sets the current read/write position in the stream.
166 *
167 * @param aPos Zero-based byte offset from the beginning of the stream.
168 *
169 * Throws ENotImplemented if this operation is not implemented for the
170 * given stream.
171 */
172 virtual void setPos (uint64_t aPos) = 0;
173};
174
175/**
176 * The Input class represents an input stream.
177 *
178 * This input stream is used to read the settings tree from.
179 * This is an abstract class that must be subclassed in order to fill it with
180 * useful functionality.
181 */
182class RT_DECL_CLASS Input : virtual public Stream
183{
184public:
185
186 /**
187 * Reads from the stream to the supplied buffer.
188 *
189 * @param aBuf Buffer to store read data to.
190 * @param aLen Buffer length.
191 *
192 * @return Number of bytes read.
193 */
194 virtual int read (char *aBuf, int aLen) = 0;
195};
196
197/**
198 *
199 */
200class RT_DECL_CLASS Output : virtual public Stream
201{
202public:
203
204 /**
205 * Writes to the stream from the supplied buffer.
206 *
207 * @param aBuf Buffer to write data from.
208 * @param aLen Buffer length.
209 *
210 * @return Number of bytes written.
211 */
212 virtual int write (const char *aBuf, int aLen) = 0;
213
214 /**
215 * Truncates the stream from the current position and upto the end.
216 * The new file size will become exactly #pos() bytes.
217 *
218 * Throws ENotImplemented if this operation is not implemented for the
219 * given stream.
220 */
221 virtual void truncate() = 0;
222};
223
224
225//////////////////////////////////////////////////////////////////////////////
226
227/**
228 * The File class is a stream implementation that reads from and writes to
229 * regular files.
230 *
231 * The File class uses IPRT File API for file operations. Note that IPRT File
232 * API is not thread-safe. This means that if you pass the same RTFILE handle to
233 * different File instances that may be simultaneously used on different
234 * threads, you should care about serialization; otherwise you will get garbage
235 * when reading from or writing to such File instances.
236 */
237class RT_DECL_CLASS File : public Input, public Output
238{
239public:
240
241 /**
242 * Possible file access modes.
243 */
244 enum Mode { Mode_Read, Mode_WriteCreate, Mode_Overwrite, Mode_ReadWrite };
245
246 /**
247 * Opens a file with the given name in the given mode. If @a aMode is Read
248 * or ReadWrite, the file must exist. If @a aMode is Write, the file must
249 * not exist. Otherwise, an EIPRTFailure excetion will be thrown.
250 *
251 * @param aMode File mode.
252 * @param aFileName File name.
253 * @param aFlushIt Whether to flush a writable file before closing it.
254 */
255 File(Mode aMode, const char *aFileName, bool aFlushIt = false);
256
257 /**
258 * Uses the given file handle to perform file operations. This file
259 * handle must be already open in necessary mode (read, or write, or mixed).
260 *
261 * The read/write position of the given handle will be reset to the
262 * beginning of the file on success.
263 *
264 * Note that the given file handle will not be automatically closed upon
265 * this object destruction.
266 *
267 * @note It you pass the same RTFILE handle to more than one File instance,
268 * please make sure you have provided serialization in case if these
269 * instasnces are to be simultaneously used by different threads.
270 * Otherwise you may get garbage when reading or writing.
271 *
272 * @param aHandle Open file handle.
273 * @param aFileName File name (for reference).
274 * @param aFlushIt Whether to flush a writable file before closing it.
275 */
276 File(RTFILE aHandle, const char *aFileName = NULL, bool aFlushIt = false);
277
278 /**
279 * Destroys the File object. If the object was created from a file name
280 * the corresponding file will be automatically closed. If the object was
281 * created from a file handle, it will remain open.
282 */
283 virtual ~File();
284
285 const char *uri() const;
286
287 uint64_t pos() const;
288 void setPos(uint64_t aPos);
289
290 /**
291 * See Input::read(). If this method is called in wrong file mode,
292 * LogicError will be thrown.
293 */
294 int read(char *aBuf, int aLen);
295
296 /**
297 * See Output::write(). If this method is called in wrong file mode,
298 * LogicError will be thrown.
299 */
300 int write(const char *aBuf, int aLen);
301
302 /**
303 * See Output::truncate(). If this method is called in wrong file mode,
304 * LogicError will be thrown.
305 */
306 void truncate();
307
308private:
309
310 /* Obscure class data */
311 struct Data;
312 Data *m;
313
314 /* auto_ptr data doesn't have proper copy semantics */
315 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (File)
316};
317
318/**
319 * The MemoryBuf class represents a stream implementation that reads from the
320 * memory buffer.
321 */
322class RT_DECL_CLASS MemoryBuf : public Input
323{
324public:
325
326 MemoryBuf (const char *aBuf, size_t aLen, const char *aURI = NULL);
327
328 virtual ~MemoryBuf();
329
330 const char *uri() const;
331
332 int read(char *aBuf, int aLen);
333 uint64_t pos() const;
334 void setPos(uint64_t aPos);
335
336private:
337 /* Obscure class data */
338 struct Data;
339 Data *m;
340
341 /* auto_ptr data doesn't have proper copy semantics */
342 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(MemoryBuf)
343};
344
345
346/*
347 * GlobalLock
348 *
349 *
350 */
351
352typedef xmlParserInput* FNEXTERNALENTITYLOADER(const char *aURI,
353 const char *aID,
354 xmlParserCtxt *aCtxt);
355typedef FNEXTERNALENTITYLOADER *PFNEXTERNALENTITYLOADER;
356
357class RT_DECL_CLASS GlobalLock
358{
359public:
360 GlobalLock();
361 ~GlobalLock();
362
363 void setExternalEntityLoader(PFNEXTERNALENTITYLOADER pFunc);
364
365 static xmlParserInput* callDefaultLoader(const char *aURI,
366 const char *aID,
367 xmlParserCtxt *aCtxt);
368
369private:
370 /* Obscure class data. */
371 struct Data;
372 struct Data *m;
373};
374
375class ElementNode;
376typedef std::list<const ElementNode*> ElementNodesList;
377
378class AttributeNode;
379
380class ContentNode;
381
382/**
383 * Node base class. Cannot be used directly, but ElementNode, ContentNode and
384 * AttributeNode derive from this. This does implement useful public methods though.
385 */
386class RT_DECL_CLASS Node
387{
388public:
389 ~Node();
390
391 const char* getName() const;
392 const char* getPrefix() 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, RTCString &str) const;
469 bool getAttributeValuePath(const char *pcszMatch, RTCString &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 RTCString &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 RTCString &strValue)
486 {
487 return setAttribute(pcszName, strValue.c_str());
488 }
489 AttributeNode* setAttributePath(const char *pcszName, const RTCString &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 RTCString 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 RTCString &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 RTCString &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 */
749
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