VirtualBox

source: vbox/trunk/include/VBox/settings.h@ 21217

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

include/VBox/*.h: Mark which components the header files relate to.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 41.7 KB
Line 
1/** @file
2 * Settings File Manipulation API. (Main)
3 */
4
5/*
6 * Copyright (C) 2007 Sun Microsystems, Inc.
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 *
25 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
26 * Clara, CA 95054 USA or visit http://www.sun.com if you need
27 * additional information or have any questions.
28 */
29
30#ifndef ___VBox_settings_h
31#define ___VBox_settings_h
32
33#include <limits>
34
35#include <iprt/cdefs.h>
36#include <iprt/cpputils.h>
37#include <iprt/time.h>
38#include <iprt/xml_cpp.h>
39
40#include <VBox/com/Guid.h>
41
42/* these conflict with numeric_digits<>::min and max */
43#undef min
44#undef max
45
46
47/** @defgroup grp_settings Settings File Manipulation API
48 * @{
49 *
50 * The Settings File Manipulation API allows to maintain a configuration file
51 * that contains "name-value" pairs grouped under named keys which are in turn
52 * organized in a hierarchical tree-like structure:
53 *
54 * @code
55 * <RootKey>
56 * <Key1 attr1="value" attr2=""/>
57 * <Key2 attr1="value">
58 * <SubKey1>SubKey1_Value</SubKey1>
59 * <SubKey2 attr1="value">SubKey2_Value</SubKey2>
60 * Key2_Value
61 * </Key2>
62 * </RootKey>
63 * @endcode
64 *
65 * All strings this API manipulates with are zero-terminated arrays of @c char
66 * in UTF-8 encoding. Strings returned by the API are owned by the API unless
67 * explicitly stated otherwise. Strings passed to the API are accessed by the
68 * API only during the given API call unless explicitly stated otherwise. If
69 * necessary, the API will make a copy of the supplied string.
70 *
71 * Error reporting is perfomed using C++ exceptions. All exceptions thrown by
72 * this API are derived from settings::Error. This doesn't cover exceptions
73 * that may be thrown by third-party library calls made by this API.
74 *
75 * All public classes represented by this API that support copy operations
76 * (i.e. may be created or assigned from other instsances of the same class),
77 * such as Key and Value classes, implement shallow copies and use this mode by
78 * default. It means two things:
79 *
80 * 1. Instances of these classes can be freely copied around and used as return
81 * values. All copies will share the same internal data block (using the
82 * reference counting technique) so that the copy operation is cheap, both
83 * in terms of memory and speed.
84 *
85 * 2. Since copied instances share the same data, an attempt to change data in
86 * the original will be reflected in all existing copies.
87 *
88 * Making deep copies or detaching the existing shallow copy from its original
89 * is not yet supported.
90 *
91 * Note that the Settings File API is not thread-safe. It means that if you
92 * want to use the same instance of a class from the settings namespace on more
93 * than one thread at a time, you will have to provide necessary access
94 * serialization yourself.
95 *
96 * Due to some (not propely studied) libxml2 limitations, the Settings File
97 * API is not thread-safe. Therefore, the API caller must provide
98 * serialization for threads using this API simultaneously. Note though that
99 * if the libxml2 library is (even imlicitly) used on some other thread which
100 * doesn't use this API (e.g. third-party code), it may lead to resource
101 * conflicts (followed by crashes, memory corruption etc.). A proper solution
102 * for these conflicts is to be found.
103 *
104 * In order to load a settings file the program creates a TreeBackend instance
105 * using one of the specific backends (e.g. XmlTreeBackend) and then passes an
106 * Input stream object (e.g. File or MemoryBuf) to the TreeBackend::read()
107 * method to parse the stream and build the settings tree. On success, the
108 * program uses the TreeBackend::rootKey() method to access the root key of
109 * the settings tree. The root key provides access to the whole tree of
110 * settings through the methods of the Key class which allow to read, change
111 * and create new key values. Below is an example that uses the XML backend to
112 * load the settings tree, then modifies it and then saves the modifications.
113 *
114 * @code
115 using namespace settings;
116
117 try
118 {
119 File file (File::ReadWrite, "myfile.xml");
120 XmlTreeBackend tree;
121
122 // load the tree, parse it and validate using the XML schema
123 tree.read (aFile, "myfile.xsd", XmlTreeBackend::Read_AddDefaults);
124
125 // get the root key
126 Key root = tree.key();
127 printf ("root=%s\n", root.name());
128
129 // enumerate all child keys of the root key named Foo
130 Key::list children = root.keys ("Foo");
131 for (Key::list::const_iterator it = children.begin();
132 it != children.end();
133 ++ it)
134 {
135 // get the "level" attribute
136 int level = (*it).value <int> ("level");
137 if (level > 5)
138 {
139 // if so, create a "Bar" key if it doesn't exist yet
140 Key bar = (*it).createKey ("Bar");
141 // set the "date" attribute
142 RTTIMESPEC now;
143 RTTimeNow (&now);
144 bar.setValue <RTTIMESPEC> ("date", now);
145 }
146 else if (level < 2)
147 {
148 // if its below 2, delete the whole "Foo" key
149 (*it).zap();
150 }
151 }
152
153 // save the tree on success (the second try is to distinguish between
154 // stream load and save errors)
155 try
156 {
157 aTree.write (aFile);
158 }
159 catch (const EIPRTFailure &err)
160 {
161 // this is an expected exception that may happen in case of stream
162 // read or write errors
163 printf ("Could not save the settings file '%s' (%Rrc)");
164 file.uri(), err.rc());
165
166 return FAILURE;
167 }
168
169 return SUCCESS;
170 }
171 catch (const EIPRTFailure &err)
172 {
173 // this is an expected exception that may happen in case of stream
174 // read or write errors
175 printf ("Could not load the settings file '%s' (%Rrc)");
176 file.uri(), err.rc());
177 }
178 catch (const XmlTreeBackend::Error &err)
179 {
180 // this is an XmlTreeBackend specific exception that may
181 // happen in case of XML parse or validation errors
182 printf ("Could not load the settings file '%s'.\n%s"),
183 file.uri(), err.what() ? err.what() : "Unknown error");
184 }
185 catch (const std::exception &err)
186 {
187 // the rest is unexpected (e.g. should not happen unless you
188 // specifically wish so for some reason and therefore allow for a
189 // situation that may throw one of these from within the try block
190 // above)
191 AssertMsgFailed ("Unexpected exception '%s' (%s)\n",
192 typeid (err).name(), err.what());
193 }
194 catch (...)
195 {
196 // this is even more unexpected, and no any useful info here
197 AssertMsgFailed ("Unexpected exception\n");
198 }
199
200 return FAILURE;
201 * @endcode
202 *
203 * Note that you can get a raw (string) value of the attribute using the
204 * Key::stringValue() method but often it's simpler and better to use the
205 * templated Key::value<>() method that can convert the string to a value of
206 * the given type for you (and throw exceptions when the converison is not
207 * possible). Similarly, the Key::setStringValue() method is used to set a raw
208 * string value and there is a templated Key::setValue<>() method to set a
209 * typed value which will implicitly convert it to a string.
210 *
211 * Currently, types supported by Key::value<>() and Key::setValue<>() include
212 * all C and IPRT integer types, bool and RTTIMESPEC (represented as isoDate
213 * in XML). You can always add support for your own types by creating
214 * additional specializations of the FromString<>() and ToString<>() templates
215 * in the settings namespace (see the real examples in this header).
216 *
217 * See individual funciton, class and method descriptions to get more details
218 * on the Settings File Manipulation API.
219 */
220
221/*
222 * Shut up MSVC complaining that auto_ptr[_ref] template instantiations (as a
223 * result of private data member declarations of some classes below) need to
224 * be exported too to in order to be accessible by clients.
225 *
226 * The alternative is to instantiate a template before the data member
227 * declaration with the VBOXXML_CLASS prefix, but the standard disables
228 * explicit instantiations in a foreign namespace. In other words, a declaration
229 * like:
230 *
231 * template class VBOXXML_CLASS std::auto_ptr <Data>;
232 *
233 * right before the member declaration makes MSVC happy too, but this is not a
234 * valid C++ construct (and G++ spits it out). So, for now we just disable the
235 * warning and will come back to this problem one day later.
236 *
237 * We also disable another warning (4275) saying that a DLL-exported class
238 * inherits form a non-DLL-exported one (e.g. settings::ENoMemory ->
239 * std::bad_alloc). I can't get how it can harm yet.
240 */
241#if defined(_MSC_VER)
242#pragma warning (disable:4251)
243#pragma warning (disable:4275)
244#endif
245
246/** @def IN_VBOXXML_R3
247 * Used to indicate whether we're inside the same link module as the
248 * XML Settings File Manipulation API.
249 *
250 * @todo should go to a separate common include together with VBOXXML2_CLASS
251 * once there becomes more than one header in the VBoxXML2 library.
252 */
253#ifdef DOXYGEN_RUNNING
254# define IN_VBOXXML_R3
255#endif
256
257/** @def VBOXXML_CLASS
258 * Class export/import wrapper. */
259#ifdef IN_VBOXXML_R3
260# define VBOXXML_CLASS DECLEXPORT_CLASS
261#else
262# define VBOXXML_CLASS DECLIMPORT_CLASS
263#endif
264
265/* Forwards */
266typedef struct _xmlParserInput xmlParserInput;
267typedef xmlParserInput *xmlParserInputPtr;
268typedef struct _xmlParserCtxt xmlParserCtxt;
269typedef xmlParserCtxt *xmlParserCtxtPtr;
270typedef struct _xmlError xmlError;
271typedef xmlError *xmlErrorPtr;
272
273
274/**
275 * Settings File Manipulation API namespace.
276 */
277namespace settings
278{
279
280// Exceptions (on top of vboxxml exceptions)
281//////////////////////////////////////////////////////////////////////////////
282
283class VBOXXML_CLASS ENoKey : public xml::LogicError
284{
285public:
286
287 ENoKey (const char *aMsg = NULL) : xml::LogicError (aMsg) {}
288};
289
290class VBOXXML_CLASS ENoValue : public xml::LogicError
291{
292public:
293
294 ENoValue (const char *aMsg = NULL) : xml::LogicError (aMsg) {}
295};
296
297class VBOXXML_CLASS ENoConversion : public xml::RuntimeError
298{
299public:
300
301 ENoConversion (const char *aMsg = NULL) : RuntimeError (aMsg) {}
302};
303
304
305// Helpers
306//////////////////////////////////////////////////////////////////////////////
307
308// string -> type conversions
309//////////////////////////////////////////////////////////////////////////////
310
311/** @internal
312 * Helper for the FromString() template, doesn't need to be called directly.
313 */
314DECLEXPORT (uint64_t) FromStringInteger (const char *aValue, bool aSigned,
315 int aBits, uint64_t aMin, uint64_t aMax);
316
317/**
318 * Generic template function to perform a conversion of an UTF-8 string to an
319 * arbitrary value of type @a T.
320 *
321 * This generic template is implenented only for 8-, 16-, 32- and 64- bit
322 * signed and unsigned integers where it uses RTStrTo[U]Int64() to perform the
323 * conversion. For all other types it throws an ENotImplemented
324 * exception. Individual template specializations for known types should do
325 * the conversion job.
326 *
327 * If the conversion is not possible (for example the string format is wrong
328 * or meaningless for the given type), this template will throw an
329 * ENoConversion exception. All specializations must do the same.
330 *
331 * If the @a aValue argument is NULL, this method will throw an ENoValue
332 * exception. All specializations must do the same.
333 *
334 * @param aValue Value to convert.
335 *
336 * @return Result of conversion.
337 */
338template <typename T>
339T FromString (const char *aValue)
340{
341 if (std::numeric_limits <T>::is_integer)
342 {
343 bool sign = std::numeric_limits <T>::is_signed;
344 int bits = std::numeric_limits <T>::digits + (sign ? 1 : 0);
345
346 return (T) FromStringInteger (aValue, sign, bits,
347 (uint64_t) std::numeric_limits <T>::min(),
348 (uint64_t) std::numeric_limits <T>::max());
349 }
350
351 throw xml::ENotImplemented (RT_SRC_POS);
352}
353
354/**
355 * Specialization of FromString for bool.
356 *
357 * Converts "true", "yes", "on" to true and "false", "no", "off" to false.
358 */
359template<> DECLEXPORT (bool) FromString <bool> (const char *aValue);
360
361/**
362 * Specialization of FromString for RTTIMESPEC.
363 *
364 * Converts the date in ISO format (<YYYY>-<MM>-<DD>T<hh>:<mm>:<ss>[timezone])
365 * to a RTTIMESPEC value. Currently, the timezone must always be Z (UTC).
366 */
367template<> DECLEXPORT (RTTIMESPEC) FromString <RTTIMESPEC> (const char *aValue);
368
369/**
370 * Converts a string of hex digits to memory bytes.
371 *
372 * @param aValue String to convert.
373 * @param aLen Where to store the length of the returned memory
374 * block (may be NULL).
375 *
376 * @return Result of conversion (a block of @a aLen bytes).
377 */
378DECLEXPORT (stdx::char_auto_ptr) FromString (const char *aValue, size_t *aLen);
379
380// type -> string conversions
381//////////////////////////////////////////////////////////////////////////////
382
383/** @internal
384 * Helper for the ToString() template, doesn't need to be called directly.
385 */
386DECLEXPORT (stdx::char_auto_ptr)
387ToStringInteger (uint64_t aValue, unsigned int aBase,
388 bool aSigned, int aBits);
389
390/**
391 * Generic template function to perform a conversion of an arbitrary value to
392 * an UTF-8 string.
393 *
394 * This generic template is implemented only for 8-, 16-, 32- and 64- bit
395 * signed and unsigned integers where it uses RTStrFormatNumber() to perform
396 * the conversion. For all other types it throws an ENotImplemented
397 * exception. Individual template specializations for known types should do
398 * the conversion job. If the conversion is not possible (for example the
399 * given value doesn't have a string representation), the relevant
400 * specialization should throw an ENoConversion exception.
401 *
402 * If the @a aValue argument's value would convert to a NULL string, this
403 * method will throw an ENoValue exception. All specializations must do the
404 * same.
405 *
406 * @param aValue Value to convert.
407 * @param aExtra Extra flags to define additional formatting. In case of
408 * integer types, it's the base used for string representation.
409 *
410 * @return Result of conversion.
411 */
412template <typename T>
413stdx::char_auto_ptr ToString (const T &aValue, unsigned int aExtra = 0)
414{
415 if (std::numeric_limits <T>::is_integer)
416 {
417 bool sign = std::numeric_limits <T>::is_signed;
418 int bits = std::numeric_limits <T>::digits + (sign ? 1 : 0);
419
420 return ToStringInteger (aValue, aExtra, sign, bits);
421 }
422
423 throw xml::ENotImplemented (RT_SRC_POS);
424}
425
426/**
427 * Specialization of ToString for bool.
428 *
429 * Converts true to "true" and false to "false". @a aExtra is not used.
430 */
431template<> DECLEXPORT (stdx::char_auto_ptr)
432ToString <bool> (const bool &aValue, unsigned int aExtra);
433
434/**
435 * Specialization of ToString for RTTIMESPEC.
436 *
437 * Converts the RTTIMESPEC value to the date string in ISO format
438 * (<YYYY>-<MM>-<DD>T<hh>:<mm>:<ss>[timezone]). Currently, the timezone will
439 * always be Z (UTC).
440 *
441 * @a aExtra is not used.
442 */
443template<> DECLEXPORT (stdx::char_auto_ptr)
444ToString <RTTIMESPEC> (const RTTIMESPEC &aValue, unsigned int aExtra);
445
446/**
447 * Converts memory bytes to a null-terminated string of hex values.
448 *
449 * @param aData Pointer to the memory block.
450 * @param aLen Length of the memory block.
451 *
452 * @return Result of conversion.
453 */
454DECLEXPORT (stdx::char_auto_ptr) ToString (const void *aData, size_t aLen);
455
456#if defined VBOX_MAIN_SETTINGS_ADDONS
457
458/// @todo once string data in Bstr and Utf8Str is auto_ref_ptr, enable the
459/// code below
460
461#if 0
462
463/** Specialization of FromString for Bstr. */
464template<> com::Bstr FromString <com::Bstr> (const char *aValue);
465
466#endif
467
468/** Specialization of ToString for Bstr. */
469template<> stdx::char_auto_ptr
470ToString <com::Bstr> (const com::Bstr &aValue, unsigned int aExtra);
471
472/** Specialization of FromString for Guid. */
473template<> com::Guid FromString <com::Guid> (const char *aValue);
474
475/** Specialization of ToString for Guid. */
476template<> stdx::char_auto_ptr
477ToString <com::Guid> (const com::Guid &aValue, unsigned int aExtra);
478
479#endif // VBOX_MAIN_SETTINGS_ADDONS
480
481// the rest
482//////////////////////////////////////////////////////////////////////////////
483
484/**
485 * The Key class represents a settings key.
486 *
487 * Every settings key has a name and zero or more uniquely named values
488 * (attributes). There is a special attribute with a NULL name that is called
489 * a key value.
490 *
491 * Besides values, settings keys may contain other settings keys. This way,
492 * settings keys form a tree-like (or a directory-like) hierarchy of keys. Key
493 * names do not need to be unique even if they belong to the same parent key
494 * which allows to have an array of keys of the same name.
495 *
496 * @note Key and Value objects returned by methods of the Key and TreeBackend
497 * classes are owned by the given TreeBackend instance and may refer to data
498 * that becomes invalid when this TreeBackend instance is destroyed.
499 */
500class VBOXXML_CLASS Key
501{
502public:
503
504 typedef std::list <Key> List;
505
506 /**
507 * Key backend interface used to perform actual key operations.
508 *
509 * This interface is implemented by backends that provide specific ways of
510 * storing settings keys.
511 */
512 class VBOXXML_CLASS Backend : public stdx::auto_ref
513 {
514 public:
515
516 /** Performs the Key::name() function. */
517 virtual const char *name() const = 0;
518
519 /** Performs the Key::setName() function. */
520 virtual void setName (const char *aName) = 0;
521
522 /** Performs the Key::stringValue() function. */
523 virtual const char *value (const char *aName) const = 0;
524
525 /** Performs the Key::setStringValue() function. */
526 virtual void setValue (const char *aName, const char *aValue) = 0;
527
528 /** Performs the Key::keys() function. */
529 virtual List keys (const char *aName = NULL) const = 0;
530
531 /** Performs the Key::findKey() function. */
532 virtual Key findKey (const char *aName) const = 0;
533
534 /** Performs the Key::appendKey() function. */
535 virtual Key appendKey (const char *aName) = 0;
536
537 /** Performs the Key::zap() function. */
538 virtual void zap() = 0;
539
540 /**
541 * Returns an opaque value that uniquely represents the position of
542 * this key on the tree which is used to compare two keys. Two or more
543 * keys may return the same value only if they actually represent the
544 * same key (i.e. they have the same list of parents and children).
545 */
546 virtual void *position() const = 0;
547 };
548
549 /**
550 * Creates a new key object. If @a aBackend is @c NULL then a null key is
551 * created.
552 *
553 * Regular API users should never need to call this method with something
554 * other than NULL argument (which is the default).
555 *
556 * @param aBackend Key backend to use.
557 */
558 Key (Backend *aBackend = NULL) : m (aBackend) {}
559
560 /**
561 * Returns @c true if this key is null.
562 */
563 bool isNull() const { return m.is_null(); }
564
565 /**
566 * Makes this object a null key.
567 *
568 * Note that as opposed to #zap(), this methid does not delete the key from
569 * the list of children of its parent key.
570 */
571 void setNull() { m = NULL; }
572
573 /**
574 * Returns the name of this key.
575 * Returns NULL if this object a null (uninitialized) key.
576 */
577 const char *name() const { return m.is_null() ? NULL : m->name(); }
578
579 /**
580 * Sets the name of this key.
581 *
582 * @param aName New key name.
583 */
584 void setName (const char *aName) { if (!m.is_null()) m->setName (aName); }
585
586 /**
587 * Returns the value of the attribute with the given name as an UTF-8
588 * string. Returns @c NULL if there is no attribute with the given name.
589 *
590 * @param aName Name of the attribute. NULL may be used to
591 * get the key value.
592 */
593 const char *stringValue (const char *aName) const
594 {
595 return m.is_null() ? NULL : m->value (aName);
596 }
597
598 /**
599 * Sets the value of the attribute with the given name from an UTF-8
600 * string. This method will do a copy of the supplied @a aValue string.
601 *
602 * @param aName Name of the attribute. NULL may be used to
603 * set the key value.
604 * @param aValue New value of the attribute. NULL may be used to
605 * delete the value instead of setting it.
606 */
607 void setStringValue (const char *aName, const char *aValue)
608 {
609 if (!m.is_null()) m->setValue (aName, aValue);
610 }
611
612 /**
613 * Returns the value of the attribute with the given name as an object of
614 * type @a T. Throws ENoValue if there is no attribute with the given
615 * name.
616 *
617 * This function calls #stringValue() to get the string representation of
618 * the attribute and then calls the FromString() template to convert this
619 * string to a value of the given type.
620 *
621 * @param aName Name of the attribute. NULL may be used to
622 * get the key value.
623 */
624 template <typename T>
625 T value (const char *aName) const
626 {
627 try
628 {
629 return FromString <T> (stringValue (aName));
630 }
631 catch (const ENoValue &)
632 {
633 throw ENoValue(com::Utf8StrFmt("No such attribute '%s'", aName));
634 }
635 }
636
637 /**
638 * Returns the value of the attribute with the given name as an object of
639 * type @a T. Returns the given default value if there is no attribute
640 * with the given name.
641 *
642 * This function calls #stringValue() to get the string representation of
643 * the attribute and then calls the FromString() template to convert this
644 * string to a value of the given type.
645 *
646 * @param aName Name of the attribute. NULL may be used to
647 * get the key value.
648 * @param aDefault Default value to return for the missing attribute.
649 */
650 template <typename T>
651 T valueOr (const char *aName, const T &aDefault) const
652 {
653 try
654 {
655 return FromString <T> (stringValue (aName));
656 }
657 catch (const ENoValue &)
658 {
659 return aDefault;
660 }
661 }
662
663 /**
664 * Sets the value of the attribute with the given name from an object of
665 * type @a T. This method will do a copy of data represented by @a aValue
666 * when necessary.
667 *
668 * This function converts the given value to a string using the ToString()
669 * template and then calls #setStringValue().
670 *
671 * @param aName Name of the attribute. NULL may be used to
672 * set the key value.
673 * @param aValue New value of the attribute.
674 * @param aExtra Extra field used by some types to specify additional
675 * details for storing the value as a string (such as the
676 * base for decimal numbers).
677 */
678 template <typename T>
679 void setValue (const char *aName, const T &aValue, unsigned int aExtra = 0)
680 {
681 try
682 {
683 stdx::char_auto_ptr value = ToString (aValue, aExtra);
684 setStringValue (aName, value.get());
685 }
686 catch (const ENoValue &)
687 {
688 throw ENoValue(com::Utf8StrFmt("No value for attribute '%s'", aName));
689 }
690 }
691
692 /**
693 * Sets the value of the attribute with the given name from an object of
694 * type @a T. If the value of the @a aValue object equals to the value of
695 * the given @a aDefault object, then the attribute with the given name
696 * will be deleted instead of setting its value to @a aValue.
697 *
698 * This function converts the given value to a string using the ToString()
699 * template and then calls #setStringValue().
700 *
701 * @param aName Name of the attribute. NULL may be used to
702 * set the key value.
703 * @param aValue New value of the attribute.
704 * @param aDefault Default value to compare @a aValue to.
705 * @param aExtra Extra field used by some types to specify additional
706 * details for storing the value as a string (such as the
707 * base for decimal numbers).
708 */
709 template <typename T>
710 void setValueOr (const char *aName, const T &aValue, const T &aDefault,
711 unsigned int aExtra = 0)
712 {
713 if (aValue == aDefault)
714 zapValue (aName);
715 else
716 setValue <T> (aName, aValue, aExtra);
717 }
718
719 /**
720 * Deletes the value of the attribute with the given name.
721 * Shortcut to <tt>setStringValue(aName, NULL)</tt>.
722 */
723 void zapValue (const char *aName) { setStringValue (aName, NULL); }
724
725 /**
726 * Returns the key value.
727 * Shortcut to <tt>stringValue (NULL)</tt>.
728 */
729 const char *keyStringValue() const { return stringValue (NULL); }
730
731 /**
732 * Sets the key value.
733 * Shortcut to <tt>setStringValue (NULL, aValue)</tt>.
734 */
735 void setKeyStringValue (const char *aValue) { setStringValue (NULL, aValue); }
736
737 /**
738 * Returns the key value.
739 * Shortcut to <tt>value (NULL)</tt>.
740 */
741 template <typename T>
742 T keyValue() const { return value <T> (NULL); }
743
744 /**
745 * Returns the key value or the given default if the key value is NULL.
746 * Shortcut to <tt>value (NULL)</tt>.
747 */
748 template <typename T>
749 T keyValueOr (const T &aDefault) const { return valueOr <T> (NULL, aDefault); }
750
751 /**
752 * Sets the key value.
753 * Shortcut to <tt>setValue (NULL, aValue, aExtra)</tt>.
754 */
755 template <typename T>
756 void setKeyValue (const T &aValue, unsigned int aExtra = 0)
757 {
758 setValue <T> (NULL, aValue, aExtra);
759 }
760
761 /**
762 * Sets the key value.
763 * Shortcut to <tt>setValueOr (NULL, aValue, aDefault)</tt>.
764 */
765 template <typename T>
766 void setKeyValueOr (const T &aValue, const T &aDefault,
767 unsigned int aExtra = 0)
768 {
769 setValueOr <T> (NULL, aValue, aDefault, aExtra);
770 }
771
772 /**
773 * Deletes the key value.
774 * Shortcut to <tt>zapValue (NULL)</tt>.
775 */
776 void zapKeyValue () { zapValue (NULL); }
777
778 /**
779 * Returns a list of all child keys named @a aName.
780 *
781 * If @a aname is @c NULL, returns a list of all child keys.
782 *
783 * @param aName Child key name to list.
784 */
785 List keys (const char *aName = NULL) const
786 {
787 return m.is_null() ? List() : m->keys (aName);
788 };
789
790 /**
791 * Returns the first child key with the given name.
792 *
793 * Throws ENoKey if no child key with the given name exists.
794 *
795 * @param aName Child key name.
796 */
797 Key key (const char *aName) const
798 {
799 Key key = findKey (aName);
800 if (key.isNull())
801 {
802 throw ENoKey(com::Utf8StrFmt("No such key '%s'", aName));
803 }
804 return key;
805 }
806
807 /**
808 * Returns the first child key with the given name.
809 *
810 * As opposed to #key(), this method will not throw an exception if no
811 * child key with the given name exists, but return a null key instead.
812 *
813 * @param aName Child key name.
814 */
815 Key findKey (const char *aName) const
816 {
817 return m.is_null() ? Key() : m->findKey (aName);
818 }
819
820 /**
821 * Creates a key with the given name as a child of this key and returns it
822 * to the caller.
823 *
824 * If one or more child keys with the given name already exist, no new key
825 * is created but the first matching child key is returned.
826 *
827 * @param aName Name of the child key to create.
828 */
829 Key createKey (const char *aName)
830 {
831 Key key = findKey (aName);
832 if (key.isNull())
833 key = appendKey (aName);
834 return key;
835 }
836
837 /**
838 * Appends a key with the given name to the list of child keys of this key
839 * and returns the appended key to the caller.
840 *
841 * @param aName Name of the child key to create.
842 */
843 Key appendKey (const char *aName)
844 {
845 return m.is_null() ? Key() : m->appendKey (aName);
846 }
847
848 /**
849 * Deletes this key.
850 *
851 * The deleted key is removed from the list of child keys of its parent
852 * key and becomes a null object.
853 */
854 void zap()
855 {
856 if (!m.is_null())
857 {
858 m->zap();
859 setNull();
860 }
861 }
862
863 /**
864 * Compares this object with the given object and returns @c true if both
865 * represent the same key on the settings tree or if both are null
866 * objects.
867 *
868 * @param that Object to compare this object with.
869 */
870 bool operator== (const Key &that) const
871 {
872 return m == that.m ||
873 (!m.is_null() && !that.m.is_null() &&
874 m->position() == that.m->position());
875 }
876
877 /**
878 * Counterpart to operator==().
879 */
880 bool operator!= (const Key &that) const { return !operator== (that); }
881
882private:
883
884 stdx::auto_ref_ptr <Backend> m;
885
886 friend class TreeBackend;
887};
888
889/**
890 * The TreeBackend class represents a storage backend used to read a settings
891 * tree from and write it to a stream.
892 *
893 * @note All Key objects returned by any of the TreeBackend methods (and by
894 * methods of returned Key objects) are owned by the given TreeBackend
895 * instance. When this instance is destroyed, all Key objects become invalid
896 * and an attempt to access Key data will cause the program crash.
897 */
898class VBOXXML_CLASS TreeBackend
899{
900public:
901
902 /**
903 * Reads and parses the given input stream.
904 *
905 * On success, the previous settings tree owned by this backend (if any)
906 * is deleted.
907 *
908 * The optional schema URI argument determines the name of the schema to
909 * use for input validation. If the schema URI is NULL then the validation
910 * is not performed. Note that you may set a custom input resolver if you
911 * want to provide the input stream for the schema file (and for other
912 * external entities) instead of letting the backend to read the specified
913 * URI directly.
914 *
915 * This method will set the read/write position to the beginning of the
916 * given stream before reading. After the stream has been successfully
917 * parsed, the position will be set back to the beginning.
918 *
919 * @param aInput Input stream.
920 * @param aSchema Schema URI to use for input stream validation.
921 * @param aFlags Optional bit flags.
922 */
923 void read (xml::Input &aInput, const char *aSchema = NULL, int aFlags = 0)
924 {
925 aInput.setPos (0);
926 rawRead (aInput, aSchema, aFlags);
927 aInput.setPos (0);
928 }
929
930 /**
931 * Reads and parses the given input stream in a raw fashion.
932 *
933 * This method doesn't set the stream position to the beginnign before and
934 * after reading but instead leaves it as is in both cases. It's the
935 * caller's responsibility to maintain the correct position.
936 *
937 * @see read()
938 */
939 virtual void rawRead (xml::Input &aInput, const char *aSchema = NULL,
940 int aFlags = 0) = 0;
941
942 /**
943 * Writes the current settings tree to the given output stream.
944 *
945 * This method will set the read/write position to the beginning of the
946 * given stream before writing. After the settings have been successfully
947 * written to the stream, the stream will be truncated at the position
948 * following the last byte written by this method anc ghd position will be
949 * set back to the beginning.
950 *
951 * @param aOutput Output stream.
952 */
953 void write (xml::Output &aOutput)
954 {
955 aOutput.setPos (0);
956 rawWrite (aOutput);
957 aOutput.truncate();
958 aOutput.setPos (0);
959 }
960
961 /**
962 * Writes the current settings tree to the given output stream in a raw
963 * fashion.
964 *
965 * This method doesn't set the stream position to the beginnign before and
966 * after reading and doesn't truncate the stream, but instead leaves it as
967 * is in both cases. It's the caller's responsibility to maintain the
968 * correct position and perform truncation.
969 *
970 * @see write()
971 */
972 virtual void rawWrite (xml::Output &aOutput) = 0;
973
974 /**
975 * Deletes the current settings tree.
976 */
977 virtual void reset() = 0;
978
979 /**
980 * Returns the root settings key.
981 */
982 virtual Key &rootKey() const = 0;
983
984protected:
985
986 static Key::Backend *GetKeyBackend (const Key &aKey) { return aKey.m.raw(); }
987};
988
989class XmlKeyBackend;
990
991/**
992 * The XmlTreeBackend class uses XML markup to store settings trees.
993 *
994 * @note libxml2 and libxslt libraries used by the XmlTreeBackend are not
995 * fully reentrant. To "fix" this, the XmlTreeBackend backend serializes access
996 * to such non-reentrant parts using a global mutex so that only one thread can
997 * use non-reentrant code at a time. Currently, this relates to the #rawRead()
998 * method (and to #read() as a consequence). This means that only one thread can
999 * parse an XML stream at a time; other threads trying to parse same or
1000 * different streams using different XmlTreeBackend and Input instances
1001 * will have to wait.
1002 *
1003 * Keep in mind that the above reentrancy fix does not imply thread-safety: it
1004 * is still the caller's responsibility to provide serialization if the same
1005 * XmlTreeBackend instnace (as well as instances of other classes from the
1006 * settings namespace) needs to be used by more than one thread.
1007 */
1008class VBOXXML_CLASS XmlTreeBackend : public TreeBackend
1009{
1010public:
1011
1012 /** Flags for TreeBackend::read(). */
1013 enum
1014 {
1015 /**
1016 * Sbstitute default values for missing attributes that have defaults
1017 * in the XML schema. Otherwise, stringValue() will return NULL for
1018 * such attributes.
1019 */
1020 Read_AddDefaults = RT_BIT (0),
1021 };
1022
1023 /**
1024 * The EConversionCycle class represents a conversion cycle detected by the
1025 * AutoConverter::needsConversion() implementation.
1026 */
1027 class VBOXXML_CLASS EConversionCycle : public xml::RuntimeError
1028 {
1029 public:
1030
1031 EConversionCycle (const char *aMsg = NULL) : RuntimeError (aMsg) {}
1032 };
1033
1034 /**
1035 * The InputResolver class represents an interface to provide input streams
1036 * for external entities given an URL and entity ID.
1037 */
1038 class VBOXXML_CLASS InputResolver
1039 {
1040 public:
1041
1042 /**
1043 * Returns a newly allocated input stream for the given arguments. The
1044 * caller will delete the returned object when no more necessary.
1045 *
1046 * @param aURI URI of the external entity.
1047 * @param aID ID of the external entity (may be NULL).
1048 *
1049 * @return Input stream created using @c new or NULL to indicate
1050 * a wrong URI/ID pair.
1051 *
1052 * @todo Return by value after implementing the copy semantics for
1053 * Input subclasses.
1054 */
1055 virtual xml::Input *resolveEntity (const char *aURI, const char *aID) = 0;
1056 };
1057
1058 /**
1059 * The AutoConverter class represents an interface to automatically convert
1060 * old settings trees to a new version when the tree is read from the
1061 * stream.
1062 */
1063 class VBOXXML_CLASS AutoConverter
1064 {
1065 public:
1066
1067 /**
1068 * Returns @true if the given tree needs to be converted using the XSLT
1069 * template identified by #templateUri(), or @false if no conversion is
1070 * required.
1071 *
1072 * The implementation normally checks for the "version" value of the
1073 * root key to determine if the conversion is necessary. When the
1074 * @a aOldVersion argument is not NULL, the implementation must return a
1075 * non-NULL non-empty string representing the old version (before
1076 * conversion) in it this string is used by XmlTreeBackend::oldVersion()
1077 * and must be non-NULL to indicate that the conversion has been
1078 * performed on the tree. The returned string must be allocated using
1079 * RTStrDup() or such.
1080 *
1081 * This method is called again after the successful transformation to
1082 * let the implementation retry the version check and request another
1083 * transformation if necessary. This may be used to perform multi-step
1084 * conversion like this: 1.1 => 1.2, 1.2 => 1.3 (instead of 1.1 => 1.3)
1085 * which saves from the need to update all previous conversion
1086 * templates to make each of them convert directly to the recent
1087 * version.
1088 *
1089 * @note Multi-step transformations are performed in a loop that exits
1090 * only when this method returns @false. It's up to the
1091 * implementation to detect cycling (repeated requests to convert
1092 * from the same version) wrong version order, etc. and throw an
1093 * EConversionCycle exception to break the loop without returning
1094 * @false (which means the transformation succeeded).
1095 *
1096 * @param aRoot Root settings key.
1097 * @param aOldVersionString Where to store old version string
1098 * pointer. May be NULL. Allocated memory is
1099 * freed by the caller using RTStrFree().
1100 */
1101 virtual bool needsConversion (const Key &aRoot,
1102 char **aOldVersion) const = 0;
1103
1104 /**
1105 * Returns the URI of the XSLT template to perform the conversion.
1106 * This template will be applied to the tree if #needsConversion()
1107 * returns @c true for this tree.
1108 */
1109 virtual const char *templateUri() const = 0;
1110 };
1111
1112 XmlTreeBackend();
1113 ~XmlTreeBackend();
1114
1115 /**
1116 * Sets an external entity resolver used to provide input streams for
1117 * entities referred to by the XML document being parsed.
1118 *
1119 * The given resolver object must exist as long as this instance exists or
1120 * until a different resolver is set using setInputResolver() or reset
1121 * using resetInputResolver().
1122 *
1123 * @param aResolver Resolver to use.
1124 */
1125 void setInputResolver (InputResolver &aResolver);
1126
1127 /**
1128 * Resets the entity resolver to the default resolver. The default
1129 * resolver provides support for 'file:' and 'http:' protocols.
1130 */
1131 void resetInputResolver();
1132
1133 /**
1134 * Sets a settings tree converter and enables the automatic conversion.
1135 *
1136 * The Automatic settings tree conversion is useful for upgrading old
1137 * settings files to the new version transparently during execution of the
1138 * #read() method.
1139 *
1140 * The automatic conversion takes place after reading the document from the
1141 * stream but before validating it. The given converter is asked if the
1142 * conversion is necessary using the AutoConverter::needsConversion() call,
1143 * and if so, the XSLT template specified by AutoConverter::templateUri() is
1144 * applied to the settings tree.
1145 *
1146 * Note that in order to make the result of the conversion permanent, the
1147 * settings tree needs to be exlicitly written back to the stream.
1148 *
1149 * The given converter object must exist as long as this instance exists or
1150 * until a different converter is set using setAutoConverter() or reset
1151 * using resetAutoConverter().
1152 *
1153 * @param aConverter Settings converter to use.
1154 */
1155 void setAutoConverter (AutoConverter &aConverter);
1156
1157 /**
1158 * Disables the automatic settings conversion previously enabled by
1159 * setAutoConverter(). By default automatic conversion it is disabled.
1160 */
1161 void resetAutoConverter();
1162
1163 /**
1164 * Returns a non-NULL string if the automatic settings conversion has been
1165 * performed during the last successful #read() call. Returns @c NULL if
1166 * there was no settings conversion.
1167 *
1168 * If #read() fails, this method will return the version string set by the
1169 * previous successful #read() call or @c NULL if there were no #read()
1170 * calls.
1171 */
1172 const char *oldVersion() const;
1173
1174 void rawRead (xml::Input &aInput, const char *aSchema = NULL, int aFlags = 0);
1175 void rawWrite (xml::Output &aOutput);
1176 void reset();
1177 Key &rootKey() const;
1178
1179private:
1180
1181 /* Obscure class data */
1182 struct Data;
1183 std::auto_ptr <Data> m;
1184
1185 /* auto_ptr data doesn't have proper copy semantics */
1186 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (XmlTreeBackend)
1187
1188 static int ReadCallback (void *aCtxt, char *aBuf, int aLen);
1189 static int WriteCallback (void *aCtxt, const char *aBuf, int aLen);
1190 static int CloseCallback (void *aCtxt);
1191
1192 static void ValidityErrorCallback (void *aCtxt, const char *aMsg, ...);
1193 static void ValidityWarningCallback (void *aCtxt, const char *aMsg, ...);
1194 static void StructuredErrorCallback (void *aCtxt, xmlErrorPtr aErr);
1195
1196 static xmlParserInput *ExternalEntityLoader (const char *aURI,
1197 const char *aID,
1198 xmlParserCtxt *aCtxt);
1199
1200 static XmlTreeBackend *sThat;
1201
1202 static XmlKeyBackend *GetKeyBackend (const Key &aKey)
1203 { return (XmlKeyBackend *) TreeBackend::GetKeyBackend (aKey); }
1204};
1205
1206} /* namespace settings */
1207
1208
1209/*
1210 * VBoxXml
1211 *
1212 *
1213 */
1214
1215
1216class VBoxXmlBase
1217{
1218protected:
1219 VBoxXmlBase();
1220
1221 ~VBoxXmlBase();
1222
1223 xmlParserCtxtPtr m_ctxt;
1224};
1225
1226class VBoxXmlFile : public VBoxXmlBase
1227{
1228public:
1229 VBoxXmlFile();
1230 ~VBoxXmlFile();
1231};
1232
1233
1234
1235#if defined(_MSC_VER)
1236#pragma warning (default:4251)
1237#endif
1238
1239/** @} */
1240
1241#endif /* ___VBox_settings_h */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use