VirtualBox

source: vbox/trunk/src/VBox/Main/xml/xml.cpp@ 16210

Last change on this file since 16210 was 16188, checked in by vboxsync, 16 years ago

Merge OVF branch.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.5 KB
Line 
1/** @file
2 * VirtualBox XML Manipulation API.
3 */
4
5/*
6 * Copyright (C) 2007-2008 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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
17 * Clara, CA 95054 USA or visit http://www.sun.com if you need
18 * additional information or have any questions.
19 */
20
21#include "Logging.h"
22
23#include <iprt/err.h>
24#include <iprt/file.h>
25#include <iprt/lock.h>
26#include <iprt/string.h>
27
28#include <libxml/tree.h>
29#include <libxml/parser.h>
30#include <libxml/globals.h>
31#include <libxml/xmlIO.h>
32#include <libxml/xmlsave.h>
33#include <libxml/uri.h>
34
35#include <libxml/xmlschemas.h>
36
37#include <string>
38#include <list>
39#include <map>
40
41#include "boost/shared_ptr.hpp"
42
43#include "VBox/xml.h"
44
45
46/**
47 * Global module initialization structure. This is to wrap non-reentrant bits
48 * of libxml, among other things.
49 *
50 * The constructor and destructor of this structure are used to perform global
51 * module initiaizaton and cleanup. Thee must be only one global variable of
52 * this structure.
53 */
54static
55class Global
56{
57public:
58
59 Global()
60 {
61 /* Check the parser version. The docs say it will kill the app if
62 * there is a serious version mismatch, but I couldn't find it in the
63 * source code (it only prints the error/warning message to the console) so
64 * let's leave it as is for informational purposes. */
65 LIBXML_TEST_VERSION
66
67 /* Init libxml */
68 xmlInitParser();
69
70 /* Save the default entity resolver before someone has replaced it */
71 sxml.defaultEntityLoader = xmlGetExternalEntityLoader();
72 }
73
74 ~Global()
75 {
76 /* Shutdown libxml */
77 xmlCleanupParser();
78 }
79
80 struct
81 {
82 xmlExternalEntityLoader defaultEntityLoader;
83
84 /** Used to provide some thread safety missing in libxml2 (see e.g.
85 * XmlTreeBackend::read()) */
86 RTLockMtx lock;
87 }
88 sxml; /* XXX naming this xml will break with gcc-3.3 */
89}
90gGlobal;
91
92
93
94namespace xml
95{
96
97//////////////////////////////////////////////////////////////////////////////
98// Exceptions
99//////////////////////////////////////////////////////////////////////////////
100
101LogicError::LogicError(RT_SRC_POS_DECL)
102 : Error(NULL)
103{
104 char *msg = NULL;
105 RTStrAPrintf(&msg, "In '%s', '%s' at #%d",
106 pszFunction, pszFile, iLine);
107 setWhat(msg);
108 RTStrFree(msg);
109}
110
111XmlError::XmlError(xmlErrorPtr aErr)
112{
113 if (!aErr)
114 throw EInvalidArg (RT_SRC_POS);
115
116 char *msg = Format(aErr);
117 setWhat(msg);
118 RTStrFree(msg);
119}
120
121/**
122 * Composes a single message for the given error. The caller must free the
123 * returned string using RTStrFree() when no more necessary.
124 */
125// static
126char *XmlError::Format(xmlErrorPtr aErr)
127{
128 const char *msg = aErr->message ? aErr->message : "<none>";
129 size_t msgLen = strlen(msg);
130 /* strip spaces, trailing EOLs and dot-like char */
131 while (msgLen && strchr(" \n.?!", msg [msgLen - 1]))
132 --msgLen;
133
134 char *finalMsg = NULL;
135 RTStrAPrintf(&finalMsg, "%.*s.\nLocation: '%s', line %d (%d), column %d",
136 msgLen, msg, aErr->file, aErr->line, aErr->int1, aErr->int2);
137
138 return finalMsg;
139}
140
141EIPRTFailure::EIPRTFailure(int aRC)
142 : RuntimeError(NULL),
143 mRC(aRC)
144{
145 char *newMsg = NULL;
146 RTStrAPrintf(&newMsg, "Runtime error: %d (%s)", aRC, RTErrGetShort(aRC));
147 setWhat(newMsg);
148 RTStrFree(newMsg);
149}
150
151//////////////////////////////////////////////////////////////////////////////
152// File Class
153//////////////////////////////////////////////////////////////////////////////
154
155struct File::Data
156{
157 Data()
158 : fileName (NULL), handle (NIL_RTFILE), opened (false) {}
159
160 char *fileName;
161 RTFILE handle;
162 bool opened : 1;
163};
164
165File::File(Mode aMode, const char *aFileName)
166 : m (new Data())
167{
168 m->fileName = RTStrDup (aFileName);
169 if (m->fileName == NULL)
170 throw ENoMemory();
171
172 unsigned flags = 0;
173 switch (aMode)
174 {
175 case Mode_Read:
176 flags = RTFILE_O_READ;
177 break;
178 case Mode_Write:
179 flags = RTFILE_O_WRITE | RTFILE_O_CREATE;
180 break;
181 case Mode_ReadWrite:
182 flags = RTFILE_O_READ | RTFILE_O_WRITE;
183 }
184
185 int vrc = RTFileOpen (&m->handle, aFileName, flags);
186 if (RT_FAILURE (vrc))
187 throw EIPRTFailure (vrc);
188
189 m->opened = true;
190}
191
192File::File (RTFILE aHandle, const char *aFileName /* = NULL */)
193 : m (new Data())
194{
195 if (aHandle == NIL_RTFILE)
196 throw EInvalidArg (RT_SRC_POS);
197
198 m->handle = aHandle;
199
200 if (aFileName)
201 {
202 m->fileName = RTStrDup (aFileName);
203 if (m->fileName == NULL)
204 throw ENoMemory();
205 }
206
207 setPos (0);
208}
209
210File::~File()
211{
212 if (m->opened)
213 RTFileClose (m->handle);
214
215 RTStrFree (m->fileName);
216}
217
218const char *File::uri() const
219{
220 return m->fileName;
221}
222
223uint64_t File::pos() const
224{
225 uint64_t p = 0;
226 int vrc = RTFileSeek (m->handle, 0, RTFILE_SEEK_CURRENT, &p);
227 if (RT_SUCCESS (vrc))
228 return p;
229
230 throw EIPRTFailure (vrc);
231}
232
233void File::setPos (uint64_t aPos)
234{
235 uint64_t p = 0;
236 unsigned method = RTFILE_SEEK_BEGIN;
237 int vrc = VINF_SUCCESS;
238
239 /* check if we overflow int64_t and move to INT64_MAX first */
240 if (((int64_t) aPos) < 0)
241 {
242 vrc = RTFileSeek (m->handle, INT64_MAX, method, &p);
243 aPos -= (uint64_t) INT64_MAX;
244 method = RTFILE_SEEK_CURRENT;
245 }
246 /* seek the rest */
247 if (RT_SUCCESS (vrc))
248 vrc = RTFileSeek (m->handle, (int64_t) aPos, method, &p);
249 if (RT_SUCCESS (vrc))
250 return;
251
252 throw EIPRTFailure (vrc);
253}
254
255int File::read (char *aBuf, int aLen)
256{
257 size_t len = aLen;
258 int vrc = RTFileRead (m->handle, aBuf, len, &len);
259 if (RT_SUCCESS (vrc))
260 return len;
261
262 throw EIPRTFailure (vrc);
263}
264
265int File::write (const char *aBuf, int aLen)
266{
267 size_t len = aLen;
268 int vrc = RTFileWrite (m->handle, aBuf, len, &len);
269 if (RT_SUCCESS (vrc))
270 return len;
271
272 throw EIPRTFailure (vrc);
273
274 return -1 /* failure */;
275}
276
277void File::truncate()
278{
279 int vrc = RTFileSetSize (m->handle, pos());
280 if (RT_SUCCESS (vrc))
281 return;
282
283 throw EIPRTFailure (vrc);
284}
285
286//////////////////////////////////////////////////////////////////////////////
287// MemoryBuf Class
288//////////////////////////////////////////////////////////////////////////////
289
290struct MemoryBuf::Data
291{
292 Data()
293 : buf (NULL), len (0), uri (NULL), pos (0) {}
294
295 const char *buf;
296 size_t len;
297 char *uri;
298
299 size_t pos;
300};
301
302MemoryBuf::MemoryBuf (const char *aBuf, size_t aLen, const char *aURI /* = NULL */)
303 : m (new Data())
304{
305 if (aBuf == NULL)
306 throw EInvalidArg (RT_SRC_POS);
307
308 m->buf = aBuf;
309 m->len = aLen;
310 m->uri = RTStrDup (aURI);
311}
312
313MemoryBuf::~MemoryBuf()
314{
315 RTStrFree (m->uri);
316}
317
318const char *MemoryBuf::uri() const
319{
320 return m->uri;
321}
322
323uint64_t MemoryBuf::pos() const
324{
325 return m->pos;
326}
327
328void MemoryBuf::setPos (uint64_t aPos)
329{
330 size_t pos = (size_t) aPos;
331 if ((uint64_t) pos != aPos)
332 throw EInvalidArg();
333
334 if (pos > m->len)
335 throw EInvalidArg();
336
337 m->pos = pos;
338}
339
340int MemoryBuf::read (char *aBuf, int aLen)
341{
342 if (m->pos >= m->len)
343 return 0 /* nothing to read */;
344
345 size_t len = m->pos + aLen < m->len ? aLen : m->len - m->pos;
346 memcpy (aBuf, m->buf + m->pos, len);
347 m->pos += len;
348
349 return len;
350}
351
352/*
353 * GlobalLock
354 *
355 *
356 */
357
358struct GlobalLock::Data
359{
360 PFNEXTERNALENTITYLOADER pOldLoader;
361 RTLock lock;
362
363 Data()
364 : pOldLoader(NULL),
365 lock(gGlobal.sxml.lock)
366 {
367 }
368};
369
370GlobalLock::GlobalLock()
371 : m(new Data())
372{
373}
374
375GlobalLock::~GlobalLock()
376{
377 if (m->pOldLoader)
378 xmlSetExternalEntityLoader(m->pOldLoader);
379}
380
381void GlobalLock::setExternalEntityLoader(PFNEXTERNALENTITYLOADER pLoader)
382{
383 m->pOldLoader = xmlGetExternalEntityLoader();
384 xmlSetExternalEntityLoader(pLoader);
385}
386
387// static
388xmlParserInput* GlobalLock::callDefaultLoader(const char *aURI,
389 const char *aID,
390 xmlParserCtxt *aCtxt)
391{
392 return gGlobal.sxml.defaultEntityLoader(aURI, aID, aCtxt);
393}
394
395/*
396 * Node
397 *
398 *
399 */
400
401struct Node::Data
402{
403 xmlNode *plibNode; // != NULL if this is an element
404 xmlAttr *plibAttr; // != NULL if this is an element
405
406 Node *pParent; // NULL only for the root element
407 const char *pcszName; // points either into plibNode or plibAttr
408
409 struct compare_const_char
410 {
411 bool operator()(const char* s1, const char* s2) const
412 {
413 return strcmp(s1, s2) < 0;
414 }
415 };
416
417 // attributes, if this is an element; can be empty
418 typedef std::map<const char*, boost::shared_ptr<Node>, compare_const_char > AttributesMap;
419 AttributesMap attribs;
420
421 // child elements, if this is an element; can be empty
422 typedef std::list< boost::shared_ptr<Node> > InternalNodesList;
423 InternalNodesList children;
424};
425
426Node::Node()
427 : m(new Data)
428{
429 m->plibNode = NULL;
430 m->plibAttr = NULL;
431 m->pParent = NULL;
432}
433
434Node::~Node()
435{
436 delete m;
437}
438
439void Node::buildChildren() // private
440{
441 // go thru this element's attributes
442 xmlAttr *plibAttr = m->plibNode->properties;
443 while (plibAttr)
444 {
445 const char *pcszAttribName = (const char*)plibAttr->name;
446 boost::shared_ptr<Node> pNew(new Node);
447 pNew->m->plibAttr = plibAttr;
448 pNew->m->pcszName = (const char*)plibAttr->name;
449 pNew->m->pParent = this;
450 // store
451 m->attribs[pcszAttribName] = pNew;
452
453 plibAttr = plibAttr->next;
454 }
455
456 // go thru this element's child elements
457 xmlNodePtr plibNode = m->plibNode->children;
458 while (plibNode)
459 {
460 // create a new Node for this child element
461 boost::shared_ptr<Node> pNew(new Node);
462 pNew->m->plibNode = plibNode;
463 pNew->m->pcszName = (const char*)plibNode->name;
464 pNew->m->pParent = this;
465 // store
466 m->children.push_back(pNew);
467
468 // recurse for this child element to get its own children
469 pNew->buildChildren();
470
471 plibNode = plibNode->next;
472 }
473}
474
475const char* Node::getName() const
476{
477 return m->pcszName;
478}
479
480/**
481 * Returns the value of a node. If this node is an attribute, returns
482 * the attribute value; if this node is an element, then this returns
483 * the element text content.
484 * @return
485 */
486const char* Node::getValue() const
487{
488 if ( (m->plibAttr)
489 && (m->plibAttr->children)
490 )
491 // libxml hides attribute values in another node created as a
492 // single child of the attribute node, and it's in the content field
493 return (const char*)m->plibAttr->children->content;
494
495 if ( (m->plibNode)
496 && (m->plibNode->children)
497 )
498 return (const char*)m->plibNode->children->content;
499
500 return NULL;
501}
502
503/**
504 * Copies the value of a node into the given integer variable.
505 * Returns TRUE only if a value was found and was actually an
506 * integer of the given type.
507 * @return
508 */
509bool Node::copyValue(int32_t &i) const
510{
511 const char *pcsz;
512 if ( ((pcsz = getValue()))
513 && (VINF_SUCCESS == RTStrToInt32Ex(pcsz, NULL, 10, &i))
514 )
515 return true;
516
517 return false;
518}
519
520/**
521 * Copies the value of a node into the given integer variable.
522 * Returns TRUE only if a value was found and was actually an
523 * integer of the given type.
524 * @return
525 */
526bool Node::copyValue(uint32_t &i) const
527{
528 const char *pcsz;
529 if ( ((pcsz = getValue()))
530 && (VINF_SUCCESS == RTStrToUInt32Ex(pcsz, NULL, 10, &i))
531 )
532 return true;
533
534 return false;
535}
536
537/**
538 * Copies the value of a node into the given integer variable.
539 * Returns TRUE only if a value was found and was actually an
540 * integer of the given type.
541 * @return
542 */
543bool Node::copyValue(int64_t &i) const
544{
545 const char *pcsz;
546 if ( ((pcsz = getValue()))
547 && (VINF_SUCCESS == RTStrToInt64Ex(pcsz, NULL, 10, &i))
548 )
549 return true;
550
551 return false;
552}
553
554/**
555 * Copies the value of a node into the given integer variable.
556 * Returns TRUE only if a value was found and was actually an
557 * integer of the given type.
558 * @return
559 */
560bool Node::copyValue(uint64_t &i) const
561{
562 const char *pcsz;
563 if ( ((pcsz = getValue()))
564 && (VINF_SUCCESS == RTStrToUInt64Ex(pcsz, NULL, 10, &i))
565 )
566 return true;
567
568 return false;
569}
570
571/**
572 * Returns the line number of the current node in the source XML file.
573 * Useful for error messages.
574 * @return
575 */
576int Node::getLineNumber() const
577{
578 if (m->plibAttr)
579 return m->pParent->m->plibNode->line;
580
581 return m->plibNode->line;
582}
583
584/**
585 * Builds a list of direct child elements of the current element that
586 * match the given string; if pcszMatch is NULL, all direct child
587 * elements are returned.
588 * @param children out: list of nodes to which children will be appended.
589 * @param pcszMatch in: match string, or NULL to return all children.
590 * @return Number of items appended to the list (0 if none).
591 */
592int Node::getChildElements(NodesList &children,
593 const char *pcszMatch /*= NULL*/)
594 const
595{
596 int i = 0;
597 Data::InternalNodesList::const_iterator
598 it,
599 last = m->children.end();
600 for (it = m->children.begin();
601 it != last;
602 ++it)
603 {
604 // export this child node if ...
605 if ( (!pcszMatch) // the caller wants all nodes or
606 || (!strcmp(pcszMatch, (**it).getName())) // the element name matches
607 )
608 {
609 children.push_back((*it).get());
610 ++i;
611 }
612 }
613 return i;
614}
615
616/**
617 * Returns the first child element whose name matches pcszMatch.
618 * @param pcszMatch
619 * @return
620 */
621const Node* Node::findChildElement(const char *pcszMatch)
622 const
623{
624 Data::InternalNodesList::const_iterator
625 it,
626 last = m->children.end();
627 for (it = m->children.begin();
628 it != last;
629 ++it)
630 {
631 if (!strcmp(pcszMatch, (**it).getName())) // the element name matches
632 return (*it).get();
633 }
634
635 return NULL;
636}
637
638/**
639 * Returns the first child element whose "id" attribute matches pcszId.
640 * @param pcszId identifier to look for.
641 * @return child element or NULL if not found.
642 */
643const Node* Node::findChildElementFromId(const char *pcszId) const
644{
645 Data::InternalNodesList::const_iterator
646 it,
647 last = m->children.end();
648 for (it = m->children.begin();
649 it != last;
650 ++it)
651 {
652 const Node *pElem = (*it).get();
653 const Node *pAttr;
654 if ( ((pAttr = pElem->findAttribute("id")))
655 && (!strcmp(pAttr->getValue(), pcszId))
656 )
657 return pElem;
658 }
659
660 return NULL;
661}
662
663/**
664 *
665 * @param pcszMatch
666 * @return
667 */
668const Node* Node::findAttribute(const char *pcszMatch) const
669{
670 Data::AttributesMap::const_iterator it;
671
672 it = m->attribs.find(pcszMatch);
673 if (it != m->attribs.end())
674 return it->second.get();
675
676 return NULL;
677}
678
679/**
680 * Convenience method which attempts to find the attribute with the given
681 * name and returns its value as a string.
682 *
683 * @param pcszMatch name of attribute to find.
684 * @param str out: attribute value
685 * @return TRUE if attribute was found and str was thus updated.
686 */
687bool Node::getAttributeValue(const char *pcszMatch, std::string &str) const
688{
689 const Node* pAttr;
690 if ((pAttr = findAttribute(pcszMatch)))
691 {
692 str = pAttr->getValue();
693 return true;
694 }
695
696 return false;
697}
698
699/**
700 * Convenience method which attempts to find the attribute with the given
701 * name and returns its value as a signed long integer. This calls
702 * RTStrToInt64Ex internally and will only output the integer if that
703 * function returns no error.
704 *
705 * @param pcszMatch name of attribute to find.
706 * @param i out: attribute value
707 * @return TRUE if attribute was found and str was thus updated.
708 */
709bool Node::getAttributeValue(const char *pcszMatch, int64_t &i) const
710{
711 std::string str;
712 if ( (getAttributeValue(pcszMatch, str))
713 && (VINF_SUCCESS == RTStrToInt64Ex(str.c_str(), NULL, 10, &i))
714 )
715 return true;
716
717 return false;
718}
719
720/**
721 * Convenience method which attempts to find the attribute with the given
722 * name and returns its value as an unsigned long integer.This calls
723 * RTStrToUInt64Ex internally and will only output the integer if that
724 * function returns no error.
725 *
726 * @param pcszMatch name of attribute to find.
727 * @param i out: attribute value
728 * @return TRUE if attribute was found and str was thus updated.
729 */
730bool Node::getAttributeValue(const char *pcszMatch, uint64_t &i) const
731{
732 std::string str;
733 if ( (getAttributeValue(pcszMatch, str))
734 && (VINF_SUCCESS == RTStrToUInt64Ex(str.c_str(), NULL, 10, &i))
735 )
736 return true;
737
738 return false;
739}
740
741/*
742 * NodesLoop
743 *
744 */
745
746struct NodesLoop::Data
747{
748 NodesList listElements;
749 NodesList::const_iterator it;
750};
751
752NodesLoop::NodesLoop(const Node &node, const char *pcszMatch /* = NULL */)
753{
754 m = new Data;
755 node.getChildElements(m->listElements, pcszMatch);
756 m->it = m->listElements.begin();
757}
758
759NodesLoop::~NodesLoop()
760{
761 delete m;
762}
763
764
765/**
766 * Handy convenience helper for looping over all child elements. Create an
767 * instance of NodesLoop on the stack and call this method until it returns
768 * NULL, like this:
769 * <code>
770 * xml::Node node; // should point to an element
771 * xml::NodesLoop loop(node, "child"); // find all "child" elements under node
772 * const xml::Node *pChild = NULL;
773 * while (pChild = loop.forAllNodes())
774 * ...;
775 * </code>
776 * @param node
777 * @param pcszMatch
778 * @return
779 */
780const Node* NodesLoop::forAllNodes() const
781{
782 const Node *pNode = NULL;
783
784 if (m->it != m->listElements.end())
785 {
786 pNode = *(m->it);
787 ++(m->it);
788 }
789
790 return pNode;
791}
792
793/*
794 * Document
795 *
796 *
797 */
798
799struct Document::Data
800{
801 xmlDocPtr pDocument;
802 Node *pRootElement;
803
804 Data()
805 {
806 pDocument = NULL;
807 pRootElement = NULL;
808 }
809
810 ~Data()
811 {
812 reset();
813 }
814
815 void reset()
816 {
817 if (pDocument)
818 {
819 xmlFreeDoc(pDocument);
820 pDocument = NULL;
821 }
822 if (pRootElement)
823 {
824 delete pRootElement;
825 pRootElement = NULL;
826 }
827 }
828
829 void copyFrom(const Document::Data *p)
830 {
831 if (p->pDocument)
832 {
833 pDocument = xmlCopyDoc(p->pDocument,
834 1); // recursive == copy all
835 }
836 }
837};
838
839Document::Document()
840 : m(new Data)
841{
842}
843
844Document::Document(const Document &x)
845 : m(new Data)
846{
847 m->copyFrom(x.m);
848};
849
850Document& Document::operator=(const Document &x)
851{
852 m->reset();
853 m->copyFrom(x.m);
854 return *this;
855};
856
857Document::~Document()
858{
859 delete m;
860}
861
862/**
863 * private method to refresh all internal structures after the internal pDocument
864 * has changed. Called from XmlFileParser::read(). m->reset() must have been
865 * called before to make sure all members except the internal pDocument are clean.
866 */
867void Document::refreshInternals() // private
868{
869 m->pRootElement = new Node();
870 m->pRootElement->m->plibNode = xmlDocGetRootElement(m->pDocument);
871 m->pRootElement->m->pcszName = (const char*)m->pRootElement->m->plibNode->name;
872
873 m->pRootElement->buildChildren();
874}
875
876const Node* Document::getRootElement() const
877{
878 return m->pRootElement;
879}
880
881/*
882 * XmlParserBase
883 *
884 *
885 */
886
887XmlParserBase::XmlParserBase()
888{
889 m_ctxt = xmlNewParserCtxt();
890 if (m_ctxt == NULL)
891 throw ENoMemory();
892}
893
894XmlParserBase::~XmlParserBase()
895{
896 xmlFreeParserCtxt (m_ctxt);
897 m_ctxt = NULL;
898}
899
900/*
901 * XmlFileParser
902 *
903 *
904 */
905
906struct XmlFileParser::Data
907{
908 xmlParserCtxtPtr ctxt;
909 std::string strXmlFilename;
910
911 Data()
912 {
913 if (!(ctxt = xmlNewParserCtxt()))
914 throw xml::ENoMemory();
915 }
916
917 ~Data()
918 {
919 xmlFreeParserCtxt(ctxt);
920 ctxt = NULL;
921 }
922};
923
924XmlFileParser::XmlFileParser()
925 : XmlParserBase(),
926 m(new Data())
927{
928}
929
930XmlFileParser::~XmlFileParser()
931{
932}
933
934struct ReadContext
935{
936 File file;
937 std::string error;
938
939 ReadContext(const char *pcszFilename)
940 : file(File::Mode_Read, pcszFilename)
941 {
942 }
943
944 void setError(const xml::Error &x)
945 {
946 error = x.what();
947 }
948
949 void setError(const std::exception &x)
950 {
951 error = x.what();
952 }
953};
954
955/**
956 * Reads the given file and fills the given Document object with its contents.
957 * Throws XmlError on parsing errors.
958 *
959 * The document that is passed in will be reset before being filled if not empty.
960 *
961 * @param pcszFilename in: name fo file to parse.
962 * @param doc out: document to be reset and filled with data according to file contents.
963 */
964void XmlFileParser::read(const char *pcszFilename,
965 Document &doc)
966{
967 GlobalLock lock();
968// global.setExternalEntityLoader(ExternalEntityLoader);
969
970 m->strXmlFilename = pcszFilename;
971
972 ReadContext context(pcszFilename);
973 doc.m->reset();
974 if (!(doc.m->pDocument = xmlCtxtReadIO(m->ctxt,
975 ReadCallback,
976 CloseCallback,
977 &context,
978 pcszFilename,
979 NULL, // encoding = auto
980 XML_PARSE_NOBLANKS)))
981 throw XmlError(xmlCtxtGetLastError(m->ctxt));
982
983 doc.refreshInternals();
984}
985
986// static
987int XmlFileParser::ReadCallback(void *aCtxt, char *aBuf, int aLen)
988{
989 ReadContext *pContext = static_cast<ReadContext*>(aCtxt);
990
991 /* To prevent throwing exceptions while inside libxml2 code, we catch
992 * them and forward to our level using a couple of variables. */
993
994 try
995 {
996 return pContext->file.read(aBuf, aLen);
997 }
998 catch (const xml::EIPRTFailure &err) { pContext->setError(err); }
999 catch (const xml::Error &err) { pContext->setError(err); }
1000 catch (const std::exception &err) { pContext->setError(err); }
1001 catch (...) { pContext->setError(xml::LogicError(RT_SRC_POS)); }
1002
1003 return -1 /* failure */;
1004}
1005
1006int XmlFileParser::CloseCallback(void *aCtxt)
1007{
1008 /// @todo to be written
1009
1010 return -1;
1011}
1012
1013
1014} // end namespace xml
1015
1016
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