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