settings.h revision 5eccbb7d5743bb1f0d65f56f32521e6191e754d7
af062818b47340eef15700d2f0211576ba3506eevboxsync * Settings File Manipulation API.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright (C) 2007 innotek GmbH
af062818b47340eef15700d2f0211576ba3506eevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
af062818b47340eef15700d2f0211576ba3506eevboxsync * available from http://www.virtualbox.org. This file is free software;
af062818b47340eef15700d2f0211576ba3506eevboxsync * you can redistribute it and/or modify it under the terms of the GNU
af062818b47340eef15700d2f0211576ba3506eevboxsync * General Public License as published by the Free Software Foundation,
af062818b47340eef15700d2f0211576ba3506eevboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
af062818b47340eef15700d2f0211576ba3506eevboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
af062818b47340eef15700d2f0211576ba3506eevboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync/* these conflict with numeric_digits<>::min and max */
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync/** @defgroup grp_settings Settings File Manipulation API
af062818b47340eef15700d2f0211576ba3506eevboxsync * The Settings File Manipulation API allows to maintain a configuration file
af062818b47340eef15700d2f0211576ba3506eevboxsync * that contains "name-value" pairs grouped under named keys which are in turn
af062818b47340eef15700d2f0211576ba3506eevboxsync * organized in a hierarchical tree-like structure:
af062818b47340eef15700d2f0211576ba3506eevboxsync * <RootKey>
af062818b47340eef15700d2f0211576ba3506eevboxsync * <Key1 attr1="value" attr2=""/>
af062818b47340eef15700d2f0211576ba3506eevboxsync * <Key2 attr1="value">
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync * <SubKey1>SubKey1_Value</SubKey1>
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync * <SubKey2 attr1="value">SubKey2_Value</SubKey2>
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync * Key2_Value
af062818b47340eef15700d2f0211576ba3506eevboxsync * </RootKey>
af062818b47340eef15700d2f0211576ba3506eevboxsync * All strings this API manipulates with are zero-terminated arrays of @c char
af062818b47340eef15700d2f0211576ba3506eevboxsync * in UTF-8 encoding. Strings returned by the API are owned by the API unless
af062818b47340eef15700d2f0211576ba3506eevboxsync * explicitly stated otherwise. Strings passed to the API are accessed by the
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync * API only during the given API call unless explicitly stated otherwise. If
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync * necessary, the API will make a copy of the supplied string.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Error reprting is perfomed using C++ exceptions. All exceptions thrown by
af062818b47340eef15700d2f0211576ba3506eevboxsync * this API are derived from settings::Error. This doesn't cover exceptions
af062818b47340eef15700d2f0211576ba3506eevboxsync * that may be thrown by third-party library calls made by this API.
af062818b47340eef15700d2f0211576ba3506eevboxsync * All public classes represented by this API that support copy operations
af062818b47340eef15700d2f0211576ba3506eevboxsync * (i.e. may be created or assigned from other instsances of the same class),
af062818b47340eef15700d2f0211576ba3506eevboxsync * such as Key and Value classes, implement shallow copies and use this mode by
af062818b47340eef15700d2f0211576ba3506eevboxsync * default. It means two things:
af062818b47340eef15700d2f0211576ba3506eevboxsync * 1. Instances of these classes can be freely copied around and used as return
af062818b47340eef15700d2f0211576ba3506eevboxsync * values. All copies will share the same internal data block (using the
af062818b47340eef15700d2f0211576ba3506eevboxsync * reference counting technique) so that the copy operation is cheap, both
af062818b47340eef15700d2f0211576ba3506eevboxsync * in terms of memory and speed.
af062818b47340eef15700d2f0211576ba3506eevboxsync * 2. Since copied instances share the same data, an attempt to change data in
5112e32d7072e280613921c982a6672f2c859cf3vboxsync * the original will be reflected in all existing copies.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Making deep copies or detaching the existing shallow copy from its original
e068057c82b010bc7cc663e8f57ac3ef1890a33cvboxsync * is not yet supported.
06bfdb01d92810c68168b1304ac7aef2130c86a0vboxsync * Note that the Settings File API is not thread-safe. It means that if you
af062818b47340eef15700d2f0211576ba3506eevboxsync * want to use the same instance of a class from the settings namespace on more
af062818b47340eef15700d2f0211576ba3506eevboxsync * than one thread at a time, you will have to provide necessary access
af062818b47340eef15700d2f0211576ba3506eevboxsync * serialization yourself.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Due to some (not propely studied) libxml2 limitations, the Settings File
af062818b47340eef15700d2f0211576ba3506eevboxsync * API is not thread-safe. Therefore, the API caller must provide
af062818b47340eef15700d2f0211576ba3506eevboxsync * serialization for threads using this API simultaneously. Note though that
af062818b47340eef15700d2f0211576ba3506eevboxsync * if the libxml2 library is (even imlicitly) used on some other thread which
af062818b47340eef15700d2f0211576ba3506eevboxsync * doesn't use this API (e.g. third-party code), it may lead to resource
af062818b47340eef15700d2f0211576ba3506eevboxsync * conflicts (followed by crashes, memory corruption etc.). A proper solution
af062818b47340eef15700d2f0211576ba3506eevboxsync * for these conflicts is to be found.
af062818b47340eef15700d2f0211576ba3506eevboxsync * In order to load a settings file the program creates a TreeBackend instance
af062818b47340eef15700d2f0211576ba3506eevboxsync * using one of the specific backends (e.g. XmlTreeBackend) and then passes an
af062818b47340eef15700d2f0211576ba3506eevboxsync * Input stream object (e.g. File or MemoryBuf) to the TreeBackend::read()
af062818b47340eef15700d2f0211576ba3506eevboxsync * method to parse the stream and build the settings tree. On success, the
af062818b47340eef15700d2f0211576ba3506eevboxsync * program uses the TreeBackend::rootKey() method to access the root key of
af062818b47340eef15700d2f0211576ba3506eevboxsync * the settings tree. The root key provides access to the whole tree of
af062818b47340eef15700d2f0211576ba3506eevboxsync * settings through the methods of the Key class which allow to read, change
af062818b47340eef15700d2f0211576ba3506eevboxsync * and create new key values. Below is an example that uses the XML backend to
af062818b47340eef15700d2f0211576ba3506eevboxsync * load the settings tree, then modifies it and then saves the modifications.
af062818b47340eef15700d2f0211576ba3506eevboxsync using namespace settings;
af062818b47340eef15700d2f0211576ba3506eevboxsync File file (File::ReadWrite, "myfile.xml");
af062818b47340eef15700d2f0211576ba3506eevboxsync XmlTreeBackend tree;
af062818b47340eef15700d2f0211576ba3506eevboxsync // load the tree, parse it and validate using the XML schema
af062818b47340eef15700d2f0211576ba3506eevboxsync tree.read (aFile, "myfile.xsd", XmlTreeBackend::Read_AddDefaults);
af062818b47340eef15700d2f0211576ba3506eevboxsync // get the root key
af062818b47340eef15700d2f0211576ba3506eevboxsync Key root = tree.key();
af062818b47340eef15700d2f0211576ba3506eevboxsync printf ("root=%s\n", root.name());
af062818b47340eef15700d2f0211576ba3506eevboxsync // enumerate all child keys of the root key named Foo
af062818b47340eef15700d2f0211576ba3506eevboxsync Key::list children = root.keys ("Foo");
af062818b47340eef15700d2f0211576ba3506eevboxsync for (Key::list::const_iterator it = children.begin();
af062818b47340eef15700d2f0211576ba3506eevboxsync it != children.end();
af062818b47340eef15700d2f0211576ba3506eevboxsync // get the "level" attribute
af062818b47340eef15700d2f0211576ba3506eevboxsync int level = (*it).value <int> ("level");
af062818b47340eef15700d2f0211576ba3506eevboxsync if (level > 5)
af062818b47340eef15700d2f0211576ba3506eevboxsync // if so, create a "Bar" key if it doesn't exist yet
af062818b47340eef15700d2f0211576ba3506eevboxsync Key bar = (*it).createKey ("Bar");
af062818b47340eef15700d2f0211576ba3506eevboxsync // set the "date" attribute
af062818b47340eef15700d2f0211576ba3506eevboxsync RTTIMESPEC now;
af062818b47340eef15700d2f0211576ba3506eevboxsync RTTimeNow (&now);
af062818b47340eef15700d2f0211576ba3506eevboxsync bar.setValue <RTTIMESPEC> ("date", now);
af062818b47340eef15700d2f0211576ba3506eevboxsync else if (level < 2)
af062818b47340eef15700d2f0211576ba3506eevboxsync // if its below 2, delete the whole "Foo" key
af062818b47340eef15700d2f0211576ba3506eevboxsync (*it).zap();
af062818b47340eef15700d2f0211576ba3506eevboxsync // save the tree on success (the second try is to distinguish between
af062818b47340eef15700d2f0211576ba3506eevboxsync // stream load and save errors)
af062818b47340eef15700d2f0211576ba3506eevboxsync aTree.write (aFile);
af062818b47340eef15700d2f0211576ba3506eevboxsync catch (const EIPRTFailure &err)
af062818b47340eef15700d2f0211576ba3506eevboxsync // this is an expected exception that may happen in case of stream
af062818b47340eef15700d2f0211576ba3506eevboxsync // read or write errors
af062818b47340eef15700d2f0211576ba3506eevboxsync printf ("Could not save the settings file '%s' (%Vrc)");
af062818b47340eef15700d2f0211576ba3506eevboxsync file.uri(), err.rc());
af062818b47340eef15700d2f0211576ba3506eevboxsync return FAILURE;
af062818b47340eef15700d2f0211576ba3506eevboxsync return SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync catch (const EIPRTFailure &err)
af062818b47340eef15700d2f0211576ba3506eevboxsync // this is an expected exception that may happen in case of stream
af062818b47340eef15700d2f0211576ba3506eevboxsync // read or write errors
af062818b47340eef15700d2f0211576ba3506eevboxsync printf ("Could not load the settings file '%s' (%Vrc)");
af062818b47340eef15700d2f0211576ba3506eevboxsync file.uri(), err.rc());
af062818b47340eef15700d2f0211576ba3506eevboxsync catch (const XmlTreeBackend::Error &err)
af062818b47340eef15700d2f0211576ba3506eevboxsync // this is an XmlTreeBackend specific exception exception that may
af062818b47340eef15700d2f0211576ba3506eevboxsync // happen in case of XML parse or validation errors
af062818b47340eef15700d2f0211576ba3506eevboxsync printf ("Could not load the settings file '%s'.\n%s"),
af062818b47340eef15700d2f0211576ba3506eevboxsync file.uri(), err.what() ? err.what() : "Unknown error");
af062818b47340eef15700d2f0211576ba3506eevboxsync catch (const std::exception &err)
af062818b47340eef15700d2f0211576ba3506eevboxsync // the rest is unexpected (e.g. should not happen unless you
af062818b47340eef15700d2f0211576ba3506eevboxsync // specifically wish so for some reason and therefore allow for a
af062818b47340eef15700d2f0211576ba3506eevboxsync // situation that may throw one of these from within the try block
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgFailed ("Unexpected exception '%s' (%s)\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync typeid (err).name(), err.what());
af062818b47340eef15700d2f0211576ba3506eevboxsync catch (...)
af062818b47340eef15700d2f0211576ba3506eevboxsync // this is even more unexpected, and no any useful info here
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgFailed ("Unexpected exception\n");
af062818b47340eef15700d2f0211576ba3506eevboxsync return FAILURE;
af062818b47340eef15700d2f0211576ba3506eevboxsync * Note that you can get a raw (string) value of the attribute using the
af062818b47340eef15700d2f0211576ba3506eevboxsync * Key::stringValue() method but often it's simpler and better to use the
af062818b47340eef15700d2f0211576ba3506eevboxsync * templated Key::value<>() method that can convert the string to a value of
af062818b47340eef15700d2f0211576ba3506eevboxsync * the given type for you (and throw exceptions when the converison is not
af062818b47340eef15700d2f0211576ba3506eevboxsync * possible). Similarly, the Key::setStringValue() methid is used to set a raw
af062818b47340eef15700d2f0211576ba3506eevboxsync * string value and there is a templated Key::setValue<>() method to set a
af062818b47340eef15700d2f0211576ba3506eevboxsync * typed value which will implicitly convert it to a string.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Currently, types supported by Key::value<>() and Key::setValue<>() include
af062818b47340eef15700d2f0211576ba3506eevboxsync * all C and IPRT integer types, bool and RTTIMESPEC (represented as isoDate
af062818b47340eef15700d2f0211576ba3506eevboxsync * in XML). You can always add support for your own types by creating
af062818b47340eef15700d2f0211576ba3506eevboxsync * additional specializations of the FromString<>() and ToString<>() templates
af062818b47340eef15700d2f0211576ba3506eevboxsync * in the settings namespace (see the real examples in this header).
af062818b47340eef15700d2f0211576ba3506eevboxsync * See individual funciton, class and method descriptions to get more details
af062818b47340eef15700d2f0211576ba3506eevboxsync * on the Settings File Manipulation API.
af062818b47340eef15700d2f0211576ba3506eevboxsync# error "There are no settings APIs available in Ring-0 Context!"
af062818b47340eef15700d2f0211576ba3506eevboxsync#else /* IN_RING3 */
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @def IN_VBOXSETTINGS_R3
af062818b47340eef15700d2f0211576ba3506eevboxsync * Used to indicate whether we're inside the same link module as the
af062818b47340eef15700d2f0211576ba3506eevboxsync * XML Settings File Manipulation API.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @todo should go to a separate common include together with VBOXXML2_CLASS
af062818b47340eef15700d2f0211576ba3506eevboxsync * once there becomes more than one header in the VBoxXML2 library.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Shut up MSVC complaining that auto_ptr[_ref] template instantiations (as a
af062818b47340eef15700d2f0211576ba3506eevboxsync * result of private data member declarations of some classes below) need to
af062818b47340eef15700d2f0211576ba3506eevboxsync * be exported too to in order to be accessible by clients. I don't
af062818b47340eef15700d2f0211576ba3506eevboxsync * The alternative is to instantiate a template before the data member
af062818b47340eef15700d2f0211576ba3506eevboxsync * declaration with the VBOXSETTINGS_CLASS prefix, but the standard disables
af062818b47340eef15700d2f0211576ba3506eevboxsync * explicit instantiations in a foreign namespace. However, a declaration
af062818b47340eef15700d2f0211576ba3506eevboxsync * template class VBOXSETTINGS_CLASS std::auto_ptr <Data>;
af062818b47340eef15700d2f0211576ba3506eevboxsync * right before the member declaration makes MSVC happy too, but this is not a
af062818b47340eef15700d2f0211576ba3506eevboxsync * valid C++ construct (and G++ spits it out). So, for now we just disable the
af062818b47340eef15700d2f0211576ba3506eevboxsync * warning and will come back to this problem one dat later.
af062818b47340eef15700d2f0211576ba3506eevboxsync * We also disable another warning (4275) saying that a DLL-exported class
af062818b47340eef15700d2f0211576ba3506eevboxsync * inherits form a non-DLL-exported one (e.g. settings::ENoMemory ->
af062818b47340eef15700d2f0211576ba3506eevboxsync * std::bad_alloc). I can't get how it can harm yet.
af062818b47340eef15700d2f0211576ba3506eevboxsync/* Forwards */
af062818b47340eef15700d2f0211576ba3506eevboxsync * Settings File Manipulation API namespace.
af062818b47340eef15700d2f0211576ba3506eevboxsync//////////////////////////////////////////////////////////////////////////////
af062818b47340eef15700d2f0211576ba3506eevboxsync * Temporary holder for the formatted string.
0c274283a9861b59b9fe178c992ce415c8f0bf8avboxsync * Instances of this class are used for passing the formatted string as an
af062818b47340eef15700d2f0211576ba3506eevboxsync * argument to an Error constructor or to another function that takes
char *mStr;
struct Str
return that;
int mRC;
return aDefault;
unsigned int aExtra = 0)
unsigned int aExtra = 0)
return key;
return key;
void zap()
if (!m.is_null())
m->zap();
setNull();
return m == that.m ||
int aFlags = 0) = 0;
const char *uri() const;
void truncate();
struct Data;
const char *uri() const;
struct Data;
char **aOldVersion) const = 0;
~XmlTreeBackend();
void resetInputResolver();
void resetAutoConverter();
const char *oldVersion() const;
void reset();
struct Data;
const char *aID,
#if defined(_MSC_VER)