VirtualBox

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

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

Main: clean up spaghetti code in Console::configConstructor(): remove RC_CHECK() macro and delegate error handling to a few shared functions; move XML exceptions to separate header in IPRT to allow for reuse

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.6 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
363/**
364 * Node:
365 * an XML node, which represents either an element or text content
366 * or an attribute.
367 *
368 * For elements, getName() returns the element name, and getValue()
369 * returns the text contents, if any.
370 *
371 * For attributes, getName() returns the attribute name, and getValue()
372 * returns the attribute value, if any.
373 *
374 * Since the default constructor is private, one can create new nodes
375 * only through factory methods provided by the XML classes. These are:
376 *
377 * -- xml::Document::createRootElement()
378 * -- xml::Node::createChild()
379 * -- xml::Node::addContent()
380 * -- xml::Node::setAttribute()
381 */
382
383class ElementNode;
384typedef std::list<const ElementNode*> ElementNodesList;
385
386class AttributeNode;
387
388class ContentNode;
389
390class RT_DECL_CLASS Node
391{
392public:
393 ~Node();
394
395 const char* getName() const;
396 bool nameEquals(const char *pcszNamespace, const char *pcsz) const;
397 bool nameEquals(const char *pcsz) const
398 {
399 return nameEquals(NULL, pcsz);
400 }
401
402 const char* getValue() const;
403 bool copyValue(int32_t &i) const;
404 bool copyValue(uint32_t &i) const;
405 bool copyValue(int64_t &i) const;
406 bool copyValue(uint64_t &i) const;
407
408 int getLineNumber() const;
409
410 int isElement() const
411 {
412 return m_Type == IsElement;
413 }
414
415protected:
416 typedef enum {IsElement, IsAttribute, IsContent} EnumType;
417
418 EnumType m_Type;
419 Node *m_pParent;
420 xmlNode *m_plibNode; // != NULL if this is an element or content node
421 xmlAttr *m_plibAttr; // != NULL if this is an attribute node
422 const char *m_pcszNamespacePrefix; // not always set
423 const char *m_pcszNamespaceHref; // full http:// spec
424 const char *m_pcszName; // element or attribute name, points either into plibNode or plibAttr;
425 // NULL if this is a content node
426
427 // hide the default constructor so people use only our factory methods
428 Node(EnumType type,
429 Node *pParent,
430 xmlNode *plibNode,
431 xmlAttr *plibAttr);
432 Node(const Node &x); // no copying
433
434 void buildChildren(const ElementNode &elmRoot);
435
436 /* Obscure class data */
437 struct Data;
438 Data *m;
439
440 friend class AttributeNode;
441};
442
443class RT_DECL_CLASS ElementNode : public Node
444{
445public:
446 int getChildElements(ElementNodesList &children,
447 const char *pcszMatch = NULL) const;
448
449 const ElementNode* findChildElement(const char *pcszNamespace,
450 const char *pcszMatch) const;
451 const ElementNode* findChildElement(const char *pcszMatch) const
452 {
453 return findChildElement(NULL, pcszMatch);
454 }
455 const ElementNode* findChildElementFromId(const char *pcszId) const;
456
457 const AttributeNode* findAttribute(const char *pcszMatch) const;
458 bool getAttributeValue(const char *pcszMatch, const char *&ppcsz) const;
459 bool getAttributeValue(const char *pcszMatch, iprt::MiniString &str) const;
460 bool getAttributeValue(const char *pcszMatch, int32_t &i) const;
461 bool getAttributeValue(const char *pcszMatch, uint32_t &i) const;
462 bool getAttributeValue(const char *pcszMatch, int64_t &i) const;
463 bool getAttributeValue(const char *pcszMatch, uint64_t &i) const;
464 bool getAttributeValue(const char *pcszMatch, bool &f) const;
465
466 ElementNode* createChild(const char *pcszElementName);
467
468 ContentNode* addContent(const char *pcszContent);
469 ContentNode* addContent(const iprt::MiniString &strContent)
470 {
471 return addContent(strContent.c_str());
472 }
473
474 AttributeNode* setAttribute(const char *pcszName, const char *pcszValue);
475 AttributeNode* setAttribute(const char *pcszName, const iprt::MiniString &strValue)
476 {
477 return setAttribute(pcszName, strValue.c_str());
478 }
479 AttributeNode* setAttribute(const char *pcszName, int32_t i);
480 AttributeNode* setAttribute(const char *pcszName, uint32_t i);
481 AttributeNode* setAttribute(const char *pcszName, int64_t i);
482 AttributeNode* setAttribute(const char *pcszName, uint64_t i);
483 AttributeNode* setAttributeHex(const char *pcszName, uint32_t i);
484 AttributeNode* setAttribute(const char *pcszName, bool f);
485
486protected:
487 // hide the default constructor so people use only our factory methods
488 ElementNode(const ElementNode *pelmRoot, Node *pParent, xmlNode *plibNode);
489 ElementNode(const ElementNode &x); // no copying
490
491 const ElementNode *m_pelmRoot;
492
493 friend class Node;
494 friend class Document;
495 friend class XmlFileParser;
496};
497
498class RT_DECL_CLASS ContentNode : public Node
499{
500public:
501
502protected:
503 // hide the default constructor so people use only our factory methods
504 ContentNode(Node *pParent, xmlNode *plibNode);
505 ContentNode(const ContentNode &x); // no copying
506
507 friend class Node;
508 friend class ElementNode;
509};
510
511class RT_DECL_CLASS AttributeNode : public Node
512{
513public:
514
515protected:
516 // hide the default constructor so people use only our factory methods
517 AttributeNode(const ElementNode &elmRoot,
518 Node *pParent,
519 xmlAttr *plibAttr,
520 const char **ppcszKey);
521 AttributeNode(const AttributeNode &x); // no copying
522
523 iprt::MiniString m_strKey;
524
525 friend class Node;
526 friend class ElementNode;
527};
528
529/*
530 * NodesLoop
531 *
532 */
533
534class RT_DECL_CLASS NodesLoop
535{
536public:
537 NodesLoop(const ElementNode &node, const char *pcszMatch = NULL);
538 ~NodesLoop();
539 const ElementNode* forAllNodes() const;
540
541private:
542 /* Obscure class data */
543 struct Data;
544 Data *m;
545};
546
547/*
548 * Document
549 *
550 */
551
552class RT_DECL_CLASS Document
553{
554public:
555 Document();
556 ~Document();
557
558 Document(const Document &x);
559 Document& operator=(const Document &x);
560
561 const ElementNode* getRootElement() const;
562 ElementNode* getRootElement();
563
564 ElementNode* createRootElement(const char *pcszRootElementName);
565
566private:
567 friend class XmlFileParser;
568 friend class XmlFileWriter;
569
570 void refreshInternals();
571
572 /* Obscure class data */
573 struct Data;
574 Data *m;
575};
576
577/*
578 * XmlParserBase
579 *
580 */
581
582class RT_DECL_CLASS XmlParserBase
583{
584protected:
585 XmlParserBase();
586 ~XmlParserBase();
587
588 xmlParserCtxtPtr m_ctxt;
589};
590
591/*
592 * XmlFileParser
593 *
594 */
595
596class RT_DECL_CLASS XmlFileParser : public XmlParserBase
597{
598public:
599 XmlFileParser();
600 ~XmlFileParser();
601
602 void read(const iprt::MiniString &strFilename, Document &doc);
603
604private:
605 /* Obscure class data */
606 struct Data;
607 struct Data *m;
608
609 static int ReadCallback(void *aCtxt, char *aBuf, int aLen);
610 static int CloseCallback (void *aCtxt);
611};
612
613/*
614 * XmlFileWriter
615 *
616 */
617
618class RT_DECL_CLASS XmlFileWriter
619{
620public:
621 XmlFileWriter(Document &doc);
622 ~XmlFileWriter();
623
624 /**
625 * Writes the XML document to the specified file.
626 *
627 * @param pcszFilename The name of the output file.
628 * @param fSafe If @c true, some extra safety precautions will be
629 * taken when writing the file:
630 * -# The file is written with a '-tmp' suffix.
631 * -# It is flushed to disk after writing.
632 * -# Any original file is renamed to '-prev'.
633 * -# The '-tmp' file is then renamed to the
634 * specified name.
635 * -# The directory changes are flushed to disk.
636 * The suffixes are available via s_pszTmpSuff and
637 * s_pszPrevSuff.
638 */
639 void write(const char *pcszFilename, bool fSafe);
640
641 static int WriteCallback(void *aCtxt, const char *aBuf, int aLen);
642 static int CloseCallback(void *aCtxt);
643
644 /** The suffix used by XmlFileWriter::write() for the temporary file. */
645 static const char * const s_pszTmpSuff;
646 /** The suffix used by XmlFileWriter::write() for the previous (backup) file. */
647 static const char * const s_pszPrevSuff;
648
649private:
650 void writeInternal(const char *pcszFilename, bool fSafe);
651
652 /* Obscure class data */
653 struct Data;
654 Data *m;
655};
656
657#if defined(_MSC_VER)
658#pragma warning (default:4251)
659#endif
660
661/** @} */
662
663} // end namespace xml
664
665#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