VirtualBox

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

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

Merged dmik/s2 branch (r25959:26751) to the trunk.

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