VirtualBox

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

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

Main: replace redundant xml::FmtStr with com::Utf8StrFmt

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

© 2023 Oracle
ContactPrivacy policyTerms of Use