VirtualBox

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

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

iprt::MiniString -> RTCString.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.8 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 bool nameEquals(const char *pcszNamespace, const char *pcsz) const;
393 bool nameEquals(const char *pcsz) const
394 {
395 return nameEquals(NULL, pcsz);
396 }
397
398 const char* getValue() const;
399 bool copyValue(int32_t &i) const;
400 bool copyValue(uint32_t &i) const;
401 bool copyValue(int64_t &i) const;
402 bool copyValue(uint64_t &i) const;
403
404 int getLineNumber() const;
405
406 int isElement() const
407 {
408 return m_Type == IsElement;
409 }
410
411protected:
412 typedef enum {IsElement, IsAttribute, IsContent} EnumType;
413
414 EnumType m_Type;
415 Node *m_pParent;
416 xmlNode *m_plibNode; // != NULL if this is an element or content node
417 xmlAttr *m_plibAttr; // != NULL if this is an attribute node
418 const char *m_pcszNamespacePrefix; // not always set
419 const char *m_pcszNamespaceHref; // full http:// spec
420 const char *m_pcszName; // element or attribute name, points either into plibNode or plibAttr;
421 // NULL if this is a content node
422
423 // hide the default constructor so people use only our factory methods
424 Node(EnumType type,
425 Node *pParent,
426 xmlNode *plibNode,
427 xmlAttr *plibAttr);
428 Node(const Node &x); // no copying
429
430 void buildChildren(const ElementNode &elmRoot);
431
432 /* Obscure class data */
433 struct Data;
434 Data *m;
435
436 friend class AttributeNode;
437};
438
439/**
440 * Node subclass that represents an element.
441 *
442 * For elements, Node::getName() returns the element name, and Node::getValue()
443 * returns the text contents, if any.
444 *
445 * Since the Node constructor is private, one can create element nodes
446 * only through the following factory methods:
447 *
448 * -- Document::createRootElement()
449 * -- ElementNode::createChild()
450 */
451class RT_DECL_CLASS ElementNode : public Node
452{
453public:
454 int getChildElements(ElementNodesList &children,
455 const char *pcszMatch = NULL) const;
456
457 const ElementNode* findChildElement(const char *pcszNamespace,
458 const char *pcszMatch) const;
459 const ElementNode* findChildElement(const char *pcszMatch) const
460 {
461 return findChildElement(NULL, pcszMatch);
462 }
463 const ElementNode* findChildElementFromId(const char *pcszId) const;
464
465 const AttributeNode* findAttribute(const char *pcszMatch) const;
466 bool getAttributeValue(const char *pcszMatch, const char *&ppcsz) const;
467 bool getAttributeValue(const char *pcszMatch, RTCString &str) const;
468 bool getAttributeValuePath(const char *pcszMatch, RTCString &str) const;
469 bool getAttributeValue(const char *pcszMatch, int32_t &i) const;
470 bool getAttributeValue(const char *pcszMatch, uint32_t &i) const;
471 bool getAttributeValue(const char *pcszMatch, int64_t &i) const;
472 bool getAttributeValue(const char *pcszMatch, uint64_t &i) const;
473 bool getAttributeValue(const char *pcszMatch, bool &f) const;
474
475 ElementNode* createChild(const char *pcszElementName);
476
477 ContentNode* addContent(const char *pcszContent);
478 ContentNode* addContent(const RTCString &strContent)
479 {
480 return addContent(strContent.c_str());
481 }
482
483 AttributeNode* setAttribute(const char *pcszName, const char *pcszValue);
484 AttributeNode* setAttribute(const char *pcszName, const RTCString &strValue)
485 {
486 return setAttribute(pcszName, strValue.c_str());
487 }
488 AttributeNode* setAttributePath(const char *pcszName, const RTCString &strValue);
489 AttributeNode* setAttribute(const char *pcszName, int32_t i);
490 AttributeNode* setAttribute(const char *pcszName, uint32_t i);
491 AttributeNode* setAttribute(const char *pcszName, int64_t i);
492 AttributeNode* setAttribute(const char *pcszName, uint64_t i);
493 AttributeNode* setAttributeHex(const char *pcszName, uint32_t i);
494 AttributeNode* setAttribute(const char *pcszName, bool f);
495
496protected:
497 // hide the default constructor so people use only our factory methods
498 ElementNode(const ElementNode *pelmRoot, Node *pParent, xmlNode *plibNode);
499 ElementNode(const ElementNode &x); // no copying
500
501 const ElementNode *m_pelmRoot;
502
503 friend class Node;
504 friend class Document;
505 friend class XmlFileParser;
506};
507
508/**
509 * Node subclass that represents content (non-element text).
510 *
511 * Since the Node constructor is private, one can create new content nodes
512 * only through the following factory methods:
513 *
514 * -- ElementNode::addContent()
515 */
516class RT_DECL_CLASS ContentNode : public Node
517{
518public:
519
520protected:
521 // hide the default constructor so people use only our factory methods
522 ContentNode(Node *pParent, xmlNode *plibNode);
523 ContentNode(const ContentNode &x); // no copying
524
525 friend class Node;
526 friend class ElementNode;
527};
528
529/**
530 * Node subclass that represents an attribute of an element.
531 *
532 * For attributes, Node::getName() returns the attribute name, and Node::getValue()
533 * returns the attribute value, if any.
534 *
535 * Since the Node constructor is private, one can create new attribute nodes
536 * only through the following factory methods:
537 *
538 * -- ElementNode::setAttribute()
539 */
540class RT_DECL_CLASS AttributeNode : public Node
541{
542public:
543
544protected:
545 // hide the default constructor so people use only our factory methods
546 AttributeNode(const ElementNode &elmRoot,
547 Node *pParent,
548 xmlAttr *plibAttr,
549 const char **ppcszKey);
550 AttributeNode(const AttributeNode &x); // no copying
551
552 RTCString m_strKey;
553
554 friend class Node;
555 friend class ElementNode;
556};
557
558/**
559 * Handy helper class with which one can loop through all or some children
560 * of a particular element. See NodesLoop::forAllNodes() for details.
561 */
562class RT_DECL_CLASS NodesLoop
563{
564public:
565 NodesLoop(const ElementNode &node, const char *pcszMatch = NULL);
566 ~NodesLoop();
567 const ElementNode* forAllNodes() const;
568
569private:
570 /* Obscure class data */
571 struct Data;
572 Data *m;
573};
574
575/**
576 * The XML document class. An instance of this needs to be created by a user
577 * of the XML classes and then passed to
578 *
579 * -- XmlMemParser or XmlFileParser to read an XML document; those classes then
580 * fill the caller's Document with ElementNode, ContentNode and AttributeNode
581 * instances. The typical sequence then is:
582 * @code
583 Document doc;
584 XmlFileParser parser;
585 parser.read("file.xml", doc);
586 Element *pelmRoot = doc.getRootElement();
587 @endcode
588 *
589 * -- XmlMemWriter or XmlFileWriter to write out an XML document after it has
590 * been created and filled. Example:
591 *
592 * @code
593 Document doc;
594 Element *pelmRoot = doc.createRootElement();
595 // add children
596 xml::XmlFileWriter writer(doc);
597 writer.write("file.xml", true);
598 @endcode
599 */
600class RT_DECL_CLASS Document
601{
602public:
603 Document();
604 ~Document();
605
606 Document(const Document &x);
607 Document& operator=(const Document &x);
608
609 const ElementNode* getRootElement() const;
610 ElementNode* getRootElement();
611
612 ElementNode* createRootElement(const char *pcszRootElementName,
613 const char *pcszComment = NULL);
614
615private:
616 friend class XmlMemParser;
617 friend class XmlFileParser;
618 friend class XmlMemWriter;
619 friend class XmlFileWriter;
620
621 void refreshInternals();
622
623 /* Obscure class data */
624 struct Data;
625 Data *m;
626};
627
628/*
629 * XmlParserBase
630 *
631 */
632
633class RT_DECL_CLASS XmlParserBase
634{
635protected:
636 XmlParserBase();
637 ~XmlParserBase();
638
639 xmlParserCtxtPtr m_ctxt;
640};
641
642/*
643 * XmlMemParser
644 *
645 */
646
647class RT_DECL_CLASS XmlMemParser : public XmlParserBase
648{
649public:
650 XmlMemParser();
651 ~XmlMemParser();
652
653 void read(const void* pvBuf, size_t cbSize, const RTCString &strFilename, Document &doc);
654};
655
656/*
657 * XmlFileParser
658 *
659 */
660
661class RT_DECL_CLASS XmlFileParser : public XmlParserBase
662{
663public:
664 XmlFileParser();
665 ~XmlFileParser();
666
667 void read(const RTCString &strFilename, Document &doc);
668
669private:
670 /* Obscure class data */
671 struct Data;
672 struct Data *m;
673
674 static int ReadCallback(void *aCtxt, char *aBuf, int aLen);
675 static int CloseCallback (void *aCtxt);
676};
677
678/*
679 * XmlMemParser
680 *
681 */
682
683class RT_DECL_CLASS XmlMemWriter
684{
685public:
686 XmlMemWriter();
687 ~XmlMemWriter();
688
689 void write(const Document &doc, void** ppvBuf, size_t *pcbSize);
690
691private:
692 void* m_pBuf;
693};
694
695/*
696 * XmlFileWriter
697 *
698 */
699
700class RT_DECL_CLASS XmlFileWriter
701{
702public:
703 XmlFileWriter(Document &doc);
704 ~XmlFileWriter();
705
706 /**
707 * Writes the XML document to the specified file.
708 *
709 * @param pcszFilename The name of the output file.
710 * @param fSafe If @c true, some extra safety precautions will be
711 * taken when writing the file:
712 * -# The file is written with a '-tmp' suffix.
713 * -# It is flushed to disk after writing.
714 * -# Any original file is renamed to '-prev'.
715 * -# The '-tmp' file is then renamed to the
716 * specified name.
717 * -# The directory changes are flushed to disk.
718 * The suffixes are available via s_pszTmpSuff and
719 * s_pszPrevSuff.
720 */
721 void write(const char *pcszFilename, bool fSafe);
722
723 static int WriteCallback(void *aCtxt, const char *aBuf, int aLen);
724 static int CloseCallback(void *aCtxt);
725
726 /** The suffix used by XmlFileWriter::write() for the temporary file. */
727 static const char * const s_pszTmpSuff;
728 /** The suffix used by XmlFileWriter::write() for the previous (backup) file. */
729 static const char * const s_pszPrevSuff;
730
731private:
732 void writeInternal(const char *pcszFilename, bool fSafe);
733
734 /* Obscure class data */
735 struct Data;
736 Data *m;
737};
738
739#if defined(_MSC_VER)
740#pragma warning (default:4251)
741#endif
742
743/** @} */
744
745} // end namespace xml
746
747#endif /* !___iprt_xml_h */
748
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