VirtualBox

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

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

Main: move libxml2 to IPRT unconditionally (remove VBOX_WITH_LIBXML2_IN_VBOXRT); move xml classes to IPRT; introduce IPRT ministring class as base for both Utf8Str and xml.cpp, with better performance (remembers string lengths and can thus use memcpy instead of strdup); introduce some Utf8Str helpers to avoid string buffer hacks in Main code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 41.2 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 <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/* Forwards */
247typedef struct _xmlParserInput xmlParserInput;
248typedef xmlParserInput *xmlParserInputPtr;
249typedef struct _xmlParserCtxt xmlParserCtxt;
250typedef xmlParserCtxt *xmlParserCtxtPtr;
251typedef struct _xmlError xmlError;
252typedef xmlError *xmlErrorPtr;
253
254
255/**
256 * Settings File Manipulation API namespace.
257 */
258namespace settings
259{
260
261// Exceptions (on top of vboxxml exceptions)
262//////////////////////////////////////////////////////////////////////////////
263
264class VBOXXML_CLASS ENoKey : public xml::LogicError
265{
266public:
267
268 ENoKey (const char *aMsg = NULL) : xml::LogicError (aMsg) {}
269};
270
271class VBOXXML_CLASS ENoValue : public xml::LogicError
272{
273public:
274
275 ENoValue (const char *aMsg = NULL) : xml::LogicError (aMsg) {}
276};
277
278class VBOXXML_CLASS ENoConversion : public xml::RuntimeError
279{
280public:
281
282 ENoConversion (const char *aMsg = NULL) : RuntimeError (aMsg) {}
283};
284
285
286// Helpers
287//////////////////////////////////////////////////////////////////////////////
288
289// string -> type conversions
290//////////////////////////////////////////////////////////////////////////////
291
292/** @internal
293 * Helper for the FromString() template, doesn't need to be called directly.
294 */
295DECLEXPORT (uint64_t) FromStringInteger (const char *aValue, bool aSigned,
296 int aBits, uint64_t aMin, uint64_t aMax);
297
298/**
299 * Generic template function to perform a conversion of an UTF-8 string to an
300 * arbitrary value of type @a T.
301 *
302 * This generic template is implenented only for 8-, 16-, 32- and 64- bit
303 * signed and unsigned integers where it uses RTStrTo[U]Int64() to perform the
304 * conversion. For all other types it throws an ENotImplemented
305 * exception. Individual template specializations for known types should do
306 * the conversion job.
307 *
308 * If the conversion is not possible (for example the string format is wrong
309 * or meaningless for the given type), this template will throw an
310 * ENoConversion exception. All specializations must do the same.
311 *
312 * If the @a aValue argument is NULL, this method will throw an ENoValue
313 * exception. All specializations must do the same.
314 *
315 * @param aValue Value to convert.
316 *
317 * @return Result of conversion.
318 */
319template <typename T>
320T FromString (const char *aValue)
321{
322 if (std::numeric_limits <T>::is_integer)
323 {
324 bool sign = std::numeric_limits <T>::is_signed;
325 int bits = std::numeric_limits <T>::digits + (sign ? 1 : 0);
326
327 return (T) FromStringInteger (aValue, sign, bits,
328 (uint64_t) std::numeric_limits <T>::min(),
329 (uint64_t) std::numeric_limits <T>::max());
330 }
331
332 throw xml::ENotImplemented (RT_SRC_POS);
333}
334
335/**
336 * Specialization of FromString for bool.
337 *
338 * Converts "true", "yes", "on" to true and "false", "no", "off" to false.
339 */
340template<> DECLEXPORT (bool) FromString <bool> (const char *aValue);
341
342/**
343 * Specialization of FromString for RTTIMESPEC.
344 *
345 * Converts the date in ISO format (<YYYY>-<MM>-<DD>T<hh>:<mm>:<ss>[timezone])
346 * to a RTTIMESPEC value. Currently, the timezone must always be Z (UTC).
347 */
348template<> DECLEXPORT (RTTIMESPEC) FromString <RTTIMESPEC> (const char *aValue);
349
350/**
351 * Converts a string of hex digits to memory bytes.
352 *
353 * @param aValue String to convert.
354 * @param aLen Where to store the length of the returned memory
355 * block (may be NULL).
356 *
357 * @return Result of conversion (a block of @a aLen bytes).
358 */
359DECLEXPORT (stdx::char_auto_ptr) FromString (const char *aValue, size_t *aLen);
360
361// type -> string conversions
362//////////////////////////////////////////////////////////////////////////////
363
364/** @internal
365 * Helper for the ToString() template, doesn't need to be called directly.
366 */
367DECLEXPORT (stdx::char_auto_ptr)
368ToStringInteger (uint64_t aValue, unsigned int aBase,
369 bool aSigned, int aBits);
370
371/**
372 * Generic template function to perform a conversion of an arbitrary value to
373 * an UTF-8 string.
374 *
375 * This generic template is implemented only for 8-, 16-, 32- and 64- bit
376 * signed and unsigned integers where it uses RTStrFormatNumber() to perform
377 * the conversion. For all other types it throws an ENotImplemented
378 * exception. Individual template specializations for known types should do
379 * the conversion job. If the conversion is not possible (for example the
380 * given value doesn't have a string representation), the relevant
381 * specialization should throw an ENoConversion exception.
382 *
383 * If the @a aValue argument's value would convert to a NULL string, this
384 * method will throw an ENoValue exception. All specializations must do the
385 * same.
386 *
387 * @param aValue Value to convert.
388 * @param aExtra Extra flags to define additional formatting. In case of
389 * integer types, it's the base used for string representation.
390 *
391 * @return Result of conversion.
392 */
393template <typename T>
394stdx::char_auto_ptr ToString (const T &aValue, unsigned int aExtra = 0)
395{
396 if (std::numeric_limits <T>::is_integer)
397 {
398 bool sign = std::numeric_limits <T>::is_signed;
399 int bits = std::numeric_limits <T>::digits + (sign ? 1 : 0);
400
401 return ToStringInteger (aValue, aExtra, sign, bits);
402 }
403
404 throw xml::ENotImplemented (RT_SRC_POS);
405}
406
407/**
408 * Specialization of ToString for bool.
409 *
410 * Converts true to "true" and false to "false". @a aExtra is not used.
411 */
412template<> DECLEXPORT (stdx::char_auto_ptr)
413ToString <bool> (const bool &aValue, unsigned int aExtra);
414
415/**
416 * Specialization of ToString for RTTIMESPEC.
417 *
418 * Converts the RTTIMESPEC value to the date string in ISO format
419 * (<YYYY>-<MM>-<DD>T<hh>:<mm>:<ss>[timezone]). Currently, the timezone will
420 * always be Z (UTC).
421 *
422 * @a aExtra is not used.
423 */
424template<> DECLEXPORT (stdx::char_auto_ptr)
425ToString <RTTIMESPEC> (const RTTIMESPEC &aValue, unsigned int aExtra);
426
427/**
428 * Converts memory bytes to a null-terminated string of hex values.
429 *
430 * @param aData Pointer to the memory block.
431 * @param aLen Length of the memory block.
432 *
433 * @return Result of conversion.
434 */
435DECLEXPORT (stdx::char_auto_ptr) ToString (const void *aData, size_t aLen);
436
437#if defined VBOX_MAIN_SETTINGS_ADDONS
438
439/// @todo once string data in Bstr and Utf8Str is auto_ref_ptr, enable the
440/// code below
441
442#if 0
443
444/** Specialization of FromString for Bstr. */
445template<> com::Bstr FromString <com::Bstr> (const char *aValue);
446
447#endif
448
449/** Specialization of ToString for Bstr. */
450template<> stdx::char_auto_ptr
451ToString <com::Bstr> (const com::Bstr &aValue, unsigned int aExtra);
452
453/** Specialization of FromString for Guid. */
454template<> com::Guid FromString <com::Guid> (const char *aValue);
455
456/** Specialization of ToString for Guid. */
457template<> stdx::char_auto_ptr
458ToString <com::Guid> (const com::Guid &aValue, unsigned int aExtra);
459
460#endif // VBOX_MAIN_SETTINGS_ADDONS
461
462// the rest
463//////////////////////////////////////////////////////////////////////////////
464
465/**
466 * The Key class represents a settings key.
467 *
468 * Every settings key has a name and zero or more uniquely named values
469 * (attributes). There is a special attribute with a NULL name that is called
470 * a key value.
471 *
472 * Besides values, settings keys may contain other settings keys. This way,
473 * settings keys form a tree-like (or a directory-like) hierarchy of keys. Key
474 * names do not need to be unique even if they belong to the same parent key
475 * which allows to have an array of keys of the same name.
476 *
477 * @note Key and Value objects returned by methods of the Key and TreeBackend
478 * classes are owned by the given TreeBackend instance and may refer to data
479 * that becomes invalid when this TreeBackend instance is destroyed.
480 */
481class VBOXXML_CLASS Key
482{
483public:
484
485 typedef std::list <Key> List;
486
487 /**
488 * Key backend interface used to perform actual key operations.
489 *
490 * This interface is implemented by backends that provide specific ways of
491 * storing settings keys.
492 */
493 class VBOXXML_CLASS Backend : public stdx::auto_ref
494 {
495 public:
496
497 /** Performs the Key::name() function. */
498 virtual const char *name() const = 0;
499
500 /** Performs the Key::setName() function. */
501 virtual void setName (const char *aName) = 0;
502
503 /** Performs the Key::stringValue() function. */
504 virtual const char *value (const char *aName) const = 0;
505
506 /** Performs the Key::setStringValue() function. */
507 virtual void setValue (const char *aName, const char *aValue) = 0;
508
509 /** Performs the Key::keys() function. */
510 virtual List keys (const char *aName = NULL) const = 0;
511
512 /** Performs the Key::findKey() function. */
513 virtual Key findKey (const char *aName) const = 0;
514
515 /** Performs the Key::appendKey() function. */
516 virtual Key appendKey (const char *aName) = 0;
517
518 /** Performs the Key::zap() function. */
519 virtual void zap() = 0;
520
521 /**
522 * Returns an opaque value that uniquely represents the position of
523 * this key on the tree which is used to compare two keys. Two or more
524 * keys may return the same value only if they actually represent the
525 * same key (i.e. they have the same list of parents and children).
526 */
527 virtual void *position() const = 0;
528 };
529
530 /**
531 * Creates a new key object. If @a aBackend is @c NULL then a null key is
532 * created.
533 *
534 * Regular API users should never need to call this method with something
535 * other than NULL argument (which is the default).
536 *
537 * @param aBackend Key backend to use.
538 */
539 Key (Backend *aBackend = NULL) : m (aBackend) {}
540
541 /**
542 * Returns @c true if this key is null.
543 */
544 bool isNull() const { return m.is_null(); }
545
546 /**
547 * Makes this object a null key.
548 *
549 * Note that as opposed to #zap(), this methid does not delete the key from
550 * the list of children of its parent key.
551 */
552 void setNull() { m = NULL; }
553
554 /**
555 * Returns the name of this key.
556 * Returns NULL if this object a null (uninitialized) key.
557 */
558 const char *name() const { return m.is_null() ? NULL : m->name(); }
559
560 /**
561 * Sets the name of this key.
562 *
563 * @param aName New key name.
564 */
565 void setName (const char *aName) { if (!m.is_null()) m->setName (aName); }
566
567 /**
568 * Returns the value of the attribute with the given name as an UTF-8
569 * string. Returns @c NULL if there is no attribute with the given name.
570 *
571 * @param aName Name of the attribute. NULL may be used to
572 * get the key value.
573 */
574 const char *stringValue (const char *aName) const
575 {
576 return m.is_null() ? NULL : m->value (aName);
577 }
578
579 /**
580 * Sets the value of the attribute with the given name from an UTF-8
581 * string. This method will do a copy of the supplied @a aValue string.
582 *
583 * @param aName Name of the attribute. NULL may be used to
584 * set the key value.
585 * @param aValue New value of the attribute. NULL may be used to
586 * delete the value instead of setting it.
587 */
588 void setStringValue (const char *aName, const char *aValue)
589 {
590 if (!m.is_null()) m->setValue (aName, aValue);
591 }
592
593 /**
594 * Returns the value of the attribute with the given name as an object of
595 * type @a T. Throws ENoValue if there is no attribute with the given
596 * name.
597 *
598 * This function calls #stringValue() to get the string representation of
599 * the attribute and then calls the FromString() template to convert this
600 * string to a value of the given type.
601 *
602 * @param aName Name of the attribute. NULL may be used to
603 * get the key value.
604 */
605 template <typename T>
606 T value (const char *aName) const
607 {
608 try
609 {
610 return FromString <T> (stringValue (aName));
611 }
612 catch (const ENoValue &)
613 {
614 throw ENoValue(com::Utf8StrFmt("No such attribute '%s'", aName));
615 }
616 }
617
618 /**
619 * Returns the value of the attribute with the given name as an object of
620 * type @a T. Returns the given default value if there is no attribute
621 * with the given name.
622 *
623 * This function calls #stringValue() to get the string representation of
624 * the attribute and then calls the FromString() template to convert this
625 * string to a value of the given type.
626 *
627 * @param aName Name of the attribute. NULL may be used to
628 * get the key value.
629 * @param aDefault Default value to return for the missing attribute.
630 */
631 template <typename T>
632 T valueOr (const char *aName, const T &aDefault) const
633 {
634 try
635 {
636 return FromString <T> (stringValue (aName));
637 }
638 catch (const ENoValue &)
639 {
640 return aDefault;
641 }
642 }
643
644 /**
645 * Sets the value of the attribute with the given name from an object of
646 * type @a T. This method will do a copy of data represented by @a aValue
647 * when necessary.
648 *
649 * This function converts the given value to a string using the ToString()
650 * template and then calls #setStringValue().
651 *
652 * @param aName Name of the attribute. NULL may be used to
653 * set the key value.
654 * @param aValue New value of the attribute.
655 * @param aExtra Extra field used by some types to specify additional
656 * details for storing the value as a string (such as the
657 * base for decimal numbers).
658 */
659 template <typename T>
660 void setValue (const char *aName, const T &aValue, unsigned int aExtra = 0)
661 {
662 try
663 {
664 stdx::char_auto_ptr value = ToString (aValue, aExtra);
665 setStringValue (aName, value.get());
666 }
667 catch (const ENoValue &)
668 {
669 throw ENoValue(com::Utf8StrFmt("No value for attribute '%s'", aName));
670 }
671 }
672
673 /**
674 * Sets the value of the attribute with the given name from an object of
675 * type @a T. If the value of the @a aValue object equals to the value of
676 * the given @a aDefault object, then the attribute with the given name
677 * will be deleted instead of setting its value to @a aValue.
678 *
679 * This function converts the given value to a string using the ToString()
680 * template and then calls #setStringValue().
681 *
682 * @param aName Name of the attribute. NULL may be used to
683 * set the key value.
684 * @param aValue New value of the attribute.
685 * @param aDefault Default value to compare @a aValue to.
686 * @param aExtra Extra field used by some types to specify additional
687 * details for storing the value as a string (such as the
688 * base for decimal numbers).
689 */
690 template <typename T>
691 void setValueOr (const char *aName, const T &aValue, const T &aDefault,
692 unsigned int aExtra = 0)
693 {
694 if (aValue == aDefault)
695 zapValue (aName);
696 else
697 setValue <T> (aName, aValue, aExtra);
698 }
699
700 /**
701 * Deletes the value of the attribute with the given name.
702 * Shortcut to <tt>setStringValue(aName, NULL)</tt>.
703 */
704 void zapValue (const char *aName) { setStringValue (aName, NULL); }
705
706 /**
707 * Returns the key value.
708 * Shortcut to <tt>stringValue (NULL)</tt>.
709 */
710 const char *keyStringValue() const { return stringValue (NULL); }
711
712 /**
713 * Sets the key value.
714 * Shortcut to <tt>setStringValue (NULL, aValue)</tt>.
715 */
716 void setKeyStringValue (const char *aValue) { setStringValue (NULL, aValue); }
717
718 /**
719 * Returns the key value.
720 * Shortcut to <tt>value (NULL)</tt>.
721 */
722 template <typename T>
723 T keyValue() const { return value <T> (NULL); }
724
725 /**
726 * Returns the key value or the given default if the key value is NULL.
727 * Shortcut to <tt>value (NULL)</tt>.
728 */
729 template <typename T>
730 T keyValueOr (const T &aDefault) const { return valueOr <T> (NULL, aDefault); }
731
732 /**
733 * Sets the key value.
734 * Shortcut to <tt>setValue (NULL, aValue, aExtra)</tt>.
735 */
736 template <typename T>
737 void setKeyValue (const T &aValue, unsigned int aExtra = 0)
738 {
739 setValue <T> (NULL, aValue, aExtra);
740 }
741
742 /**
743 * Sets the key value.
744 * Shortcut to <tt>setValueOr (NULL, aValue, aDefault)</tt>.
745 */
746 template <typename T>
747 void setKeyValueOr (const T &aValue, const T &aDefault,
748 unsigned int aExtra = 0)
749 {
750 setValueOr <T> (NULL, aValue, aDefault, aExtra);
751 }
752
753 /**
754 * Deletes the key value.
755 * Shortcut to <tt>zapValue (NULL)</tt>.
756 */
757 void zapKeyValue () { zapValue (NULL); }
758
759 /**
760 * Returns a list of all child keys named @a aName.
761 *
762 * If @a aname is @c NULL, returns a list of all child keys.
763 *
764 * @param aName Child key name to list.
765 */
766 List keys (const char *aName = NULL) const
767 {
768 return m.is_null() ? List() : m->keys (aName);
769 };
770
771 /**
772 * Returns the first child key with the given name.
773 *
774 * Throws ENoKey if no child key with the given name exists.
775 *
776 * @param aName Child key name.
777 */
778 Key key (const char *aName) const
779 {
780 Key key = findKey (aName);
781 if (key.isNull())
782 {
783 throw ENoKey(com::Utf8StrFmt("No such key '%s'", aName));
784 }
785 return key;
786 }
787
788 /**
789 * Returns the first child key with the given name.
790 *
791 * As opposed to #key(), this method will not throw an exception if no
792 * child key with the given name exists, but return a null key instead.
793 *
794 * @param aName Child key name.
795 */
796 Key findKey (const char *aName) const
797 {
798 return m.is_null() ? Key() : m->findKey (aName);
799 }
800
801 /**
802 * Creates a key with the given name as a child of this key and returns it
803 * to the caller.
804 *
805 * If one or more child keys with the given name already exist, no new key
806 * is created but the first matching child key is returned.
807 *
808 * @param aName Name of the child key to create.
809 */
810 Key createKey (const char *aName)
811 {
812 Key key = findKey (aName);
813 if (key.isNull())
814 key = appendKey (aName);
815 return key;
816 }
817
818 /**
819 * Appends a key with the given name to the list of child keys of this key
820 * and returns the appended key to the caller.
821 *
822 * @param aName Name of the child key to create.
823 */
824 Key appendKey (const char *aName)
825 {
826 return m.is_null() ? Key() : m->appendKey (aName);
827 }
828
829 /**
830 * Deletes this key.
831 *
832 * The deleted key is removed from the list of child keys of its parent
833 * key and becomes a null object.
834 */
835 void zap()
836 {
837 if (!m.is_null())
838 {
839 m->zap();
840 setNull();
841 }
842 }
843
844 /**
845 * Compares this object with the given object and returns @c true if both
846 * represent the same key on the settings tree or if both are null
847 * objects.
848 *
849 * @param that Object to compare this object with.
850 */
851 bool operator== (const Key &that) const
852 {
853 return m == that.m ||
854 (!m.is_null() && !that.m.is_null() &&
855 m->position() == that.m->position());
856 }
857
858 /**
859 * Counterpart to operator==().
860 */
861 bool operator!= (const Key &that) const { return !operator== (that); }
862
863private:
864
865 stdx::auto_ref_ptr <Backend> m;
866
867 friend class TreeBackend;
868};
869
870/**
871 * The TreeBackend class represents a storage backend used to read a settings
872 * tree from and write it to a stream.
873 *
874 * @note All Key objects returned by any of the TreeBackend methods (and by
875 * methods of returned Key objects) are owned by the given TreeBackend
876 * instance. When this instance is destroyed, all Key objects become invalid
877 * and an attempt to access Key data will cause the program crash.
878 */
879class VBOXXML_CLASS TreeBackend
880{
881public:
882
883 /**
884 * Reads and parses the given input stream.
885 *
886 * On success, the previous settings tree owned by this backend (if any)
887 * is deleted.
888 *
889 * The optional schema URI argument determines the name of the schema to
890 * use for input validation. If the schema URI is NULL then the validation
891 * is not performed. Note that you may set a custom input resolver if you
892 * want to provide the input stream for the schema file (and for other
893 * external entities) instead of letting the backend to read the specified
894 * URI directly.
895 *
896 * This method will set the read/write position to the beginning of the
897 * given stream before reading. After the stream has been successfully
898 * parsed, the position will be set back to the beginning.
899 *
900 * @param aInput Input stream.
901 * @param aSchema Schema URI to use for input stream validation.
902 * @param aFlags Optional bit flags.
903 */
904 void read (xml::Input &aInput, const char *aSchema = NULL, int aFlags = 0)
905 {
906 aInput.setPos (0);
907 rawRead (aInput, aSchema, aFlags);
908 aInput.setPos (0);
909 }
910
911 /**
912 * Reads and parses the given input stream in a raw fashion.
913 *
914 * This method doesn't set the stream position to the beginnign before and
915 * after reading but instead leaves it as is in both cases. It's the
916 * caller's responsibility to maintain the correct position.
917 *
918 * @see read()
919 */
920 virtual void rawRead (xml::Input &aInput, const char *aSchema = NULL,
921 int aFlags = 0) = 0;
922
923 /**
924 * Writes the current settings tree to the given output stream.
925 *
926 * This method will set the read/write position to the beginning of the
927 * given stream before writing. After the settings have been successfully
928 * written to the stream, the stream will be truncated at the position
929 * following the last byte written by this method anc ghd position will be
930 * set back to the beginning.
931 *
932 * @param aOutput Output stream.
933 */
934 void write (xml::Output &aOutput)
935 {
936 aOutput.setPos (0);
937 rawWrite (aOutput);
938 aOutput.truncate();
939 aOutput.setPos (0);
940 }
941
942 /**
943 * Writes the current settings tree to the given output stream in a raw
944 * fashion.
945 *
946 * This method doesn't set the stream position to the beginnign before and
947 * after reading and doesn't truncate the stream, but instead leaves it as
948 * is in both cases. It's the caller's responsibility to maintain the
949 * correct position and perform truncation.
950 *
951 * @see write()
952 */
953 virtual void rawWrite (xml::Output &aOutput) = 0;
954
955 /**
956 * Deletes the current settings tree.
957 */
958 virtual void reset() = 0;
959
960 /**
961 * Returns the root settings key.
962 */
963 virtual Key &rootKey() const = 0;
964
965protected:
966
967 static Key::Backend *GetKeyBackend (const Key &aKey) { return aKey.m.raw(); }
968};
969
970class XmlKeyBackend;
971
972/**
973 * The XmlTreeBackend class uses XML markup to store settings trees.
974 *
975 * @note libxml2 and libxslt libraries used by the XmlTreeBackend are not
976 * fully reentrant. To "fix" this, the XmlTreeBackend backend serializes access
977 * to such non-reentrant parts using a global mutex so that only one thread can
978 * use non-reentrant code at a time. Currently, this relates to the #rawRead()
979 * method (and to #read() as a consequence). This means that only one thread can
980 * parse an XML stream at a time; other threads trying to parse same or
981 * different streams using different XmlTreeBackend and Input instances
982 * will have to wait.
983 *
984 * Keep in mind that the above reentrancy fix does not imply thread-safety: it
985 * is still the caller's responsibility to provide serialization if the same
986 * XmlTreeBackend instnace (as well as instances of other classes from the
987 * settings namespace) needs to be used by more than one thread.
988 */
989class VBOXXML_CLASS XmlTreeBackend : public TreeBackend
990{
991public:
992
993 /** Flags for TreeBackend::read(). */
994 enum
995 {
996 /**
997 * Sbstitute default values for missing attributes that have defaults
998 * in the XML schema. Otherwise, stringValue() will return NULL for
999 * such attributes.
1000 */
1001 Read_AddDefaults = RT_BIT (0),
1002 };
1003
1004 /**
1005 * The EConversionCycle class represents a conversion cycle detected by the
1006 * AutoConverter::needsConversion() implementation.
1007 */
1008 class VBOXXML_CLASS EConversionCycle : public xml::RuntimeError
1009 {
1010 public:
1011
1012 EConversionCycle (const char *aMsg = NULL) : RuntimeError (aMsg) {}
1013 };
1014
1015 /**
1016 * The InputResolver class represents an interface to provide input streams
1017 * for external entities given an URL and entity ID.
1018 */
1019 class VBOXXML_CLASS InputResolver
1020 {
1021 public:
1022
1023 /**
1024 * Returns a newly allocated input stream for the given arguments. The
1025 * caller will delete the returned object when no more necessary.
1026 *
1027 * @param aURI URI of the external entity.
1028 * @param aID ID of the external entity (may be NULL).
1029 *
1030 * @return Input stream created using @c new or NULL to indicate
1031 * a wrong URI/ID pair.
1032 *
1033 * @todo Return by value after implementing the copy semantics for
1034 * Input subclasses.
1035 */
1036 virtual xml::Input *resolveEntity (const char *aURI, const char *aID) = 0;
1037 };
1038
1039 /**
1040 * The AutoConverter class represents an interface to automatically convert
1041 * old settings trees to a new version when the tree is read from the
1042 * stream.
1043 */
1044 class VBOXXML_CLASS AutoConverter
1045 {
1046 public:
1047
1048 /**
1049 * Returns @true if the given tree needs to be converted using the XSLT
1050 * template identified by #templateUri(), or @false if no conversion is
1051 * required.
1052 *
1053 * The implementation normally checks for the "version" value of the
1054 * root key to determine if the conversion is necessary. When the
1055 * @a aOldVersion argument is not NULL, the implementation must return a
1056 * non-NULL non-empty string representing the old version (before
1057 * conversion) in it this string is used by XmlTreeBackend::oldVersion()
1058 * and must be non-NULL to indicate that the conversion has been
1059 * performed on the tree. The returned string must be allocated using
1060 * RTStrDup() or such.
1061 *
1062 * This method is called again after the successful transformation to
1063 * let the implementation retry the version check and request another
1064 * transformation if necessary. This may be used to perform multi-step
1065 * conversion like this: 1.1 => 1.2, 1.2 => 1.3 (instead of 1.1 => 1.3)
1066 * which saves from the need to update all previous conversion
1067 * templates to make each of them convert directly to the recent
1068 * version.
1069 *
1070 * @note Multi-step transformations are performed in a loop that exits
1071 * only when this method returns @false. It's up to the
1072 * implementation to detect cycling (repeated requests to convert
1073 * from the same version) wrong version order, etc. and throw an
1074 * EConversionCycle exception to break the loop without returning
1075 * @false (which means the transformation succeeded).
1076 *
1077 * @param aRoot Root settings key.
1078 * @param aOldVersionString Where to store old version string
1079 * pointer. May be NULL. Allocated memory is
1080 * freed by the caller using RTStrFree().
1081 */
1082 virtual bool needsConversion (const Key &aRoot,
1083 char **aOldVersion) const = 0;
1084
1085 /**
1086 * Returns the URI of the XSLT template to perform the conversion.
1087 * This template will be applied to the tree if #needsConversion()
1088 * returns @c true for this tree.
1089 */
1090 virtual const char *templateUri() const = 0;
1091 };
1092
1093 XmlTreeBackend();
1094 ~XmlTreeBackend();
1095
1096 /**
1097 * Sets an external entity resolver used to provide input streams for
1098 * entities referred to by the XML document being parsed.
1099 *
1100 * The given resolver object must exist as long as this instance exists or
1101 * until a different resolver is set using setInputResolver() or reset
1102 * using resetInputResolver().
1103 *
1104 * @param aResolver Resolver to use.
1105 */
1106 void setInputResolver (InputResolver &aResolver);
1107
1108 /**
1109 * Resets the entity resolver to the default resolver. The default
1110 * resolver provides support for 'file:' and 'http:' protocols.
1111 */
1112 void resetInputResolver();
1113
1114 /**
1115 * Sets a settings tree converter and enables the automatic conversion.
1116 *
1117 * The Automatic settings tree conversion is useful for upgrading old
1118 * settings files to the new version transparently during execution of the
1119 * #read() method.
1120 *
1121 * The automatic conversion takes place after reading the document from the
1122 * stream but before validating it. The given converter is asked if the
1123 * conversion is necessary using the AutoConverter::needsConversion() call,
1124 * and if so, the XSLT template specified by AutoConverter::templateUri() is
1125 * applied to the settings tree.
1126 *
1127 * Note that in order to make the result of the conversion permanent, the
1128 * settings tree needs to be exlicitly written back to the stream.
1129 *
1130 * The given converter object must exist as long as this instance exists or
1131 * until a different converter is set using setAutoConverter() or reset
1132 * using resetAutoConverter().
1133 *
1134 * @param aConverter Settings converter to use.
1135 */
1136 void setAutoConverter (AutoConverter &aConverter);
1137
1138 /**
1139 * Disables the automatic settings conversion previously enabled by
1140 * setAutoConverter(). By default automatic conversion it is disabled.
1141 */
1142 void resetAutoConverter();
1143
1144 /**
1145 * Returns a non-NULL string if the automatic settings conversion has been
1146 * performed during the last successful #read() call. Returns @c NULL if
1147 * there was no settings conversion.
1148 *
1149 * If #read() fails, this method will return the version string set by the
1150 * previous successful #read() call or @c NULL if there were no #read()
1151 * calls.
1152 */
1153 const char *oldVersion() const;
1154
1155 void rawRead (xml::Input &aInput, const char *aSchema = NULL, int aFlags = 0);
1156 void rawWrite (xml::Output &aOutput);
1157 void reset();
1158 Key &rootKey() const;
1159
1160private:
1161
1162 /* Obscure class data */
1163 struct Data;
1164 std::auto_ptr <Data> m;
1165
1166 /* auto_ptr data doesn't have proper copy semantics */
1167 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (XmlTreeBackend)
1168
1169 static int ReadCallback (void *aCtxt, char *aBuf, int aLen);
1170 static int WriteCallback (void *aCtxt, const char *aBuf, int aLen);
1171 static int CloseCallback (void *aCtxt);
1172
1173 static void ValidityErrorCallback (void *aCtxt, const char *aMsg, ...);
1174 static void ValidityWarningCallback (void *aCtxt, const char *aMsg, ...);
1175 static void StructuredErrorCallback (void *aCtxt, xmlErrorPtr aErr);
1176
1177 static xmlParserInput *ExternalEntityLoader (const char *aURI,
1178 const char *aID,
1179 xmlParserCtxt *aCtxt);
1180
1181 static XmlTreeBackend *sThat;
1182
1183 static XmlKeyBackend *GetKeyBackend (const Key &aKey)
1184 { return (XmlKeyBackend *) TreeBackend::GetKeyBackend (aKey); }
1185};
1186
1187} /* namespace settings */
1188
1189
1190/*
1191 * VBoxXml
1192 *
1193 *
1194 */
1195
1196
1197class VBoxXmlBase
1198{
1199protected:
1200 VBoxXmlBase();
1201
1202 ~VBoxXmlBase();
1203
1204 xmlParserCtxtPtr m_ctxt;
1205};
1206
1207class VBoxXmlFile : public VBoxXmlBase
1208{
1209public:
1210 VBoxXmlFile();
1211 ~VBoxXmlFile();
1212};
1213
1214
1215
1216#if defined(_MSC_VER)
1217#pragma warning (default:4251)
1218#endif
1219
1220/** @} */
1221
1222#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