VirtualBox

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

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

iprt: XmlFileWrite - expose the two suffixes write() uses when fSafe is set.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette