VirtualBox

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

Last change on this file since 30254 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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