VirtualBox

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

Last change on this file since 17420 was 16560, checked in by vboxsync, 16 years ago

Main: do not include include/VBox/settings.h from other header files but only from implementations that need it (save compile time)

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