VirtualBox

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

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

Main;Runtime: fix memory freeing returned by libxml2

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