VirtualBox

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

Last change on this file since 4753 was 4372, checked in by vboxsync, 17 years ago

Finally corrected the RTFileRead, RTFileReadAt, RTFileWrite and RTFileWriteAt APIs to size_t. This was long overdue.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 79.4 KB
Line 
1/** @file
2 *
3 * CFGLDR - Configuration Loader
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/* Define STANDALONE_TEST for making a executable that
19 * will load and parse a XML file
20 */
21// #define STANDALONE_TEST
22
23/** @page pg_cfgldr CFGLDR - The Configuration Loader
24 *
25 * The configuration loader loads and keeps the configuration of VBox
26 * session. It will be used by VBox components to retrieve configuration
27 * values at startup and to change values if necessary.
28 *
29 * When VBox is started, it must call CFGLDRLoad to load global
30 * VBox configuration and then VM configuration.
31 *
32 * Handles then used by VBox components to retrieve configuration
33 * values. Components must query their values at startup.
34 * Configuration values can be changed only by respective
35 * component and the component must call CFGLDRSet*, to change the
36 * value in configuration file.
37 *
38 * Values are accessed only by name. It is important for components to
39 * use CFGLDRQuery* only at startup for performance reason.
40 *
41 * All CFGLDR* functions that take a CFGHANDLE or CFGNODE as their first
42 * argument return the VERR_INVALID_HANDLE status code if the argument is
43 * null handle (i.e. its value is zero).
44 */
45
46#define VBOX_XML_WRITER_FILTER
47#define VBOX_XML_XSLT
48#define _CRT_SECURE_NO_DEPRECATE
49
50#define LOG_GROUP LOG_GROUP_MAIN
51#include <VBox/log.h>
52
53#include <VBox/err.h>
54
55#include <iprt/string.h>
56#include <iprt/uuid.h>
57#include <iprt/path.h>
58#include <iprt/file.h>
59#include <iprt/time.h>
60#include <iprt/alloc.h>
61
62/// @todo (dmik) until RTTimeImplode and friends are done
63#include <time.h>
64
65#include <xercesc/util/PlatformUtils.hpp>
66
67#include <xercesc/dom/DOM.hpp>
68#include <xercesc/dom/DOMImplementation.hpp>
69#include <xercesc/dom/DOMImplementationLS.hpp>
70#include <xercesc/dom/DOMBuilder.hpp>
71#include <xercesc/dom/DOMWriter.hpp>
72
73#include <xercesc/framework/LocalFileFormatTarget.hpp>
74
75#include <xercesc/util/XMLUni.hpp>
76#include <xercesc/util/XMLUniDefs.hpp>
77#include <xercesc/util/BinInputStream.hpp>
78#include <xercesc/util/BinMemInputStream.hpp>
79
80#ifdef VBOX_XML_WRITER_FILTER
81#include <xercesc/dom/DOMWriterFilter.hpp>
82#endif
83
84#ifdef VBOX_XML_XSLT
85
86#include <xalanc/Include/PlatformDefinitions.hpp>
87#include <xalanc/XalanTransformer/XalanTransformer.hpp>
88#include <xalanc/XalanTransformer/XercesDOMWrapperParsedSource.hpp>
89#include <xalanc/XercesParserLiaison/XercesParserLiaison.hpp>
90#include <xalanc/XercesParserLiaison/XercesDOMSupport.hpp>
91#include <xalanc/XercesParserLiaison/FormatterToXercesDOM.hpp>
92#include <xalanc/XSLT/ProblemListener.hpp>
93
94XALAN_CPP_NAMESPACE_USE
95
96// generated file
97#include "SettingsConverter_xsl.h"
98
99#endif // VBOX_XML_XSLT
100
101// Little hack so we don't have to include the COM stuff
102// Note that those defines need to be made before we include
103// cfgldr.h so that the prototypes can be compiled.
104#ifndef BSTR
105#define OLECHAR wchar_t
106#define BSTR void*
107#if defined(RT_OS_WINDOWS)
108extern "C" BSTR __stdcall SysAllocString(const OLECHAR* sz);
109#else
110extern "C" BSTR SysAllocString(const OLECHAR* sz);
111#endif
112#endif
113
114#include "Logging.h"
115
116#include <VBox/cfgldr.h>
117
118#include <string.h>
119#include <stdio.h> // for sscanf
120
121#ifdef STANDALONE_TEST
122# include <stdlib.h>
123# include <iprt/runtime.h>
124#endif
125
126XERCES_CPP_NAMESPACE_USE
127
128// Helpers
129////////////////////////////////////////////////////////////////////////////////
130
131inline unsigned char fromhex (RTUTF16 hexdigit)
132{
133 if (hexdigit >= '0' && hexdigit <= '9')
134 return hexdigit - '0';
135 if (hexdigit >= 'A' && hexdigit <= 'F')
136 return hexdigit - 'A' + 0xA;
137 if (hexdigit >= 'a' && hexdigit <= 'f')
138 return hexdigit - 'a' + 0xa;
139
140 return 0xFF; // error indicator
141}
142
143inline RTUTF16 tohex (unsigned char ch)
144{
145 return (ch < 0xA) ? ch + '0' : ch - 0xA + 'A';
146}
147
148/**
149 * Converts a string of hex digits to memory bytes.
150 *
151 * @param puszValue String of hex digits to convert.
152 * @param pvValue Where to store converted bytes.
153 * @param cbValue Size of the @a pvValue array.
154 * @param pcbValue Where to store the actual number of stored bytes.
155 *
156 * @return IPRT status code.
157 */
158int wstr_to_bin (PCRTUTF16 puszValue, void *pvValue, unsigned cbValue, unsigned *pcbValue)
159{
160 int rc = VINF_SUCCESS;
161
162 unsigned count = 0;
163 unsigned char *dst = (unsigned char *) pvValue;
164
165 while (*puszValue)
166 {
167 unsigned char b = fromhex (*puszValue);
168
169 if (b == 0xFF)
170 {
171 /* it was not a valid hex digit */
172 rc = VERR_CFG_INVALID_FORMAT;
173 break;
174 }
175
176 if (count < cbValue)
177 {
178 *dst = b;
179 }
180
181 puszValue++;
182
183 if (!*puszValue)
184 {
185 rc = VERR_CFG_INVALID_FORMAT;
186 break;
187 }
188
189 b = fromhex (*puszValue++);
190
191 if (b == 0xFF)
192 {
193 /* it was not a valid hex digit */
194 rc = VERR_CFG_INVALID_FORMAT;
195 break;
196 }
197
198 if (count < cbValue)
199 {
200 *dst = ((*dst) << 4) + b;
201 dst++;
202 }
203
204 count++;
205 }
206
207 *pcbValue = count;
208
209 return rc;
210}
211
212/**
213 * Converts memory bytes to a null-terminated string of hex values.
214 *
215 * @param pvValue Memory array to convert.
216 * @param cbValue Number of bytes in the @a pvValue array.
217 * @param puszValue Where to store the pointer to the resulting string.
218 * On success, this string should be freed using RTUtf16Free().
219 *
220 * @return IPRT status code.
221 */
222static int bin_to_wstr (const void *pvValue, unsigned cbValue, PRTUTF16 *puszValue)
223{
224 int rc = VINF_SUCCESS;
225
226 /* each byte will produce two hex digits and there will be nul
227 * terminator */
228 *puszValue = (PRTUTF16) RTMemTmpAlloc (sizeof (RTUTF16) * (cbValue * 2 + 1));
229
230 if (!*puszValue)
231 {
232 rc = VERR_NO_MEMORY;
233 }
234 else
235 {
236 unsigned i = 0;
237 unsigned char *src = (unsigned char *) pvValue;
238 PRTUTF16 dst = *puszValue;
239
240 for (; i < cbValue; i++, src++)
241 {
242 *dst++ = tohex ((*src) >> 4);
243 *dst++ = tohex ((*src) & 0xF);
244 }
245
246 *dst = '\0';
247 }
248
249 return rc;
250}
251
252// CfgNode
253////////////////////////////////////////////////////////////////////////////////
254
255class CfgNode
256{
257 private:
258 friend class CfgLoader;
259 CfgLoader *pConfiguration;
260 CfgNode *next;
261 CfgNode *prev;
262
263 DOMNode *pdomnode;
264
265 CfgNode (CfgLoader *pcfg);
266 virtual ~CfgNode ();
267
268 int resolve (DOMNode *root, const char *pszName, unsigned uIndex, unsigned flags);
269
270 int getValueString (const char *pszName, PRTUTF16 *ppwszValue);
271 int setValueString (const char *pszName, PRTUTF16 pwszValue);
272
273 DOMNode *findChildText (void);
274
275 public:
276
277 enum {
278 fSearch = 0,
279 fCreateIfNotExists = 1,
280 fAppend = 2
281 };
282
283 static int ReleaseNode (CfgNode *pnode);
284 static int DeleteNode (CfgNode *pnode);
285
286 int CreateChildNode (const char *pszName, CfgNode **ppnode);
287 int AppendChildNode (const char *pszName, CfgNode **ppnode);
288
289 int GetChild (const char *pszName, unsigned uIndex, CfgNode **ppnode);
290 int CountChildren (const char *pszChildName, unsigned *pCount);
291
292
293 int QueryUInt32 (const char *pszName, uint32_t *pulValue);
294 int SetUInt32 (const char *pszName, uint32_t ulValue, unsigned int uiBase = 0);
295 int QueryUInt64 (const char *pszName, uint64_t *pullValue);
296 int SetUInt64 (const char *pszName, uint64_t ullValue, unsigned int uiBase = 0);
297
298 int QueryInt32 (const char *pszName, int32_t *plValue);
299 int SetInt32 (const char *pszName, int32_t lValue, unsigned int uiBase = 0);
300 int QueryInt64 (const char *pszName, int64_t *pllValue);
301 int SetInt64 (const char *pszName, int64_t llValue, unsigned int uiBase = 0);
302
303 int QueryUInt16 (const char *pszName, uint16_t *puhValue);
304 int SetUInt16 (const char *pszName, uint16_t uhValue, unsigned int uiBase = 0);
305
306 int QueryBin (const char *pszName, void *pvValue, unsigned cbValue, unsigned *pcbValue);
307 int SetBin (const char *pszName, const void *pvValue, unsigned cbValue);
308 int QueryString (const char *pszName, void **pValue, unsigned cbValue, unsigned *pcbValue, bool returnUtf16);
309 int SetString (const char *pszName, const char *pszValue, unsigned cbValue, bool isUtf16);
310
311 int QueryBool (const char *pszName, bool *pfValue);
312 int SetBool (const char *pszName, bool fValue);
313
314 int DeleteAttribute (const char *pszName);
315};
316
317// CfgLoader
318////////////////////////////////////////////////////////////////////////////////
319
320class CfgLoader
321{
322 private:
323
324 friend class CfgNode;
325
326 PRTUTF16 pwszOriginalFilename;
327 RTFILE hOriginalFileHandle; /** r=bird: this is supposed to mean 'handle to the orignal file handle'? The name is
328 * overloaded with too many 'handles'... That goes for those hFileHandle parameters too.
329 * hOriginalFile / FileOriginal and hFile / File should do by a long way. */
330 CfgNode *pfirstnode;
331
332 DOMBuilder *builder;
333 DOMNode *root;
334
335 int getNode (DOMNode *prootnode, const char *pszName, unsigned uIndex, CfgNode **ppnode, unsigned flags);
336
337 DOMDocument *Document(void) { return static_cast<DOMDocument *>(root); };
338
339 public:
340
341 CfgLoader ();
342 virtual ~CfgLoader ();
343
344 int Load (const char *pszFileName, RTFILE hFileHandle,
345 const char *pszExternalSchemaLocation, bool bDoNamespaces,
346 PFNCFGLDRENTITYRESOLVER pfnEntityResolver,
347 char **ppszErrorMessage);
348 int Save (const char *pszFilename, RTFILE hFileHandle,
349 char **ppszErrorMessage);
350 int Create ();
351#ifdef VBOX_XML_XSLT
352 int Transform (const char *pszTemlateLocation,
353 PFNCFGLDRENTITYRESOLVER pfnEntityResolver,
354 char **ppszErrorMessage);
355#endif
356
357 static int FreeConfiguration (CfgLoader *pcfg);
358
359 int CreateNode (const char *pszName, CfgNode **ppnode);
360
361 int GetNode (const char *pszName, unsigned uIndex, CfgNode **ppnode);
362};
363
364// VBoxWriterFilter
365////////////////////////////////////////////////////////////////////////////////
366
367#ifdef VBOX_XML_WRITER_FILTER
368class VBoxWriterFilter : public DOMWriterFilter
369{
370 public:
371 VBoxWriterFilter (unsigned long whatToShow = DOMNodeFilter::SHOW_ALL);
372 ~VBoxWriterFilter () {};
373
374 virtual short acceptNode (const DOMNode*) const;
375 virtual unsigned long getWhatToShow () const { return fWhatToShow; };
376 virtual void setWhatToShow (unsigned long toShow) { fWhatToShow = toShow; };
377
378 private:
379 unsigned long fWhatToShow;
380};
381
382VBoxWriterFilter::VBoxWriterFilter(unsigned long whatToShow)
383 :
384 fWhatToShow (whatToShow)
385{
386}
387
388short VBoxWriterFilter::acceptNode(const DOMNode* node) const
389{
390 switch (node->getNodeType())
391 {
392 case DOMNode::TEXT_NODE:
393 {
394 /* Reject empty nodes */
395 const XMLCh *pxmlch = node->getNodeValue ();
396
397 if (pxmlch)
398 {
399 while (*pxmlch != chNull)
400 {
401 if ( *pxmlch == chLF
402 || *pxmlch == chCR
403 || *pxmlch == chSpace
404 || *pxmlch == chHTab
405 )
406 {
407 pxmlch++;
408 continue;
409 }
410
411 break;
412 }
413
414 if (*pxmlch != chNull)
415 {
416 /* Accept the node because it contains non space characters */
417 return DOMNodeFilter::FILTER_ACCEPT;
418 }
419 }
420
421 return DOMNodeFilter::FILTER_REJECT;
422 }
423 }
424
425 return DOMNodeFilter::FILTER_ACCEPT;
426}
427
428#endif
429
430// CfgLdrInputSource
431////////////////////////////////////////////////////////////////////////////////
432
433/**
434 * A wrapper around RTFILE or a char buffer that acts like a DOMInputSource
435 * and therefore can be with DOMBuilder instances.
436 */
437class CfgLdrInputSource : public DOMInputSource
438{
439public:
440
441 CfgLdrInputSource (PCFGLDRENTITY pcEntity, const char *pcszSystemId);
442 virtual ~CfgLdrInputSource() { release(); }
443
444 // Functions introduced in DOM Level 3
445
446 const XMLCh *getEncoding () const { return NULL; }
447 const XMLCh *getPublicId () const { return NULL; }
448 const XMLCh *getSystemId () const { return (const XMLCh *)m_pwszSystemId; }
449 const XMLCh *getBaseURI () const { return (const XMLCh *)m_pwszBaseURI; }
450
451 void setEncoding (const XMLCh *const /* encodingStr */)
452 { AssertMsgFailed (("Not implemented!\n")); }
453 void setPublicId (const XMLCh *const /* publicId */)
454 { AssertMsgFailed (("Not implemented!\n")); }
455 void setSystemId (const XMLCh *const /* systemId */)
456 { AssertMsgFailed (("Not implemented!\n")); }
457 void setBaseURI (const XMLCh *const /* baseURI */)
458 { AssertMsgFailed (("Not implemented!\n")); }
459
460 // Non-standard Extension
461
462 BinInputStream *makeStream() const;
463 void setIssueFatalErrorIfNotFound (const bool /* flag */) {}
464 bool getIssueFatalErrorIfNotFound() const { return true; }
465 void release();
466
467private:
468
469 class FileHandleInputStream : public BinInputStream
470 {
471 public:
472
473 FileHandleInputStream (RTFILE hFileHandle);
474
475 unsigned int curPos() const;
476 unsigned int readBytes (XMLByte *const toFill, const unsigned int maxToRead);
477
478 private:
479
480 RTFILE m_hFileHandle;
481 uint64_t m_cbPos;
482 };
483
484 void init (const char *pcszSystemId);
485
486 CFGLDRENTITY m_entity;
487
488 PRTUTF16 m_pwszSystemId;
489 PRTUTF16 m_pwszBaseURI;
490};
491
492CfgLdrInputSource::CfgLdrInputSource (PCFGLDRENTITY pcEntity,
493 const char *pcszSystemId) :
494 m_pwszSystemId (NULL), m_pwszBaseURI (NULL)
495{
496 Assert (pcEntity && pcEntity->enmType != CFGLDRENTITYTYPE_INVALID);
497 // make a copy of the entity descriptor
498 m_entity = *pcEntity;
499
500 Assert (pcszSystemId);
501 int rc = RTStrToUtf16 (pcszSystemId, &m_pwszSystemId);
502 AssertRC (rc);
503
504 char *pszBaseURI = NULL;
505 pszBaseURI = RTStrDup (pcszSystemId);
506 Assert (pszBaseURI);
507 RTPathStripFilename (pszBaseURI);
508
509 rc = RTStrToUtf16 (pszBaseURI, &m_pwszBaseURI);
510 AssertRC (rc);
511}
512
513void CfgLdrInputSource::release()
514{
515 switch (m_entity.enmType)
516 {
517 case CFGLDRENTITYTYPE_HANDLE:
518 if (m_entity.u.handle.bClose)
519 RTFileClose (m_entity.u.handle.hFile);
520 break;
521 case CFGLDRENTITYTYPE_MEMORY:
522 if (m_entity.u.memory.bFree)
523 RTMemTmpFree (m_entity.u.memory.puchBuf);
524 break;
525 default:
526 break;
527 };
528
529 m_entity.enmType = CFGLDRENTITYTYPE_INVALID;
530
531 if (m_pwszBaseURI)
532 {
533 RTUtf16Free (m_pwszBaseURI);
534 m_pwszBaseURI = NULL;
535 }
536 if (m_pwszSystemId)
537 {
538 RTUtf16Free (m_pwszSystemId);
539 m_pwszSystemId = NULL;
540 }
541}
542
543BinInputStream *CfgLdrInputSource::makeStream() const
544{
545 BinInputStream *stream = NULL;
546
547 switch (m_entity.enmType)
548 {
549 case CFGLDRENTITYTYPE_HANDLE:
550 stream = new FileHandleInputStream (m_entity.u.handle.hFile);
551 break;
552 case CFGLDRENTITYTYPE_MEMORY:
553 // puchBuf is neither copied nor destructed by BinMemInputStream
554 stream = new BinMemInputStream (m_entity.u.memory.puchBuf,
555 m_entity.u.memory.cbBuf,
556 BinMemInputStream::BufOpt_Reference);
557 break;
558 default:
559 AssertMsgFailed (("Invalid resolver entity type!\n"));
560 break;
561 };
562
563 return stream;
564}
565
566CfgLdrInputSource::FileHandleInputStream::FileHandleInputStream (RTFILE hFileHandle) :
567 m_hFileHandle (hFileHandle),
568 m_cbPos (0)
569{
570}
571
572unsigned int CfgLdrInputSource::FileHandleInputStream::curPos() const
573{
574 AssertMsg (!(m_cbPos >> 32), ("m_cbPos exceeds 32 bits (%16Xll)\n", m_cbPos));
575 return (unsigned int)m_cbPos;
576}
577
578unsigned int CfgLdrInputSource::FileHandleInputStream::readBytes (
579 XMLByte *const toFill, const unsigned int maxToRead
580)
581{
582 /// @todo (dmik) trhow the appropriate exceptions if we fail to write
583
584 int rc;
585 NOREF (rc);
586
587 // memorize the current position
588 uint64_t cbOriginalPos = RTFileTell (m_hFileHandle);
589 Assert (cbOriginalPos != ~0ULL);
590 // set the new position
591 rc = RTFileSeek (m_hFileHandle, m_cbPos, RTFILE_SEEK_BEGIN, NULL);
592 AssertRC (rc);
593
594 // read from the file
595 size_t cbRead = 0;
596 rc = RTFileRead (m_hFileHandle, toFill, maxToRead, &cbRead);
597 AssertRC (rc);
598
599 // adjust the private position
600 m_cbPos += cbRead;
601 // restore the current position
602 rc = RTFileSeek (m_hFileHandle, cbOriginalPos, RTFILE_SEEK_BEGIN, NULL);
603 AssertRC (rc);
604
605 return (unsigned int)cbRead;
606}
607
608// CfgLdrFormatTarget
609////////////////////////////////////////////////////////////////////////////////
610
611class CfgLdrFormatTarget : public XMLFormatTarget
612{
613public:
614
615 CfgLdrFormatTarget (PCFGLDRENTITY pcEntity);
616 ~CfgLdrFormatTarget();
617
618 // virtual XMLFormatTarget methods
619 void writeChars (const XMLByte *const toWrite, const unsigned int count,
620 XMLFormatter *const formatter);
621 void flush() {}
622
623private:
624
625 CFGLDRENTITY m_entity;
626};
627
628CfgLdrFormatTarget::CfgLdrFormatTarget (PCFGLDRENTITY pcEntity)
629{
630 Assert (pcEntity && pcEntity->enmType != CFGLDRENTITYTYPE_INVALID);
631 // make a copy of the entity descriptor
632 m_entity = *pcEntity;
633
634 switch (m_entity.enmType)
635 {
636 case CFGLDRENTITYTYPE_HANDLE:
637 int rc;
638 // start writting from the beginning
639 rc = RTFileSeek (m_entity.u.handle.hFile, 0, RTFILE_SEEK_BEGIN, NULL);
640 AssertRC (rc);
641 NOREF (rc);
642 break;
643 case CFGLDRENTITYTYPE_MEMORY:
644 AssertMsgFailed (("Unsupported entity type!\n"));
645 break;
646 default:
647 break;
648 };
649}
650
651CfgLdrFormatTarget::~CfgLdrFormatTarget()
652{
653 switch (m_entity.enmType)
654 {
655 case CFGLDRENTITYTYPE_HANDLE:
656 {
657 int rc;
658 // truncate the file upto the size actually written
659 uint64_t cbPos = RTFileTell (m_entity.u.handle.hFile);
660 Assert (cbPos != ~0ULL);
661 rc = RTFileSetSize (m_entity.u.handle.hFile, cbPos);
662 AssertRC (rc);
663 // reset the position to he beginning
664 rc = RTFileSeek (m_entity.u.handle.hFile, 0, RTFILE_SEEK_BEGIN, NULL);
665 AssertRC (rc);
666 NOREF (rc);
667 if (m_entity.u.handle.bClose)
668 RTFileClose (m_entity.u.handle.hFile);
669 break;
670 }
671 case CFGLDRENTITYTYPE_MEMORY:
672 break;
673 default:
674 break;
675 };
676}
677
678void CfgLdrFormatTarget::writeChars (const XMLByte *const toWrite,
679 const unsigned int count,
680 XMLFormatter *const /* formatter */)
681{
682 /// @todo (dmik) trhow the appropriate exceptions if we fail to write
683
684 switch (m_entity.enmType)
685 {
686 case CFGLDRENTITYTYPE_HANDLE:
687 int rc;
688 rc = RTFileWrite (m_entity.u.handle.hFile, toWrite, count, NULL);
689 AssertRC (rc);
690 NOREF (rc);
691 break;
692 case CFGLDRENTITYTYPE_MEMORY:
693 AssertMsgFailed (("Unsupported entity type!\n"));
694 break;
695 default:
696 AssertMsgFailed (("Invalid entity type!\n"));
697 break;
698 };
699}
700
701// CfgLdrEntityResolver
702////////////////////////////////////////////////////////////////////////////////
703
704/**
705 * A wrapper around FNCFGLDRENTITYRESOLVER callback that acts like a
706 * DOMEntityResolver and therefore can be used with DOMBuilder instances.
707 */
708class CfgLdrEntityResolver : public DOMEntityResolver
709{
710public:
711
712 CfgLdrEntityResolver (PFNCFGLDRENTITYRESOLVER pfnEntityResolver) :
713 m_pfnEntityResolver (pfnEntityResolver) {}
714
715 // Functions introduced in DOM Level 2
716 DOMInputSource *resolveEntity (const XMLCh *const publicId,
717 const XMLCh *const systemId,
718 const XMLCh *const baseURI);
719
720private:
721
722 PFNCFGLDRENTITYRESOLVER m_pfnEntityResolver;
723};
724
725DOMInputSource *CfgLdrEntityResolver::resolveEntity (const XMLCh *const publicId,
726 const XMLCh *const systemId,
727 const XMLCh *const baseURI)
728{
729 if (!m_pfnEntityResolver)
730 return NULL;
731
732 DOMInputSource *source = NULL;
733 int rc = VINF_SUCCESS;
734
735 char *pszPublicId = NULL;
736 char *pszSystemId = NULL;
737 char *pszBaseURI = NULL;
738
739 if (publicId)
740 rc = RTUtf16ToUtf8 (publicId, &pszPublicId);
741 if (VBOX_SUCCESS (rc))
742 {
743 if (systemId)
744 rc = RTUtf16ToUtf8 (systemId, &pszSystemId);
745 if (VBOX_SUCCESS (rc))
746 {
747 if (baseURI)
748 rc = RTUtf16ToUtf8 (baseURI, &pszBaseURI);
749 if (VBOX_SUCCESS (rc))
750 {
751 CFGLDRENTITY entity;
752 rc = m_pfnEntityResolver (pszPublicId, pszSystemId, pszBaseURI,
753 &entity);
754 if (rc == VINF_SUCCESS)
755 source = new CfgLdrInputSource (&entity, pszSystemId);
756 }
757 }
758 }
759
760 if (pszBaseURI)
761 RTStrFree (pszBaseURI);
762 if (pszSystemId)
763 RTStrFree (pszSystemId);
764 if (pszPublicId)
765 RTStrFree (pszPublicId);
766
767 return source;
768}
769
770// CfgLdrErrorHandler
771////////////////////////////////////////////////////////////////////////////////
772
773/**
774 * An error handler that accumulates all error messages in a single UTF-8 string.
775 */
776class CfgLdrErrorHandler : public DOMErrorHandler
777#ifdef VBOX_XML_XSLT
778 , public ProblemListener
779#endif
780{
781public:
782
783 CfgLdrErrorHandler();
784 ~CfgLdrErrorHandler();
785
786 bool hasErrors() { return m_pszBuf != NULL; }
787
788 /** Transfers ownership of the string to the caller and resets the handler */
789 char *takeErrorMessage() {
790 char *pszBuf = m_pszBuf;
791 m_pszBuf = NULL;
792 return pszBuf;
793 }
794
795 // Functions introduced in DOM Level 3
796 bool handleError (const DOMError &domError);
797
798#ifdef VBOX_XML_XSLT
799 // Xalan ProblemListener interface
800 void setPrintWriter (PrintWriter *pw) {}
801 void problem (eProblemSource where, eClassification classification,
802 const XalanNode *sourceNode, const ElemTemplateElement *styleNode,
803 const XalanDOMString &msg, const XalanDOMChar *uri,
804 int lineNo, int charOffset);
805#endif
806
807private:
808
809 char *m_pszBuf;
810};
811
812CfgLdrErrorHandler::CfgLdrErrorHandler() :
813 m_pszBuf (NULL)
814{
815}
816
817CfgLdrErrorHandler::~CfgLdrErrorHandler()
818{
819 if (m_pszBuf)
820 RTMemTmpFree (m_pszBuf);
821}
822
823bool CfgLdrErrorHandler::handleError (const DOMError &domError)
824{
825 const char *pszSeverity = NULL;
826 switch (domError.getSeverity())
827 {
828 case DOMError::DOM_SEVERITY_WARNING: pszSeverity = "WARNING: ";
829 case DOMError::DOM_SEVERITY_ERROR: pszSeverity = "ERROR: ";
830 case DOMError::DOM_SEVERITY_FATAL_ERROR: pszSeverity = "FATAL ERROR: ";
831 }
832
833 char *pszLocation = NULL;
834 const DOMLocator *pLocation = domError.getLocation();
835 if (pLocation)
836 {
837 static const char Location[] = "\nLocation: '%s', line %d, column %d";
838
839 char *pszURI = NULL;
840 if (pLocation->getURI())
841 RTUtf16ToUtf8 (pLocation->getURI(), &pszURI);
842
843 size_t cbLocation = sizeof (Location) +
844 (pszURI ? strlen (pszURI) : 10 /* NULL */) +
845 10 + 10 + 1 /* line & column & \0 */;
846 pszLocation = (char *) RTMemTmpAllocZ (cbLocation);
847 RTStrPrintf (pszLocation, cbLocation, Location,
848 pszURI,
849 pLocation->getLineNumber(), pLocation->getColumnNumber());
850
851 if (pszURI)
852 RTStrFree (pszURI);
853 }
854
855 LogFlow (("CfgLdrErrorHandler::handleError():\n %s%ls%s\n",
856 pszSeverity, domError.getMessage(), pszLocation));
857
858 char *pszMsg = NULL;
859 if (domError.getMessage())
860 RTUtf16ToUtf8 (domError.getMessage(), &pszMsg);
861
862 size_t cbNewBuf = (m_pszBuf ? strlen (m_pszBuf) : 0) +
863 (pszSeverity ? strlen (pszSeverity) : 0) +
864 (pszMsg ? strlen (pszMsg) : 0) +
865 (pszLocation ? strlen (pszLocation) : 0);
866 char *pszNewBuf = (char *) RTMemTmpAllocZ (cbNewBuf + 2 /* \n + \0 */);
867
868 if (m_pszBuf)
869 {
870 strcpy (pszNewBuf, m_pszBuf);
871 strcat (pszNewBuf, "\n");
872 }
873 if (pszSeverity)
874 strcat (pszNewBuf, pszSeverity);
875 if (pszMsg)
876 strcat (pszNewBuf, pszMsg);
877 if (pszLocation)
878 strcat (pszNewBuf, pszLocation);
879
880 if (m_pszBuf)
881 RTMemTmpFree (m_pszBuf);
882 m_pszBuf = pszNewBuf;
883
884 if (pszLocation)
885 RTMemTmpFree (pszLocation);
886 if (pszMsg)
887 RTStrFree (pszMsg);
888
889 // fail on any error when possible
890 return false;
891}
892
893#ifdef VBOX_XML_XSLT
894void CfgLdrErrorHandler::problem (eProblemSource where, eClassification classification,
895 const XalanNode *sourceNode, const ElemTemplateElement *styleNode,
896 const XalanDOMString &msg, const XalanDOMChar *uri,
897 int lineNo, int charOffset)
898{
899 const char *pszClass = NULL;
900 switch (classification)
901 {
902 case eMESSAGE: pszClass = "INFO: ";
903 case eWARNING: pszClass = "WARNING: ";
904 case eERROR: pszClass = "ERROR: ";
905 }
906
907 LogFlow (("CfgLdrErrorHandler::problem():\n %s%ls\n", pszClass, msg.c_str()));
908
909 char *pszMsg = NULL;
910 if (msg.c_str())
911 RTUtf16ToUtf8 (msg.c_str(), &pszMsg);
912
913 size_t cbNewBuf = (m_pszBuf ? strlen (m_pszBuf) : 0) +
914 (pszClass ? strlen (pszClass) : 0) +
915 (pszMsg ? strlen (pszMsg) : 0);
916 char *pszNewBuf = (char *) RTMemTmpAllocZ (cbNewBuf + 2 /* \n + \0 */);
917
918 if (m_pszBuf)
919 {
920 strcpy (pszNewBuf, m_pszBuf);
921 strcat (pszNewBuf, "\n");
922 }
923 if (pszClass)
924 strcat (pszNewBuf, pszClass);
925 if (pszMsg)
926 strcat (pszNewBuf, pszMsg);
927
928 if (m_pszBuf)
929 RTStrFree (m_pszBuf);
930
931 m_pszBuf = RTStrDup (pszNewBuf);
932
933 if (pszNewBuf)
934 RTMemTmpFree (pszNewBuf);
935 if (pszMsg)
936 RTStrFree (pszMsg);
937}
938#endif
939
940//
941////////////////////////////////////////////////////////////////////////////////
942
943static int xmlInitialized = 0;
944
945static int initXML (void)
946{
947 try
948 {
949 XMLPlatformUtils::Initialize();
950 }
951
952 catch(...)
953 {
954 return 0;
955 }
956
957 return (xmlInitialized = 1);
958}
959
960static void terminateXML (void)
961{
962 if (xmlInitialized)
963 {
964 XMLPlatformUtils::Terminate();
965 xmlInitialized = 0;
966 }
967}
968
969/* CfgLoader implementation */
970CfgLoader::CfgLoader ()
971 :
972 pwszOriginalFilename (NULL),
973 hOriginalFileHandle (NIL_RTFILE),
974 pfirstnode (NULL),
975 builder (NULL),
976 root (NULL)
977{
978}
979
980CfgLoader::~CfgLoader ()
981{
982 if (pwszOriginalFilename)
983 {
984 RTUtf16Free (pwszOriginalFilename);
985 }
986
987 if (builder)
988 {
989 /* Configuration was parsed from a file.
990 * Parser owns root and will delete root.
991 */
992 builder->release();
993 }
994 else if (root)
995 {
996 /* This is new, just created configuration.
997 * root is new object created by DOMImplementation::createDocument
998 * We have to delete root.
999 */
1000 root->release();
1001 }
1002}
1003
1004int CfgLoader::Load (const char *pszFileName, RTFILE hFileHandle,
1005 const char *pszExternalSchemaLocation, bool bDoNamespaces,
1006 PFNCFGLDRENTITYRESOLVER pfnEntityResolver,
1007 char **ppszErrorMessage)
1008{
1009 if (!xmlInitialized)
1010 return VERR_NOT_SUPPORTED;
1011
1012 Assert (!root && !pwszOriginalFilename);
1013 if (root || pwszOriginalFilename)
1014 return VERR_ALREADY_LOADED;
1015
1016 static const XMLCh LS[] = { chLatin_L, chLatin_S, chNull };
1017 DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation (LS);
1018 if (!impl)
1019 return VERR_NOT_SUPPORTED;
1020
1021 // note:
1022 // member variables allocated here (builder, pwszOriginalFilename) are not
1023 // freed in case of error because CFGLDRLoad() that calls this method will
1024 // delete this instance (and all members) if we return a failure from here
1025
1026 builder = static_cast <DOMImplementationLS *> (impl)->
1027 createDOMBuilder (DOMImplementationLS::MODE_SYNCHRONOUS, 0);
1028 if (!builder)
1029 return VERR_NOT_SUPPORTED;
1030
1031 int rc = VINF_SUCCESS;
1032
1033 if (ppszErrorMessage)
1034 *ppszErrorMessage = NULL;
1035
1036 // set parser's features
1037 Assert (builder->canSetFeature (XMLUni::fgDOMDatatypeNormalization, true));
1038 if (builder->canSetFeature (XMLUni::fgDOMDatatypeNormalization, true))
1039 builder->setFeature (XMLUni::fgDOMDatatypeNormalization, true);
1040 else
1041 return VERR_NOT_SUPPORTED;
1042 if (bDoNamespaces)
1043 {
1044 Assert (builder->canSetFeature (XMLUni::fgDOMNamespaces, true));
1045 if (builder->canSetFeature (XMLUni::fgDOMNamespaces, true))
1046 builder->setFeature (XMLUni::fgDOMNamespaces, true);
1047 else
1048 return VERR_NOT_SUPPORTED;
1049 }
1050 if (pszExternalSchemaLocation)
1051 {
1052 // set validation related features & properties
1053 Assert (builder->canSetFeature (XMLUni::fgDOMValidation, true));
1054 if (builder->canSetFeature (XMLUni::fgDOMValidation, true))
1055 builder->setFeature (XMLUni::fgDOMValidation, true);
1056 else
1057 return VERR_NOT_SUPPORTED;
1058 Assert (builder->canSetFeature (XMLUni::fgXercesSchema, true));
1059 if (builder->canSetFeature (XMLUni::fgXercesSchema, true))
1060 builder->setFeature (XMLUni::fgXercesSchema, true);
1061 else
1062 return VERR_NOT_SUPPORTED;
1063 Assert (builder->canSetFeature (XMLUni::fgXercesSchemaFullChecking, true));
1064 if (builder->canSetFeature (XMLUni::fgXercesSchemaFullChecking, true))
1065 builder->setFeature (XMLUni::fgXercesSchemaFullChecking, true);
1066 else
1067 return VERR_NOT_SUPPORTED;
1068
1069 PRTUTF16 pwszExternalSchemaLocation = NULL;
1070 rc = RTStrToUtf16 (pszExternalSchemaLocation, &pwszExternalSchemaLocation);
1071 if (VBOX_FAILURE (rc))
1072 return rc;
1073
1074 if (bDoNamespaces)
1075 {
1076 // set schema that supports namespaces
1077 builder->setProperty (XMLUni::fgXercesSchemaExternalSchemaLocation,
1078 pwszExternalSchemaLocation);
1079 }
1080 else
1081 {
1082 // set schema that doesn't support namespaces
1083 builder->setProperty (XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation,
1084 pwszExternalSchemaLocation);
1085 }
1086
1087 RTUtf16Free (pwszExternalSchemaLocation);
1088 }
1089
1090 hOriginalFileHandle = hFileHandle;
1091 rc = RTStrToUtf16 (pszFileName, &pwszOriginalFilename);
1092 if (VBOX_FAILURE (rc))
1093 return rc;
1094
1095 CfgLdrEntityResolver entityResolver (pfnEntityResolver);
1096 builder->setEntityResolver (&entityResolver);
1097
1098 CfgLdrErrorHandler errorHandler;
1099 builder->setErrorHandler (&errorHandler);
1100
1101 try
1102 {
1103 if (hFileHandle != NIL_RTFILE)
1104 {
1105 CFGLDRENTITY entity;
1106 entity.enmType = CFGLDRENTITYTYPE_HANDLE;
1107 entity.u.handle.hFile = hFileHandle;
1108 entity.u.handle.bClose = false;
1109 CfgLdrInputSource source (&entity, pszFileName);
1110 root = builder->parse (source);
1111 }
1112 else
1113 {
1114 root = builder->parseURI (pwszOriginalFilename);
1115 }
1116 }
1117 catch (...)
1118 {
1119 rc = VERR_OPEN_FAILED;
1120 }
1121
1122 if (errorHandler.hasErrors())
1123 {
1124 // this will transfer ownership of the string
1125 if (ppszErrorMessage)
1126 *ppszErrorMessage = errorHandler.takeErrorMessage();
1127 rc = VERR_OPEN_FAILED;
1128 }
1129
1130 builder->setErrorHandler (NULL);
1131 builder->setEntityResolver (NULL);
1132
1133 return rc;
1134}
1135
1136int CfgLoader::Save (const char *pszFilename, RTFILE hFileHandle,
1137 char **ppszErrorMessage)
1138{
1139 if (!pszFilename && !pwszOriginalFilename &&
1140 hFileHandle == NIL_RTFILE && hOriginalFileHandle == NIL_RTFILE)
1141 {
1142 // no explicit handle/filename specified and the configuration
1143 // was created from scratch
1144 return VERR_INVALID_PARAMETER;
1145 }
1146
1147 static const XMLCh LS[] = { chLatin_L, chLatin_S, chNull };
1148 DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation (LS);
1149 if (!impl)
1150 return VERR_NOT_SUPPORTED;
1151
1152 DOMWriter *writer = static_cast <DOMImplementationLS *> (impl)->createDOMWriter();
1153 if (!writer)
1154 return VERR_NOT_SUPPORTED;
1155
1156 int rc = VINF_SUCCESS;
1157
1158 if (ppszErrorMessage)
1159 *ppszErrorMessage = NULL;
1160
1161#ifdef VBOX_XML_WRITER_FILTER
1162 VBoxWriterFilter theFilter (DOMNodeFilter::SHOW_TEXT);
1163 writer->setFilter (&theFilter);
1164#endif
1165
1166 writer->setEncoding (XMLUni::fgUTF8EncodingString);
1167
1168 // set feature if the serializer supports the feature/mode
1169 if (writer->canSetFeature(XMLUni::fgDOMWRTDiscardDefaultContent, true))
1170 writer->setFeature(XMLUni::fgDOMWRTDiscardDefaultContent, true);
1171 if (writer->canSetFeature (XMLUni::fgDOMWRTFormatPrettyPrint, true))
1172 writer->setFeature (XMLUni::fgDOMWRTFormatPrettyPrint, true);
1173
1174 CfgLdrErrorHandler errorHandler;
1175 writer->setErrorHandler (&errorHandler);
1176
1177 try
1178 {
1179 if (hFileHandle != NIL_RTFILE || hOriginalFileHandle != NIL_RTFILE)
1180 {
1181 CFGLDRENTITY entity;
1182 entity.enmType = CFGLDRENTITYTYPE_HANDLE;
1183 entity.u.handle.hFile = hFileHandle != NIL_RTFILE ? hFileHandle :
1184 hOriginalFileHandle;
1185 entity.u.handle.bClose = false;
1186 CfgLdrFormatTarget target (&entity);
1187 writer->writeNode (&target, *root);
1188 }
1189 else
1190 {
1191 PRTUTF16 pwszFilename = NULL;
1192 if (pszFilename)
1193 rc = RTStrToUtf16 (pszFilename, &pwszFilename);
1194 if (VBOX_SUCCESS (rc))
1195 {
1196 LocalFileFormatTarget target (pwszFilename ? pwszFilename :
1197 pwszOriginalFilename);
1198 if (pwszFilename)
1199 RTUtf16Free (pwszFilename);
1200
1201 writer->writeNode (&target, *root);
1202 }
1203 }
1204 }
1205 catch(...)
1206 {
1207 rc = VERR_FILE_IO_ERROR;
1208 }
1209
1210 if (errorHandler.hasErrors())
1211 {
1212 // this will transfer ownership of the string
1213 if (ppszErrorMessage)
1214 *ppszErrorMessage = errorHandler.takeErrorMessage();
1215 rc = VERR_FILE_IO_ERROR;
1216 }
1217
1218 writer->release();
1219
1220 if (hFileHandle != NIL_RTFILE || hOriginalFileHandle != NIL_RTFILE)
1221 (void)RTFileFlush(hFileHandle != NIL_RTFILE ? hFileHandle :
1222 hOriginalFileHandle);
1223
1224 return rc;
1225}
1226
1227#ifdef VBOX_XML_XSLT
1228int CfgLoader::Transform (const char *pszTemlateLocation,
1229 PFNCFGLDRENTITYRESOLVER pfnEntityResolver,
1230 char **ppszErrorMessage)
1231{
1232 AssertReturn (strcmp (pszTemlateLocation, "SettingsConverter.xsl") == 0,
1233 VERR_NOT_SUPPORTED);
1234 AssertReturn (pfnEntityResolver == NULL,
1235 VERR_NOT_SUPPORTED);
1236
1237 int rc = VINF_SUCCESS;
1238
1239 if (ppszErrorMessage)
1240 *ppszErrorMessage = NULL;
1241
1242 XalanTransformer::initialize();
1243
1244 XalanTransformer xalan;
1245
1246 // input stream to read from SettingsConverter_xsl
1247 struct SettingsConverterStream : public XSLTInputSource
1248 {
1249 SettingsConverterStream()
1250 {
1251 XMLCh *id = XMLString::transcode ("SettingsConverter.xsl");
1252 setSystemId (id);
1253 setPublicId (id);
1254 XMLString::release (&id);
1255 }
1256
1257 BinInputStream *makeStream () const
1258 {
1259 return new BinMemInputStream (g_abSettingsConverter_xsl,
1260 g_cbSettingsConverter_xsl);
1261 }
1262 };
1263
1264 CfgLdrErrorHandler errorHandler;
1265 xalan.setProblemListener (&errorHandler);
1266
1267 try
1268 {
1269 // target is the DOM tree
1270 DOMDocument *newRoot =
1271 DOMImplementation::getImplementation()->createDocument();
1272 FormatterToXercesDOM formatter (newRoot, 0);
1273
1274 // source is the DOM tree
1275 XercesDOMSupport support;
1276 XercesParserLiaison liaison;
1277 const XercesDOMWrapperParsedSource parsedSource (
1278 Document(), liaison, support,
1279 XalanDOMString (pwszOriginalFilename));
1280
1281 // stylesheet
1282 SettingsConverterStream xsl;
1283
1284 int xrc = xalan.transform (parsedSource, xsl, formatter);
1285
1286 if (xrc)
1287 {
1288 LogFlow(("xalan.transform() = %d (%s)\n", xrc, xalan.getLastError()));
1289
1290 newRoot->release();
1291 rc = VERR_FILE_IO_ERROR;
1292 }
1293 else
1294 {
1295 // release the builder and the old document, if any
1296 if (builder)
1297 {
1298 builder->release();
1299 builder = 0;
1300 root = 0;
1301 }
1302 else if (root)
1303 {
1304 root->release();
1305 root = 0;
1306 }
1307
1308 root = newRoot;
1309
1310 // Xalan 1.9.0 (and 1.10.0) is stupid bacause disregards the
1311 // XSLT specs and ignores the exclude-result-prefixes stylesheet
1312 // attribute, flooding all the elements with stupid xmlns
1313 // specifications. Here we remove them.
1314 XMLCh *xmlnsName = XMLString::transcode ("xmlns");
1315 XMLCh *xmlnsVBox = XMLString::transcode ("http://www.innotek.de/VirtualBox-settings");
1316 DOMNodeIterator *iter =
1317 newRoot->createNodeIterator (newRoot, DOMNodeFilter::SHOW_ELEMENT,
1318 NULL, false);
1319 DOMNode *node = NULL;
1320 while ((node = iter->nextNode()) != NULL)
1321 {
1322 DOMElement *elem = static_cast <DOMElement *> (node);
1323 if (elem->getParentNode() == newRoot)
1324 continue;
1325
1326 const XMLCh *xmlns = elem->getAttribute (xmlnsName);
1327 if (xmlns == NULL)
1328 continue;
1329 if (xmlns[0] == 0 ||
1330 XMLString::compareString (xmlns, xmlnsVBox) == 0)
1331 {
1332 elem->removeAttribute (xmlnsName);
1333 }
1334 }
1335 XMLString::release (&xmlnsVBox);
1336 XMLString::release (&xmlnsName);
1337 }
1338 }
1339 catch (...)
1340 {
1341 rc = VERR_FILE_IO_ERROR;
1342 }
1343
1344 if (VBOX_FAILURE (rc))
1345 {
1346 // this will transfer ownership of the string
1347 if (ppszErrorMessage)
1348 {
1349 if (xalan.getLastError())
1350 *ppszErrorMessage = RTStrDup (xalan.getLastError());
1351 else
1352 *ppszErrorMessage = errorHandler.takeErrorMessage();
1353 }
1354 }
1355
1356 XalanTransformer::terminate();
1357
1358 return rc;
1359}
1360#endif
1361
1362int CfgLoader::Create()
1363{
1364 if (!xmlInitialized)
1365 {
1366 return VERR_NOT_SUPPORTED;
1367 }
1368
1369 int rc = VINF_SUCCESS;
1370
1371 static const XMLCh gLS[] = { chLatin_L, chLatin_S, chNull };
1372 DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(gLS);
1373
1374 if (impl)
1375 {
1376 // creating an empty doc is a non-standard extension to DOM specs.
1377 // we're using it since we're bound to Xerces anyway.
1378 root = impl->createDocument();
1379 }
1380 if (!root)
1381 {
1382 rc = VERR_NOT_SUPPORTED;
1383 }
1384
1385 return rc;
1386}
1387
1388int CfgLoader::FreeConfiguration (CfgLoader *pcfg)
1389{
1390 int rc = VINF_SUCCESS;
1391
1392 while (pcfg->pfirstnode)
1393 {
1394 CfgNode::ReleaseNode (pcfg->pfirstnode);
1395 }
1396
1397 delete pcfg;
1398
1399 return rc;
1400}
1401
1402int CfgLoader::CreateNode (const char *pszName, CfgNode **ppnode)
1403{
1404 return getNode (root, pszName, 0, ppnode, CfgNode::fCreateIfNotExists);
1405}
1406
1407int CfgLoader::GetNode (const char *pszName, unsigned uIndex, CfgNode **ppnode)
1408{
1409 return getNode (root, pszName, uIndex, ppnode, CfgNode::fSearch);
1410}
1411
1412int CfgLoader::getNode (DOMNode *prootnode, const char *pszName, unsigned uIndex, CfgNode **ppnode, unsigned flags)
1413{
1414 int rc = VINF_SUCCESS;
1415
1416 CfgNode *pnode = new CfgNode (this);
1417
1418 if (!pnode)
1419 {
1420 rc = VERR_NO_MEMORY;
1421 }
1422 else if (!prootnode)
1423 {
1424 rc = VERR_NOT_SUPPORTED;
1425 }
1426 else
1427 {
1428 rc = pnode->resolve (prootnode, pszName, uIndex, flags);
1429 }
1430
1431 if (VBOX_SUCCESS(rc))
1432 {
1433 pnode->next = pfirstnode;
1434 if (pfirstnode)
1435 {
1436 pfirstnode->prev = pnode;
1437 }
1438 pfirstnode = pnode;
1439
1440 *ppnode = pnode;
1441 }
1442 else
1443 {
1444 if (pnode)
1445 {
1446 delete pnode;
1447 }
1448 }
1449
1450 return rc;
1451}
1452
1453/* CfgNode implementation */
1454CfgNode::CfgNode (CfgLoader *pcfg)
1455 :
1456 pConfiguration (pcfg),
1457 next (NULL),
1458 prev (NULL)
1459{
1460}
1461
1462CfgNode::~CfgNode ()
1463{
1464}
1465
1466int CfgNode::ReleaseNode (CfgNode *pnode)
1467{
1468 int rc = VINF_SUCCESS;
1469
1470 if (pnode->next)
1471 {
1472 pnode->next->prev = pnode->prev;
1473 }
1474
1475 if (pnode->prev)
1476 {
1477 pnode->prev->next = pnode->next;
1478 }
1479 else
1480 {
1481 pnode->pConfiguration->pfirstnode = pnode->next;
1482 }
1483
1484 delete pnode;
1485
1486 return rc;
1487}
1488
1489int CfgNode::DeleteNode (CfgNode *pnode)
1490{
1491 int rc = VINF_SUCCESS;
1492
1493 DOMNode *pparent = pnode->pdomnode->getParentNode ();
1494
1495 pparent->removeChild (pnode->pdomnode);
1496
1497 pnode->pdomnode = 0;
1498
1499 ReleaseNode (pnode);
1500
1501 return rc;
1502}
1503
1504int CfgNode::resolve (DOMNode *root, const char *pszName, unsigned uIndex, unsigned flags)
1505{
1506 static const char *pcszEmptyName = "";
1507
1508 if (!root)
1509 {
1510 return VERR_PATH_NOT_FOUND;
1511 }
1512
1513 if (!pszName)
1514 {
1515 // special case for resolving any child
1516 pszName = pcszEmptyName;
1517 }
1518
1519 if ((flags & (fCreateIfNotExists | fAppend)) && !(*pszName))
1520 {
1521 return VERR_INVALID_PARAMETER;
1522 }
1523
1524 int rc = VINF_SUCCESS;
1525
1526 PRTUTF16 pwszName = NULL;
1527
1528 rc = RTStrToUtf16 (pszName, &pwszName);
1529
1530 if (VBOX_SUCCESS(rc))
1531 {
1532 XMLCh *puszComponent = pwszName;
1533
1534 bool lastComponent = false;
1535
1536 int lastindex = XMLString::indexOf (puszComponent, '/');
1537
1538 if (lastindex == -1)
1539 {
1540 lastindex = XMLString::stringLen (puszComponent);
1541 lastComponent = true;
1542 }
1543
1544 rc = VERR_PATH_NOT_FOUND;
1545
1546 for (;;)
1547 {
1548 DOMNode *child = 0, *first = 0;
1549
1550 if (!lastComponent || !(flags & fAppend))
1551 {
1552 for (child = root->getFirstChild(); child != 0; child=child->getNextSibling())
1553 {
1554 if (child->getNodeType () == DOMNode::ELEMENT_NODE)
1555 {
1556 if (!lastindex || XMLString::compareNString (child->getNodeName (), puszComponent, lastindex) == 0)
1557 {
1558 if (lastComponent)
1559 {
1560 if (uIndex == 0)
1561 {
1562 pdomnode = child;
1563 rc = VINF_SUCCESS;
1564 break;
1565 }
1566 uIndex--;
1567 continue;
1568 }
1569 else
1570 {
1571 if (!first)
1572 {
1573 first = child;
1574 }
1575 else
1576 {
1577 break;
1578 }
1579 }
1580 }
1581 }
1582 }
1583 }
1584
1585 if (first)
1586 {
1587 if (child)
1588 {
1589 // some element in the path (except the last) has
1590 // siblingswith the same name
1591 rc = VERR_INVALID_PARAMETER;
1592 break;
1593 }
1594 root = child = first;
1595 }
1596
1597 if (!child)
1598 {
1599 if (flags & (fCreateIfNotExists | fAppend))
1600 {
1601 // Extract the component name to a temporary buffer
1602 RTUTF16 uszName[256];
1603
1604 memcpy (uszName, puszComponent, lastindex * sizeof(uszName[0]));
1605 uszName[lastindex] = 0;
1606
1607 try
1608 {
1609 DOMElement *elem = pConfiguration->Document()->createElement(uszName);
1610 root = root->appendChild(elem);
1611 }
1612
1613 catch (...)
1614 {
1615 Log(( "Error creating element [%ls]\n", uszName ));
1616 rc = VERR_CFG_NO_VALUE;
1617 break;
1618 }
1619
1620 if (lastComponent)
1621 {
1622 pdomnode = root;
1623 rc = VINF_SUCCESS;
1624 break;
1625 }
1626 }
1627 else
1628 {
1629 break;
1630 }
1631 }
1632
1633 puszComponent += lastindex;
1634 if (*puszComponent)
1635 {
1636 puszComponent++;
1637 }
1638
1639 if (!*puszComponent)
1640 {
1641 break;
1642 }
1643
1644 lastindex = XMLString::indexOf (puszComponent, '/');
1645
1646 if (lastindex == -1)
1647 {
1648 lastindex = XMLString::stringLen (puszComponent);
1649 lastComponent = true;
1650 }
1651 }
1652
1653 RTUtf16Free (pwszName);
1654 }
1655
1656 return rc;
1657}
1658
1659int CfgNode::GetChild (const char *pszName, unsigned uIndex, CfgNode **ppnode)
1660{
1661 return pConfiguration->getNode (pdomnode, pszName, uIndex, ppnode, fSearch);
1662}
1663
1664int CfgNode::CreateChildNode (const char *pszName, CfgNode **ppnode)
1665{
1666 return pConfiguration->getNode (pdomnode, pszName, 0, ppnode, fCreateIfNotExists);
1667}
1668
1669int CfgNode::AppendChildNode (const char *pszName, CfgNode **ppnode)
1670{
1671 return pConfiguration->getNode (pdomnode, pszName, 0, ppnode, fAppend);
1672}
1673
1674int CfgNode::CountChildren (const char *pszChildName, unsigned *pCount)
1675{
1676 int rc = VINF_SUCCESS;
1677
1678 PRTUTF16 pwszChildName = NULL;
1679
1680 if (pszChildName)
1681 {
1682 rc = RTStrToUtf16 (pszChildName, &pwszChildName);
1683 }
1684
1685 if (VBOX_SUCCESS(rc))
1686 {
1687 DOMNode *child;
1688
1689 unsigned count = 0;
1690
1691 for (child = pdomnode->getFirstChild(); child != 0; child=child->getNextSibling())
1692 {
1693 if (child->getNodeType () == DOMNode::ELEMENT_NODE)
1694 {
1695 if (pwszChildName == NULL)
1696 {
1697 count++;
1698 }
1699 else if (XMLString::compareString (child->getNodeName (), pwszChildName) == 0)
1700 {
1701 count++;
1702 }
1703 }
1704 }
1705
1706 if (pwszChildName)
1707 {
1708 RTUtf16Free (pwszChildName);
1709 }
1710
1711 *pCount = count;
1712 }
1713
1714 return rc;
1715}
1716
1717DOMNode *CfgNode::findChildText (void)
1718{
1719 DOMNode *child = NULL;
1720
1721 for (child = pdomnode->getFirstChild(); child != 0; child=child->getNextSibling())
1722 {
1723 if (child->getNodeType () == DOMNode::TEXT_NODE)
1724 {
1725 break;
1726 }
1727 }
1728
1729 return child;
1730}
1731
1732/**
1733 * Gets the value of the given attribute as a UTF-16 string.
1734 * The returned string is owned by CfgNode, the caller must not free it.
1735 *
1736 * @param pszName Attribute name.
1737 * @param ppwszValue Where to store a pointer to the attribute value.
1738 *
1739 * @return IPRT status code.
1740 */
1741int CfgNode::getValueString (const char *pszName, PRTUTF16 *ppwszValue)
1742{
1743 int rc = VINF_SUCCESS;
1744
1745 PCRTUTF16 pwszValue = NULL;
1746
1747 if (!pszName)
1748 {
1749 DOMNode *ptext = findChildText ();
1750
1751 if (ptext)
1752 {
1753 pwszValue = ptext->getNodeValue ();
1754 }
1755 }
1756 else
1757 {
1758 PRTUTF16 pwszName = NULL;
1759
1760 rc = RTStrToUtf16 (pszName, &pwszName);
1761
1762 if (VBOX_SUCCESS(rc))
1763 {
1764 DOMAttr *attr = (static_cast<DOMElement *>(pdomnode))->getAttributeNode (pwszName);
1765 if (attr)
1766 {
1767 pwszValue = attr->getValue ();
1768 }
1769
1770 RTUtf16Free (pwszName);
1771 }
1772 }
1773
1774 if (!pwszValue)
1775 {
1776 *ppwszValue = NULL;
1777 rc = VERR_CFG_NO_VALUE;
1778 }
1779 else
1780 {
1781 *ppwszValue = (PRTUTF16)pwszValue;
1782 }
1783
1784 return rc;
1785}
1786
1787int CfgNode::setValueString (const char *pszName, PRTUTF16 pwszValue)
1788{
1789 int rc = VINF_SUCCESS;
1790
1791 if (!pszName)
1792 {
1793 DOMText *val = NULL;
1794
1795 try
1796 {
1797 val = pConfiguration->Document ()->createTextNode(pwszValue);
1798 }
1799
1800 catch (...)
1801 {
1802 rc = VERR_CFG_NO_VALUE;
1803 }
1804
1805 if (VBOX_SUCCESS(rc) && val)
1806 {
1807 try
1808 {
1809 DOMNode *poldtext = findChildText ();
1810
1811 if (poldtext)
1812 {
1813 pdomnode->replaceChild (val, poldtext);
1814 poldtext->release();
1815 }
1816 else
1817 {
1818 pdomnode->appendChild (val);
1819 }
1820 }
1821
1822 catch (...)
1823 {
1824 rc = VERR_CFG_NO_VALUE;
1825 val->release();
1826 }
1827 }
1828 }
1829 else
1830 {
1831 PRTUTF16 pwszName = NULL;
1832
1833 rc = RTStrToUtf16 (pszName, &pwszName);
1834
1835 if (VBOX_SUCCESS(rc))
1836 {
1837 try
1838 {
1839 static_cast<DOMElement *>(pdomnode)->setAttribute (pwszName, pwszValue);
1840 }
1841
1842 catch (...)
1843 {
1844 rc = VERR_CFG_NO_VALUE;
1845 }
1846 }
1847 }
1848
1849 return rc;
1850}
1851
1852int CfgNode::QueryUInt32 (const char *pszName, uint32_t *pulValue)
1853{
1854 int rc = VINF_SUCCESS;
1855
1856 PRTUTF16 pwszValue = NULL;
1857
1858 rc = getValueString (pszName, &pwszValue);
1859 if (VBOX_SUCCESS(rc))
1860 {
1861 uint32_t value = 0;
1862 char *pszValue = NULL;
1863
1864 rc = RTUtf16ToUtf8 (pwszValue, &pszValue);
1865 if (VBOX_SUCCESS (rc))
1866 {
1867 rc = RTStrToUInt32Ex (pszValue, NULL, 0, &value);
1868 if (VBOX_SUCCESS(rc))
1869 {
1870 *pulValue = value;
1871 }
1872
1873 RTStrFree (pszValue);
1874 }
1875 }
1876
1877 return rc;
1878}
1879
1880int CfgNode::SetUInt32 (const char *pszName, uint32_t ulValue, unsigned int uiBase)
1881{
1882 int rc = VINF_SUCCESS;
1883
1884 char szValue [64];
1885
1886 rc = RTStrFormatNumber (szValue, (uint64_t) ulValue, uiBase, 0, 0,
1887 RTSTR_F_32BIT | RTSTR_F_SPECIAL);
1888 if (VBOX_SUCCESS (rc))
1889 {
1890 PRTUTF16 pwszValue = NULL;
1891
1892 rc = RTStrToUtf16 (szValue, &pwszValue);
1893 if (VBOX_SUCCESS (rc))
1894 {
1895 rc = setValueString (pszName, pwszValue);
1896 RTUtf16Free (pwszValue);
1897 }
1898 }
1899
1900 return rc;
1901}
1902
1903int CfgNode::QueryUInt64 (const char *pszName, uint64_t *pullValue)
1904{
1905 int rc = VINF_SUCCESS;
1906
1907 PRTUTF16 pwszValue = NULL;
1908
1909 rc = getValueString (pszName, &pwszValue);
1910 if (VBOX_SUCCESS(rc))
1911 {
1912 uint64_t value = 0;
1913 char *pszValue = NULL;
1914
1915 rc = RTUtf16ToUtf8 (pwszValue, &pszValue);
1916 if (VBOX_SUCCESS (rc))
1917 {
1918 rc = RTStrToUInt64Ex (pszValue, NULL, 0, &value);
1919 if (VBOX_SUCCESS(rc))
1920 {
1921 *pullValue = value;
1922 }
1923
1924 RTStrFree (pszValue);
1925 }
1926 }
1927
1928 return rc;
1929}
1930
1931int CfgNode::SetUInt64 (const char *pszName, uint64_t ullValue, unsigned int uiBase)
1932{
1933 int rc = VINF_SUCCESS;
1934
1935 char szValue [64];
1936
1937 rc = RTStrFormatNumber (szValue, ullValue, uiBase, 0, 0,
1938 RTSTR_F_64BIT | RTSTR_F_SPECIAL);
1939 if (VBOX_SUCCESS (rc))
1940 {
1941 PRTUTF16 pwszValue = NULL;
1942
1943 rc = RTStrToUtf16 (szValue, &pwszValue);
1944 if (VBOX_SUCCESS (rc))
1945 {
1946 rc = setValueString (pszName, pwszValue);
1947 RTUtf16Free (pwszValue);
1948 }
1949 }
1950
1951 return rc;
1952}
1953
1954int CfgNode::QueryInt32 (const char *pszName, int32_t *plValue)
1955{
1956 int rc = VINF_SUCCESS;
1957
1958 PRTUTF16 pwszValue = NULL;
1959
1960 rc = getValueString (pszName, &pwszValue);
1961 if (VBOX_SUCCESS(rc))
1962 {
1963 int32_t value = 0;
1964 char *pszValue = NULL;
1965
1966 rc = RTUtf16ToUtf8 (pwszValue, &pszValue);
1967 if (VBOX_SUCCESS (rc))
1968 {
1969 rc = RTStrToInt32Ex (pszValue, NULL, 0, &value);
1970 if (VBOX_SUCCESS(rc))
1971 {
1972 *plValue = value;
1973 }
1974
1975 RTStrFree (pszValue);
1976 }
1977 }
1978
1979 return rc;
1980}
1981
1982int CfgNode::SetInt32 (const char *pszName, int32_t lValue, unsigned int uiBase)
1983{
1984 int rc = VINF_SUCCESS;
1985
1986 char szValue [64];
1987
1988 rc = RTStrFormatNumber (szValue, (uint64_t) lValue, uiBase, 0, 0,
1989 RTSTR_F_32BIT | RTSTR_F_VALSIGNED | RTSTR_F_SPECIAL);
1990 if (VBOX_SUCCESS (rc))
1991 {
1992 PRTUTF16 pwszValue = NULL;
1993
1994 rc = RTStrToUtf16 (szValue, &pwszValue);
1995 if (VBOX_SUCCESS (rc))
1996 {
1997 rc = setValueString (pszName, pwszValue);
1998 RTUtf16Free (pwszValue);
1999 }
2000 }
2001
2002 return rc;
2003}
2004
2005int CfgNode::QueryInt64 (const char *pszName, int64_t *pllValue)
2006{
2007 int rc = VINF_SUCCESS;
2008
2009 PRTUTF16 pwszValue = NULL;
2010
2011 rc = getValueString (pszName, &pwszValue);
2012 if (VBOX_SUCCESS(rc))
2013 {
2014 int64_t value = 0;
2015 char *pszValue = NULL;
2016
2017 rc = RTUtf16ToUtf8 (pwszValue, &pszValue);
2018 if (VBOX_SUCCESS (rc))
2019 {
2020 rc = RTStrToInt64Ex (pszValue, NULL, 0, &value);
2021 if (VBOX_SUCCESS(rc))
2022 {
2023 *pllValue = value;
2024 }
2025
2026 RTStrFree (pszValue);
2027 }
2028 }
2029
2030 return rc;
2031}
2032
2033int CfgNode::SetInt64 (const char *pszName, int64_t llValue, unsigned int uiBase)
2034{
2035 int rc = VINF_SUCCESS;
2036
2037 char szValue [64];
2038
2039 rc = RTStrFormatNumber (szValue, (uint64_t) llValue, uiBase, 0, 0,
2040 RTSTR_F_64BIT | RTSTR_F_VALSIGNED | RTSTR_F_SPECIAL);
2041 if (VBOX_SUCCESS (rc))
2042 {
2043 PRTUTF16 pwszValue = NULL;
2044
2045 rc = RTStrToUtf16 (szValue, &pwszValue);
2046 if (VBOX_SUCCESS (rc))
2047 {
2048 rc = setValueString (pszName, pwszValue);
2049 RTUtf16Free (pwszValue);
2050 }
2051 }
2052
2053 return rc;
2054}
2055
2056int CfgNode::QueryUInt16 (const char *pszName, uint16_t *puhValue)
2057{
2058 int rc = VINF_SUCCESS;
2059
2060 PRTUTF16 pwszValue = NULL;
2061
2062 rc = getValueString (pszName, &pwszValue);
2063 if (VBOX_SUCCESS(rc))
2064 {
2065 uint16_t value = 0;
2066 char *pszValue = NULL;
2067
2068 rc = RTUtf16ToUtf8 (pwszValue, &pszValue);
2069 if (VBOX_SUCCESS (rc))
2070 {
2071 rc = RTStrToUInt16Ex (pszValue, NULL, 0, &value);
2072 if (VBOX_SUCCESS(rc))
2073 {
2074 *puhValue = value;
2075 }
2076
2077 RTStrFree (pszValue);
2078 }
2079 }
2080
2081 return rc;
2082}
2083
2084int CfgNode::SetUInt16 (const char *pszName, uint16_t uhValue, unsigned int uiBase)
2085{
2086 int rc = VINF_SUCCESS;
2087
2088 char szValue [64];
2089
2090 rc = RTStrFormatNumber (szValue, (uint64_t) uhValue, uiBase, 0, 0,
2091 RTSTR_F_16BIT | RTSTR_F_SPECIAL);
2092 if (VBOX_SUCCESS (rc))
2093 {
2094 PRTUTF16 pwszValue = NULL;
2095
2096 rc = RTStrToUtf16 (szValue, &pwszValue);
2097 if (VBOX_SUCCESS (rc))
2098 {
2099 rc = setValueString (pszName, pwszValue);
2100 RTUtf16Free (pwszValue);
2101 }
2102 }
2103
2104 return rc;
2105}
2106
2107int CfgNode::QueryBin (const char *pszName, void *pvValue, unsigned cbValue, unsigned *pcbValue)
2108{
2109 int rc = VINF_SUCCESS;
2110
2111 PRTUTF16 pwszValue = NULL;
2112
2113 rc = getValueString (pszName, &pwszValue);
2114 if (VBOX_SUCCESS(rc))
2115 {
2116 if ( (XMLString::stringLen (pwszValue) / 2) > cbValue)
2117 {
2118 rc = VERR_BUFFER_OVERFLOW;
2119 }
2120 else if (!pvValue)
2121 {
2122 rc = VERR_INVALID_POINTER;
2123 }
2124 else
2125 {
2126 rc = wstr_to_bin (pwszValue, pvValue, cbValue, pcbValue);
2127 }
2128 }
2129
2130 return rc;
2131}
2132
2133int CfgNode::SetBin (const char *pszName, const void *pvValue, unsigned cbValue)
2134{
2135 int rc = VINF_SUCCESS;
2136
2137 PRTUTF16 pwszValue = NULL;
2138
2139 rc = bin_to_wstr (pvValue, cbValue, &pwszValue);
2140 if (VBOX_SUCCESS (rc))
2141 {
2142 rc = setValueString (pszName, pwszValue);
2143 RTUtf16Free (pwszValue);
2144 }
2145
2146 return rc;
2147}
2148
2149int CfgNode::QueryString (const char *pszName, void **pValue, unsigned cbValue, unsigned *pcbValue, bool returnUtf16)
2150{
2151 int rc = VINF_SUCCESS;
2152
2153 PRTUTF16 pwszValue = NULL;
2154
2155 // start with 0 bytes return value
2156 if (pcbValue)
2157 *pcbValue = 0;
2158
2159 rc = getValueString (pszName, &pwszValue);
2160
2161 if (VBOX_SUCCESS(rc))
2162 {
2163 if (returnUtf16)
2164 {
2165 // make a copy
2166 *pValue = (void*)SysAllocString((const OLECHAR*)pwszValue);
2167 } else
2168 {
2169 char *psz = NULL;
2170
2171 rc = RTUtf16ToUtf8 (pwszValue, &psz);
2172
2173 if (VBOX_SUCCESS(rc))
2174 {
2175 unsigned l = strlen (psz) + 1; // take trailing nul to account
2176
2177 *pcbValue = l;
2178
2179 if (l > cbValue)
2180 {
2181 rc = VERR_BUFFER_OVERFLOW;
2182 }
2183 else if (!*pValue)
2184 {
2185 rc = VERR_INVALID_POINTER;
2186 }
2187 else
2188 {
2189 memcpy (*pValue, psz, l);
2190 }
2191
2192 RTStrFree (psz);
2193 }
2194 }
2195 }
2196 return rc;
2197}
2198
2199int CfgNode::SetString (const char *pszName, const char *pszValue, unsigned cbValue, bool isUtf16)
2200{
2201 int rc = VINF_SUCCESS;
2202
2203 PRTUTF16 pwszValue = NULL;
2204
2205 if (isUtf16)
2206 pwszValue = (PRTUTF16)pszValue;
2207 else
2208 rc = RTStrToUtf16 (pszValue, &pwszValue);
2209
2210 if (VBOX_SUCCESS (rc))
2211 {
2212 rc = setValueString (pszName, pwszValue);
2213
2214 if (!isUtf16)
2215 RTUtf16Free (pwszValue);
2216 }
2217
2218 return rc;
2219}
2220
2221int CfgNode::QueryBool (const char *pszName, bool *pfValue)
2222{
2223 int rc = VINF_SUCCESS;
2224
2225 PRTUTF16 pwszValue = NULL;
2226 rc = getValueString (pszName, &pwszValue);
2227 if (VBOX_SUCCESS (rc))
2228 {
2229 char *pszValue = NULL;
2230 rc = RTUtf16ToUtf8 (pwszValue, &pszValue);
2231 if (VBOX_SUCCESS (rc))
2232 {
2233 if ( !stricmp (pszValue, "true")
2234 || !stricmp (pszValue, "yes")
2235 || !stricmp (pszValue, "on"))
2236 *pfValue = true;
2237 else if ( !stricmp (pszValue, "false")
2238 || !stricmp (pszValue, "no")
2239 || !stricmp (pszValue, "off"))
2240 *pfValue = false;
2241 else
2242 rc = VERR_CFG_INVALID_FORMAT;
2243 RTStrFree (pszValue);
2244 }
2245 }
2246
2247 return rc;
2248}
2249
2250int CfgNode::SetBool (const char *pszName, bool fValue)
2251{
2252 return SetString (pszName, fValue ? "true" : "false", fValue ? 4 : 5, false);
2253}
2254
2255int CfgNode::DeleteAttribute (const char *pszName)
2256{
2257 int rc = VINF_SUCCESS;
2258
2259 PRTUTF16 pwszName = NULL;
2260
2261 rc = RTStrToUtf16 (pszName, &pwszName);
2262
2263 if (VBOX_SUCCESS (rc))
2264 {
2265 try
2266 {
2267 (static_cast<DOMElement *>(pdomnode))->removeAttribute (pwszName);
2268 }
2269
2270 catch (...)
2271 {
2272 rc = VERR_CFG_NO_VALUE;
2273 }
2274
2275 RTUtf16Free (pwszName);
2276 }
2277
2278 return rc;
2279}
2280
2281/* Configuration loader public entry points.
2282 */
2283
2284CFGLDRR3DECL(int) CFGLDRCreate(CFGHANDLE *phcfg)
2285{
2286 if (!phcfg)
2287 {
2288 return VERR_INVALID_POINTER;
2289 }
2290
2291 CfgLoader *pcfgldr = new CfgLoader ();
2292
2293 if (!pcfgldr)
2294 {
2295 return VERR_NO_MEMORY;
2296 }
2297
2298 int rc = pcfgldr->Create();
2299
2300 if (VBOX_SUCCESS(rc))
2301 {
2302 *phcfg = pcfgldr;
2303 }
2304 else
2305 {
2306 delete pcfgldr;
2307 }
2308
2309 return rc;
2310}
2311
2312CFGLDRR3DECL(int) CFGLDRLoad (CFGHANDLE *phcfg,
2313 const char *pszFileName, RTFILE hFileHandle,
2314 const char *pszExternalSchemaLocation, bool bDoNamespaces,
2315 PFNCFGLDRENTITYRESOLVER pfnEntityResolver,
2316 char **ppszErrorMessage)
2317{
2318 if (!phcfg || !pszFileName)
2319 return VERR_INVALID_POINTER;
2320
2321 CfgLoader *pcfgldr = new CfgLoader();
2322 if (!pcfgldr)
2323 return VERR_NO_MEMORY;
2324
2325 int rc = pcfgldr->Load (pszFileName, hFileHandle,
2326 pszExternalSchemaLocation, bDoNamespaces,
2327 pfnEntityResolver, ppszErrorMessage);
2328
2329 if (VBOX_SUCCESS(rc))
2330 *phcfg = pcfgldr;
2331 else
2332 delete pcfgldr;
2333
2334 return rc;
2335}
2336
2337CFGLDRR3DECL(int) CFGLDRFree(CFGHANDLE hcfg)
2338{
2339 if (!hcfg)
2340 {
2341 return VERR_INVALID_HANDLE;
2342 }
2343
2344 CfgLoader::FreeConfiguration (hcfg);
2345
2346 return VINF_SUCCESS;
2347}
2348
2349CFGLDRR3DECL(int) CFGLDRSave(CFGHANDLE hcfg,
2350 char **ppszErrorMessage)
2351{
2352 if (!hcfg)
2353 {
2354 return VERR_INVALID_HANDLE;
2355 }
2356 return hcfg->Save (NULL, NIL_RTFILE, ppszErrorMessage);
2357}
2358
2359CFGLDRR3DECL(int) CFGLDRSaveAs(CFGHANDLE hcfg,
2360 const char *pszFilename, RTFILE hFileHandle,
2361 char **ppszErrorMessage)
2362{
2363 if (!hcfg)
2364 {
2365 return VERR_INVALID_HANDLE;
2366 }
2367 if (!pszFilename)
2368 {
2369 return VERR_INVALID_POINTER;
2370 }
2371 return hcfg->Save (pszFilename, hFileHandle, ppszErrorMessage);
2372}
2373
2374CFGLDRR3DECL(int) CFGLDRTransform (CFGHANDLE hcfg,
2375 const char *pszTemlateLocation,
2376 PFNCFGLDRENTITYRESOLVER pfnEntityResolver,
2377 char **ppszErrorMessage)
2378{
2379#ifdef VBOX_XML_XSLT
2380 if (!hcfg)
2381 {
2382 return VERR_INVALID_HANDLE;
2383 }
2384 if (!pszTemlateLocation)
2385 {
2386 return VERR_INVALID_POINTER;
2387 }
2388 return hcfg->Transform (pszTemlateLocation, pfnEntityResolver, ppszErrorMessage);
2389#else
2390 return VERR_NOT_SUPPORTED;
2391#endif
2392}
2393
2394CFGLDRR3DECL(int) CFGLDRGetNode(CFGHANDLE hcfg, const char *pszName, unsigned uIndex, CFGNODE *phnode)
2395{
2396 if (!hcfg)
2397 {
2398 return VERR_INVALID_HANDLE;
2399 }
2400 if (!phnode)
2401 {
2402 return VERR_INVALID_POINTER;
2403 }
2404 return hcfg->GetNode (pszName, uIndex, phnode);
2405}
2406
2407CFGLDRR3DECL(int) CFGLDRGetChildNode(CFGNODE hparent, const char *pszName, unsigned uIndex, CFGNODE *phnode)
2408{
2409 if (!hparent)
2410 {
2411 return VERR_INVALID_HANDLE;
2412 }
2413 if (!phnode)
2414 {
2415 return VERR_INVALID_POINTER;
2416 }
2417 return hparent->GetChild (pszName, uIndex, phnode);
2418}
2419
2420CFGLDRR3DECL(int) CFGLDRCreateNode(CFGHANDLE hcfg, const char *pszName, CFGNODE *phnode)
2421{
2422 if (!hcfg)
2423 {
2424 return VERR_INVALID_HANDLE;
2425 }
2426 if (!phnode || !pszName)
2427 {
2428 return VERR_INVALID_POINTER;
2429 }
2430 return hcfg->CreateNode (pszName, phnode);
2431}
2432
2433CFGLDRR3DECL(int) CFGLDRCreateChildNode(CFGNODE hparent, const char *pszName, CFGNODE *phnode)
2434{
2435 if (!hparent)
2436 {
2437 return VERR_INVALID_HANDLE;
2438 }
2439 if (!phnode || !pszName)
2440 {
2441 return VERR_INVALID_POINTER;
2442 }
2443 return hparent->CreateChildNode (pszName, phnode);
2444}
2445
2446CFGLDRR3DECL(int) CFGLDRAppendChildNode(CFGNODE hparent, const char *pszName, CFGNODE *phnode)
2447{
2448 if (!hparent)
2449 {
2450 return VERR_INVALID_HANDLE;
2451 }
2452 if (!phnode || !pszName)
2453 {
2454 return VERR_INVALID_POINTER;
2455 }
2456 return hparent->AppendChildNode (pszName, phnode);
2457}
2458
2459CFGLDRR3DECL(int) CFGLDRReleaseNode(CFGNODE hnode)
2460{
2461 if (!hnode)
2462 {
2463 return VERR_INVALID_HANDLE;
2464 }
2465 return CfgNode::ReleaseNode (hnode);
2466}
2467
2468CFGLDRR3DECL(int) CFGLDRDeleteNode(CFGNODE hnode)
2469{
2470 if (!hnode)
2471 {
2472 return VERR_INVALID_HANDLE;
2473 }
2474 return CfgNode::DeleteNode (hnode);
2475}
2476
2477CFGLDRR3DECL(int) CFGLDRCountChildren(CFGNODE hnode, const char *pszChildName, unsigned *pCount)
2478{
2479 if (!hnode)
2480 {
2481 return VERR_INVALID_HANDLE;
2482 }
2483 if (!pCount)
2484 {
2485 return VERR_INVALID_POINTER;
2486 }
2487 return hnode->CountChildren (pszChildName, pCount);
2488}
2489
2490CFGLDRR3DECL(int) CFGLDRQueryUInt32(CFGNODE hnode, const char *pszName, uint32_t *pulValue)
2491{
2492 if (!hnode)
2493 {
2494 return VERR_INVALID_HANDLE;
2495 }
2496 if (!pulValue)
2497 {
2498 return VERR_INVALID_POINTER;
2499 }
2500 return hnode->QueryUInt32 (pszName, pulValue);
2501}
2502
2503CFGLDRR3DECL(int) CFGLDRSetUInt32(CFGNODE hnode, const char *pszName, uint32_t ulValue)
2504{
2505 if (!hnode)
2506 {
2507 return VERR_INVALID_HANDLE;
2508 }
2509 return hnode->SetUInt32 (pszName, ulValue);
2510}
2511
2512CFGLDRR3DECL(int) CFGLDRSetUInt32Ex(CFGNODE hnode, const char *pszName, uint32_t ulValue, unsigned int uiBase)
2513{
2514 if (!hnode)
2515 {
2516 return VERR_INVALID_HANDLE;
2517 }
2518 return hnode->SetUInt32 (pszName, ulValue, uiBase);
2519}
2520
2521CFGLDRR3DECL(int) CFGLDRQueryUInt64(CFGNODE hnode, const char *pszName, uint64_t *pullValue)
2522{
2523 if (!hnode)
2524 {
2525 return VERR_INVALID_HANDLE;
2526 }
2527 if (!pullValue)
2528 {
2529 return VERR_INVALID_POINTER;
2530 }
2531 return hnode->QueryUInt64 (pszName, pullValue);
2532}
2533
2534CFGLDRR3DECL(int) CFGLDRSetUInt64(CFGNODE hnode, const char *pszName, uint64_t ullValue)
2535{
2536 if (!hnode)
2537 {
2538 return VERR_INVALID_HANDLE;
2539 }
2540 return hnode->SetUInt64 (pszName, ullValue);
2541}
2542
2543CFGLDRR3DECL(int) CFGLDRSetUInt64Ex(CFGNODE hnode, const char *pszName, uint64_t ullValue, unsigned int uiBase)
2544{
2545 if (!hnode)
2546 {
2547 return VERR_INVALID_HANDLE;
2548 }
2549 return hnode->SetUInt64 (pszName, ullValue, uiBase);
2550}
2551
2552CFGLDRR3DECL(int) CFGLDRQueryInt32(CFGNODE hnode, const char *pszName, int32_t *plValue)
2553{
2554 if (!hnode)
2555 {
2556 return VERR_INVALID_HANDLE;
2557 }
2558 return hnode->QueryInt32 (pszName, plValue);
2559}
2560
2561CFGLDRR3DECL(int) CFGLDRSetInt32(CFGNODE hnode, const char *pszName, int32_t lValue)
2562{
2563 if (!hnode)
2564 {
2565 return VERR_INVALID_HANDLE;
2566 }
2567 return hnode->SetInt32 (pszName, lValue);
2568}
2569
2570CFGLDRR3DECL(int) CFGLDRSetInt32Ex(CFGNODE hnode, const char *pszName, int32_t lValue, unsigned int uiBase)
2571{
2572 if (!hnode)
2573 {
2574 return VERR_INVALID_HANDLE;
2575 }
2576 return hnode->SetInt32 (pszName, lValue, uiBase);
2577}
2578
2579CFGLDRR3DECL(int) CFGLDRQueryInt64(CFGNODE hnode, const char *pszName, int64_t *pllValue)
2580{
2581 if (!hnode)
2582 {
2583 return VERR_INVALID_HANDLE;
2584 }
2585 return hnode->QueryInt64 (pszName, pllValue);
2586}
2587
2588CFGLDRR3DECL(int) CFGLDRSetInt64(CFGNODE hnode, const char *pszName, int64_t llValue)
2589{
2590 if (!hnode)
2591 {
2592 return VERR_INVALID_HANDLE;
2593 }
2594 return hnode->SetInt64 (pszName, llValue);
2595}
2596
2597CFGLDRR3DECL(int) CFGLDRSetInt64Ex(CFGNODE hnode, const char *pszName, int64_t llValue, unsigned int uiBase)
2598{
2599 if (!hnode)
2600 {
2601 return VERR_INVALID_HANDLE;
2602 }
2603 return hnode->SetInt64 (pszName, llValue, uiBase);
2604}
2605
2606CFGLDRR3DECL(int) CFGLDRQueryUInt16(CFGNODE hnode, const char *pszName, uint16_t *puhValue)
2607{
2608 if (!hnode)
2609 {
2610 return VERR_INVALID_HANDLE;
2611 }
2612 if (!puhValue)
2613 {
2614 return VERR_INVALID_POINTER;
2615 }
2616 return hnode->QueryUInt16 (pszName, puhValue);
2617}
2618
2619CFGLDRR3DECL(int) CFGLDRSetUInt16(CFGNODE hnode, const char *pszName, uint16_t uhValue)
2620{
2621 if (!hnode)
2622 {
2623 return VERR_INVALID_HANDLE;
2624 }
2625 return hnode->SetUInt16 (pszName, uhValue);
2626}
2627
2628CFGLDRR3DECL(int) CFGLDRSetUInt16Ex(CFGNODE hnode, const char *pszName, uint16_t uhValue, unsigned int uiBase)
2629{
2630 if (!hnode)
2631 {
2632 return VERR_INVALID_HANDLE;
2633 }
2634 return hnode->SetUInt16 (pszName, uhValue, uiBase);
2635}
2636
2637CFGLDRR3DECL(int) CFGLDRQueryBin(CFGNODE hnode, const char *pszName, void *pvValue, unsigned cbValue, unsigned *pcbValue)
2638{
2639 if (!hnode)
2640 {
2641 return VERR_INVALID_HANDLE;
2642 }
2643 if (!pcbValue)
2644 {
2645 return VERR_INVALID_POINTER;
2646 }
2647 return hnode->QueryBin (pszName, pvValue, cbValue, pcbValue);
2648}
2649
2650CFGLDRR3DECL(int) CFGLDRSetBin(CFGNODE hnode, const char *pszName, void *pvValue, unsigned cbValue)
2651{
2652 if (!hnode)
2653 {
2654 return VERR_INVALID_HANDLE;
2655 }
2656 if (!pvValue)
2657 {
2658 return VERR_INVALID_POINTER;
2659 }
2660 return hnode->SetBin (pszName, pvValue, cbValue);
2661}
2662
2663CFGLDRR3DECL(int) CFGLDRQueryString(CFGNODE hnode, const char *pszName, char *pszValue, unsigned cbValue, unsigned *pcbValue)
2664{
2665 if (!hnode)
2666 {
2667 return VERR_INVALID_HANDLE;
2668 }
2669 if (!pcbValue)
2670 {
2671 return VERR_INVALID_POINTER;
2672 }
2673 return hnode->QueryString (pszName, (void**)&pszValue, cbValue, pcbValue, false);
2674}
2675
2676CFGLDRR3DECL(int) CFGLDRQueryBSTR(CFGNODE hnode, const char *pszName, BSTR *ppwszValue)
2677{
2678 if (!hnode)
2679 {
2680 return VERR_INVALID_HANDLE;
2681 }
2682 if (!ppwszValue)
2683 {
2684 return VERR_INVALID_POINTER;
2685 }
2686 return hnode->QueryString(pszName, (void**)ppwszValue, 0, NULL, true);
2687}
2688
2689CFGLDRR3DECL(int) CFGLDRQueryUUID(CFGNODE hnode, const char *pszName, PRTUUID pUUID)
2690{
2691 if (!hnode)
2692 {
2693 return VERR_INVALID_HANDLE;
2694 }
2695 if (!pUUID)
2696 {
2697 return VERR_INVALID_POINTER;
2698 }
2699
2700 // we need it as UTF8
2701 unsigned size;
2702 int rc;
2703 rc = CFGLDRQueryString(hnode, pszName, NULL, 0, &size);
2704 if (rc == VERR_BUFFER_OVERFLOW)
2705 {
2706 char *uuidUtf8 = new char[size];
2707 rc = CFGLDRQueryString(hnode, pszName, uuidUtf8, size, &size);
2708 if (VBOX_SUCCESS(rc))
2709 {
2710 // remove the curly brackets
2711 uuidUtf8[strlen(uuidUtf8) - 1] = '\0';
2712 rc = RTUuidFromStr(pUUID, &uuidUtf8[1]);
2713 }
2714 delete[] uuidUtf8;
2715 }
2716 return rc;
2717}
2718
2719CFGLDRR3DECL(int) CFGLDRSetUUID(CFGNODE hnode, const char *pszName, PCRTUUID pUuid)
2720{
2721 if (!hnode)
2722 {
2723 return VERR_INVALID_HANDLE;
2724 }
2725 if (!pUuid)
2726 {
2727 return VERR_INVALID_HANDLE;
2728 }
2729
2730 // UUID + curly brackets
2731 char strUuid[RTUUID_STR_LENGTH + 2 * sizeof(char)];
2732 strUuid[0] = '{';
2733 RTUuidToStr((const PRTUUID)pUuid, &strUuid[1], RTUUID_STR_LENGTH);
2734 strcat(strUuid, "}");
2735 return hnode->SetString (pszName, strUuid, strlen (strUuid), false);
2736}
2737
2738CFGLDRR3DECL(int) CFGLDRSetString(CFGNODE hnode, const char *pszName, const char *pszValue)
2739{
2740 if (!hnode)
2741 {
2742 return VERR_INVALID_HANDLE;
2743 }
2744 if (!pszValue)
2745 {
2746 return VERR_INVALID_POINTER;
2747 }
2748 return hnode->SetString (pszName, pszValue, strlen (pszValue), false);
2749}
2750
2751CFGLDRR3DECL(int) CFGLDRSetBSTR(CFGNODE hnode, const char *pszName, const BSTR bstrValue)
2752{
2753 if (!hnode)
2754 {
2755 return VERR_INVALID_HANDLE;
2756 }
2757 if (!bstrValue)
2758 {
2759 return VERR_INVALID_POINTER;
2760 }
2761 return hnode->SetString (pszName, (char*)bstrValue, RTUtf16Len((PCRTUTF16)bstrValue), true);
2762}
2763
2764CFGLDRR3DECL(int) CFGLDRQueryBool(CFGNODE hnode, const char *pszName, bool *pfValue)
2765{
2766 if (!hnode)
2767 {
2768 return VERR_INVALID_HANDLE;
2769 }
2770 if (!pfValue)
2771 {
2772 return VERR_INVALID_POINTER;
2773 }
2774
2775 return hnode->QueryBool (pszName, pfValue);
2776}
2777
2778CFGLDRR3DECL(int) CFGLDRSetBool(CFGNODE hnode, const char *pszName, bool fValue)
2779{
2780 if (!hnode)
2781 {
2782 return VERR_INVALID_HANDLE;
2783 }
2784
2785 return hnode->SetBool (pszName, fValue);
2786}
2787
2788CFGLDRR3DECL(int) CFGLDRQueryDateTime(CFGNODE hnode, const char *pszName, int64_t *pi64Value)
2789{
2790 if (!hnode)
2791 {
2792 return VERR_INVALID_HANDLE;
2793 }
2794 if (!pi64Value)
2795 {
2796 return VERR_INVALID_POINTER;
2797 }
2798
2799 // query as UTF8 string
2800 unsigned size = 0;
2801 int rc = CFGLDRQueryString(hnode, pszName, NULL, 0, &size);
2802 if (rc != VERR_BUFFER_OVERFLOW)
2803 return rc;
2804
2805 char *pszValue = new char[size];
2806 char *pszBuf = new char[size];
2807 rc = CFGLDRQueryString(hnode, pszName, pszValue, size, &size);
2808 if (VBOX_SUCCESS(rc)) do
2809 {
2810 // Parse xsd:dateTime. The format is:
2811 // '-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)?
2812 // where zzzzzz is: (('+' | '-') hh ':' mm) | 'Z'
2813 uint32_t yyyy = 0;
2814 uint16_t mm = 0, dd = 0, hh = 0, mi = 0, ss = 0;
2815 if (sscanf(pszValue, "%d-%hu-%huT%hu:%hu:%hu%s",
2816 &yyyy, &mm, &dd, &hh, &mi, &ss, pszBuf) != 7)
2817 {
2818 rc = VERR_PARSE_ERROR;
2819 break;
2820 }
2821
2822 // currently, we accept only the UTC timezone ('Z'),
2823 // ignoring fractional seconds, if present
2824 if (pszBuf[0] == 'Z' ||
2825 (pszBuf[0] == '.' && pszBuf[strlen(pszBuf)-1] == 'Z'))
2826 {
2827 // start with an error
2828 rc = VERR_PARSE_ERROR;
2829
2830#if 0
2831 RTTIME time = { yyyy, mm, 0, 0, dd, hh, mm, ss, 0,
2832 RTTIME_FLAGS_TYPE_UTC };
2833 if (RTTimeNormalize(&time))
2834 {
2835 RTTIMESPEC timeSpec;
2836 if (RTTimeImplode(&time, &timeSpec))
2837 {
2838 *pi64Value = RTTimeSpecGetMilli(&timeSpec);
2839 rc = VINF_SUCCESS;
2840 }
2841 }
2842#else
2843 /// @todo (dmik) until RTTimeImplode and friends are done
2844 int isdst = 0;
2845 {
2846 time_t dummyt = time(NULL);
2847 isdst = localtime(&dummyt)->tm_isdst;
2848 }
2849 tm time;
2850 time.tm_hour = hh; /* hour (0 - 23) */
2851 time.tm_isdst = isdst; /* daylight saving time enabled/disabled */
2852 time.tm_mday = dd; /* day of month (1 - 31) */
2853 time.tm_min = mi; /* minutes (0 - 59) */
2854 time.tm_mon = mm - 1; /* month (0 - 11 : 0 = January) */
2855 time.tm_sec = ss; /* seconds (0 - 59) */
2856 time.tm_wday = 0; /* Day of week (0 - 6 : 0 = Sunday) */
2857 time.tm_yday = 0; /* Day of year (0 - 365) */
2858 time.tm_year = yyyy - 1900; /* Year less 1900 */
2859 time_t t = mktime(&time);
2860 // mktime expects local time, but we supply it UTC,
2861 // do a trick to get the right time value
2862 tm *dummytm = gmtime(&t);
2863 dummytm->tm_isdst = isdst;
2864 time_t delta = t - mktime(dummytm);
2865 *pi64Value = t + delta;
2866 *pi64Value *= 1000;
2867 rc = VINF_SUCCESS;
2868#endif
2869 }
2870 else
2871 rc = VERR_PARSE_ERROR;
2872 }
2873 while (0);
2874
2875 delete[] pszBuf;
2876 delete[] pszValue;
2877
2878 return rc;
2879}
2880
2881CFGLDRR3DECL(int) CFGLDRSetDateTime(CFGNODE hnode, const char *pszName, int64_t i64Value)
2882{
2883 if (!hnode)
2884 {
2885 return VERR_INVALID_HANDLE;
2886 }
2887
2888#if 0
2889 RTTIMESPEC timeSpec;
2890 RTTimeSpecSetMilli(&timeSpec, i64Value);
2891 RTTIME time;
2892 RTTimeExplode(&time, &timeSpec);
2893#else
2894 /// @todo (dmik) until RTTimeImplode and friends are done
2895 time_t t = (time_t)(i64Value / 1000);
2896 tm *ptm = gmtime(&t);
2897 if (!ptm)
2898 return VERR_PARSE_ERROR;
2899 tm time = *ptm;
2900 time.tm_year += 1900;
2901 time.tm_mon += 1;
2902#endif
2903
2904 // Store xsd:dateTime. The format is:
2905 // '-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)?
2906 // where zzzzzz is: (('+' | '-') hh ':' mm) | 'Z'
2907 char aszBuf [256];
2908 RTStrPrintf(aszBuf, sizeof(aszBuf),
2909 "%04ld-%02hd-%02hdT%02hd:%02hd:%02hdZ",
2910#if 0
2911 time.i32Year, (uint16_t) time.u8Month, (uint16_t) time.u8MonthDay,
2912 (uint16_t) time.u8Hour, (uint16_t) time.u8Minute, (uint16_t) time.u8Second);
2913#else
2914 /// @todo (dmik) until RTTimeImplode and friends are done
2915 time.tm_year, time.tm_mon, time.tm_mday,
2916 time.tm_hour, time.tm_min, time.tm_sec);
2917#endif
2918
2919 return hnode->SetString (pszName, aszBuf, strlen (aszBuf), false);
2920}
2921
2922CFGLDRR3DECL(int) CFGLDRDeleteAttribute(CFGNODE hnode, const char *pszName)
2923{
2924 if (!hnode)
2925 {
2926 return VERR_INVALID_HANDLE;
2927 }
2928 if (!pszName)
2929 {
2930 return VERR_INVALID_POINTER;
2931 }
2932 return hnode->DeleteAttribute (pszName);
2933}
2934
2935CFGLDRR3DECL(int) CFGLDRInitialize (void)
2936{
2937 int rc = VINF_SUCCESS;
2938
2939 if (!initXML ())
2940 {
2941 rc = VERR_NOT_SUPPORTED;
2942 }
2943
2944 return rc;
2945}
2946
2947CFGLDRR3DECL(void) CFGLDRShutdown (void)
2948{
2949 /// @todo delete CfgLoaders
2950 terminateXML ();
2951}
2952
2953#ifdef STANDALONE_TEST
2954
2955#include <iprt/runtime.h>
2956
2957int main(int argc, char **argv)
2958{
2959 Log(("Configuration loader standalone test\n"));
2960
2961 CFGHANDLE hcfg = 0;
2962 CFGNODE hnode = 0;
2963 unsigned count = 0;
2964 unsigned i;
2965 char *cfgFilename = "vboxcfg.xml";
2966 char *cfgFilenameSaved = "testas.xml";
2967
2968 /*
2969 * Initialize the VBox runtime without loading
2970 * the kernel support driver
2971 */
2972 int rc = RTR3Init(false);
2973 if (VBOX_FAILURE(rc))
2974 {
2975 Log(("RTInit failed %d\n", rc));
2976 goto l_exit_0;
2977 }
2978
2979 rc = CFGLDRInitialize();
2980 if (VBOX_FAILURE(rc))
2981 {
2982 Log(("Initialize failed %d\n", rc));
2983 goto l_exit_0;
2984 }
2985
2986 rc = CFGLDRLoad(&hcfg, cfgFilename, "vboxcfg.xsd");
2987 if (VBOX_FAILURE(rc))
2988 {
2989 Log(("Load failed %d\n", rc));
2990 goto l_exit_0;
2991 }
2992
2993 printf("Configuration loaded from %s\n", cfgFilename);
2994
2995 rc = CFGLDRCreateNode(hcfg, "Configuration/Something/DeviceManager/DeviceList", &hnode);
2996 if (VBOX_FAILURE(rc))
2997 {
2998 Log(("CreateNode failed %d\n", rc));
2999 goto l_exit_1;
3000 }
3001 rc = CFGLDRSetString(hnode, "GUID", "testtestte");
3002 rc = CFGLDRReleaseNode(hnode);
3003
3004 rc = CFGLDRGetNode(hcfg, "Configuration/Managers/DeviceManager/DeviceList", 0, &hnode);
3005 if (VBOX_FAILURE(rc))
3006 {
3007 Log(("GetNode failed %d\n", rc));
3008 goto l_exit_1;
3009 }
3010
3011 rc = CFGLDRCountChildren(hnode, "Device", &count);
3012 if (VBOX_FAILURE(rc))
3013 {
3014 Log(("CountChildren failed %d\n", rc));
3015 goto l_exit_2;
3016 }
3017
3018 Log(("Number of child nodes %d\n", count));
3019
3020 for (i = 0; i < count; i++)
3021 {
3022 CFGNODE hchild = 0;
3023 unsigned cbValue;
3024 char szValue[256];
3025
3026 rc = CFGLDRGetChildNode(hnode, "Device", i, &hchild);
3027 if (VBOX_FAILURE(rc))
3028 {
3029 Log(("GetChildNode failed %d\n", rc));
3030 goto l_exit_2;
3031 }
3032
3033 unsigned dummy;
3034 rc = CFGLDRCountChildren(hchild, NULL, &dummy);
3035 Log(("Number of child nodes of Device %d\n", dummy));
3036
3037 int32_t value;
3038
3039 rc = CFGLDRQueryInt32(hchild, "int", &value);
3040 Log(("Child node %d (rc = %d): int = %d\n", i, rc, value));
3041
3042 rc = CFGLDRQueryString(hchild, NULL, szValue, sizeof (szValue), &cbValue);
3043 if (VBOX_FAILURE(rc))
3044 {
3045 Log(("QueryString failed %d\n", rc));
3046 }
3047 Log(("Child node %d: (length = %d) = '%s'\n", i, cbValue, szValue));
3048
3049 rc = CFGLDRSetString(hchild, "GUID", "testtesttest");
3050 if (VBOX_FAILURE(rc))
3051 {
3052 Log(("SetString failed %d\n", rc));
3053 }
3054
3055 rc = CFGLDRDeleteAttribute(hchild, "int");
3056 Log(("Attribute delete %d (rc = %d)\n", i, rc));
3057
3058 CFGLDRSetBin(hchild, "Bin", (void *)CFGLDRSetBin, 100);
3059 CFGLDRSetInt32(hchild, "int32", 1973);
3060// CFGLDRSetUInt64(hchild, "uint64", 0x1973);
3061
3062 CFGNODE hnew = 0;
3063 CFGLDRCreateChildNode(hchild, "testnode", &hnew);
3064 rc = CFGLDRSetString(hchild, NULL, "her");
3065 if (VBOX_FAILURE(rc))
3066 {
3067 Log(("_SetString failed %d\n", rc));
3068 }
3069 rc = CFGLDRSetString(hnew, NULL, "neher");
3070 if (VBOX_FAILURE(rc))
3071 {
3072 Log(("+SetString failed %d\n", rc));
3073 }
3074 CFGLDRReleaseNode(hchild);
3075 }
3076
3077 rc = CFGLDRSaveAs(hcfg, cfgFilenameSaved);
3078 if (VBOX_FAILURE(rc))
3079 {
3080 Log(("SaveAs failed %d\n", rc));
3081 goto l_exit_2;
3082 }
3083
3084 Log(("Configuration saved as %s\n", cfgFilenameSaved));
3085
3086l_exit_2:
3087
3088 rc = CFGLDRReleaseNode(hnode);
3089 if (VBOX_FAILURE(rc))
3090 {
3091 Log(("ReleaseNode failed %d\n", rc));
3092 }
3093
3094l_exit_1:
3095
3096 rc = CFGLDRFree(hcfg);
3097 if (VBOX_FAILURE(rc))
3098 {
3099 Log(("Load failed %d\n", rc));
3100 }
3101
3102l_exit_0:
3103
3104 CFGLDRShutdown();
3105
3106 Log(("Test completed."));
3107 return rc;
3108}
3109#endif
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