Changeset 7315 in vbox
- Timestamp:
- Mar 6, 2008 10:12:41 AM (17 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/settings.h
r7309 r7315 1299 1299 1300 1300 /** 1301 * The InputResolver class represents an in put resolver, the service used to1302 * provide input streamsfor external entities given an URL and entity ID.1301 * The InputResolver class represents an interface to provide input streams 1302 * for external entities given an URL and entity ID. 1303 1303 */ 1304 1304 class VBOXSETTINGS_CLASS InputResolver … … 1322 1322 }; 1323 1323 1324 /** 1325 * The AutoConverter class represents an interface to automatically convert 1326 * old settings trees to a new version when the tree is read from the 1327 * stream. 1328 */ 1329 class VBOXSETTINGS_CLASS AutoConverter 1330 { 1331 public: 1332 1333 /** 1334 * Returns @true if the given tree needs to be converted using the XSLT 1335 * template identified by #templateUri(), or @false if no conversion is 1336 * required. 1337 * 1338 * The implementation normally checks for the "version" value of the 1339 * root key to determine if the conversion is necessary. The 1340 * implementation must return a string representing the old version 1341 * (before conversion) in the @c aOldVersion argument -- this string is 1342 * used by XmlTreeBackend::oldVersion() and must be non-NULL to indicate 1343 * that the conversion has been performed on the tree. The returned 1344 * string must be allocated using RTStrDup or such. 1345 * 1346 * @param aRoot Root settings key. 1347 * @param aOldVersionString Old version string (allocated by 1348 * RTStrDup or such). 1349 */ 1350 virtual bool needsConversion (const Key &aRoot, 1351 char *&aOldVersion) const = 0; 1352 1353 /** 1354 * Returns the URI of the XSLT template to perform the conversion. 1355 * This template will be applied to the tree if #needsConversion() 1356 * returns @c true for this tree. 1357 */ 1358 virtual const char *templateUri() const = 0; 1359 }; 1324 1360 1325 1361 /** … … 1356 1392 1357 1393 /** 1358 * Sets up automatic settings tree conversion. 1359 * 1360 * Automatic settings tree conversion is useful for upgrading old settings 1361 * files to the new version transparently during execution of the #read() 1362 * method. 1363 * 1364 * Automatic conversion is performed after reading the document from the 1365 * stream but before validating it using the given XSLT template if the 1366 * version check fails. The version check consists of comparing the given 1367 * version string with the value of the given attribute of the root key. The 1368 * conversion is performed only when the version strings are not equal. 1369 * 1370 * Note that in order to make the conversion permanent, the resulting tree 1371 * needs to be exlicitly written back to the stream. 1372 * 1373 * The method will make copies of the supplied strings. 1374 * 1375 * Specifying a NULL value for all of the arguments will completely disable 1376 * automatic conversion. Specifying an invalid root key name or a 1377 * non-existent attribute name will disable automatic conversion too. By 1378 * default automatic conversion it is disabled. 1379 * 1380 * Specifying a NULL value only for some of the arguments will throw an 1381 * EInvalidArg exception. 1382 * 1383 * @param aRoot Name of the root key containing the version attribute. 1384 * @param aAttr Name of the attribute containing the version string. 1385 * @param aVersion Version string to compare with the attribute value. 1386 * @param aTemplate URI of the XSLT template that performs conversion. 1387 */ 1388 void setAutoConversion (const char *aRoot, const char *aAttr, 1389 const char *aVersion, const char *aTemplate); 1390 1391 /** 1392 * Disables automatic settings conversion previously enabled by 1393 * setAutoConversion(). By default automatic conversion it is disabled. 1394 */ 1395 void resetAutoConversion() 1396 { 1397 setAutoConversion (NULL, NULL, NULL, NULL); 1398 } 1394 * Sets a settings tree converter and enables the automatic conversion. 1395 * 1396 * The Automatic settings tree conversion is useful for upgrading old 1397 * settings files to the new version transparently during execution of the 1398 * #read() method. 1399 * 1400 * The automatic conversion takes place after reading the document from the 1401 * stream but before validating it. The given converter is asked if the 1402 * conversion is necessary using the AutoConverter::needsConversion() call, 1403 * and if so, the XSLT template specified by AutoConverter::templateUri() is 1404 * applied to the settings tree. 1405 * 1406 * Note that in order to make the result of the conversion permanent, the 1407 * settings tree needs to be exlicitly written back to the stream. 1408 * 1409 * The given converter object must exist as long as this instance exists or 1410 * until a different converter is set using setAutoConverter() or reset 1411 * using resetAutoConverter(). 1412 * 1413 * @param aConverter Settings converter to use. 1414 */ 1415 void setAutoConverter (AutoConverter &aConverter); 1416 1417 /** 1418 * Disables the automatic settings conversion previously enabled by 1419 * setAutoConverter(). By default automatic conversion it is disabled. 1420 */ 1421 void resetAutoConverter(); 1422 1423 /** 1424 * Returns a non-NULL string if the automatic settings conversion has been 1425 * performed during the last successful #read() call. Returns @c NULL if 1426 * there was no settings conversion. 1427 * 1428 * If #read() fails, this method will return the version string set by the 1429 * previous successful #read() call or @c NULL if there were no #read() 1430 * calls. 1431 */ 1432 const char *oldVersion() const; 1399 1433 1400 1434 void rawRead (Input &aInput, const char *aSchema = NULL, int aFlags = 0); -
trunk/src/VBox/Main/xml/Settings.cpp
r7309 r7315 797 797 { 798 798 Data() : ctxt (NULL), doc (NULL) 799 , inputResolver (NULL) {} 799 , inputResolver (NULL) 800 , autoConverter (NULL), oldVersion (NULL) {} 800 801 801 802 xmlParserCtxtPtr ctxt; … … 806 807 InputResolver *inputResolver; 807 808 809 AutoConverter *autoConverter; 810 char *oldVersion; 811 808 812 std::auto_ptr <stdx::exception_trap_base> trappedErr; 809 810 struct AutoConv811 {812 AutoConv() : root (NULL), attr (NULL), version (NULL), xslt (NULL) {}813 ~AutoConv() { uninit(); }814 815 void uninit()816 {817 RTStrFree (xslt); xslt = NULL;818 RTStrFree (version); version = NULL;819 RTStrFree (attr); attr = NULL;820 RTStrFree (root); root = NULL;821 }822 823 bool isNull() { return xslt == NULL; }824 825 char *root;826 char *attr;827 char *version;828 char *xslt;829 }830 autoConv;831 813 832 814 /** … … 896 878 } 897 879 898 void XmlTreeBackend::setAutoConversion (const char *aRoot, const char *aAttr, 899 const char *aVersion, const char *aTemplate) 900 { 901 if (aRoot == NULL && aAttr == NULL && aVersion == NULL && aTemplate == NULL) 902 { 903 m->autoConv.uninit(); 904 return; 905 } 906 907 if (aRoot == NULL || aAttr == NULL || aVersion == NULL || aTemplate == NULL) 908 throw EInvalidArg (RT_SRC_POS); 909 910 m->autoConv.root = RTStrDup (aRoot); 911 m->autoConv.attr = RTStrDup (aAttr); 912 m->autoConv.version = RTStrDup (aVersion); 913 m->autoConv.xslt = RTStrDup (aTemplate); 880 void XmlTreeBackend::setAutoConverter (AutoConverter &aConverter) 881 { 882 m->autoConverter = &aConverter; 883 } 884 885 void XmlTreeBackend::resetAutoConverter() 886 { 887 m->autoConverter = NULL; 888 } 889 890 const char *XmlTreeBackend::oldVersion() const 891 { 892 return m->oldVersion; 914 893 } 915 894 … … 957 936 } 958 937 938 char *oldVersion = NULL; 939 959 940 /* perform automatic document transformation if necessary */ 960 if ( !m->autoConv.isNull())941 if (m->autoConverter != NULL) 961 942 { 962 943 Key root = Key (new XmlKeyBackend (xmlDocGetRootElement (doc))); 963 if ( !strcmp (root.name(), m->autoConv.root))944 if (m->autoConverter->needsConversion (root, oldVersion)) 964 945 { 965 const char *ver = root.stringValue (m->autoConv.attr); 966 if (strcmp (ver, m->autoConv.version)) 946 xmlDocPtr xsltDoc = NULL; 947 xsltStylesheetPtr xslt = NULL; 948 xsltTransformContextPtr tranCtxt = NULL; 949 char *errorStr = NULL; 950 951 try 967 952 { 968 /* version mismatch */ 969 970 xmlDocPtr xsltDoc = NULL; 971 xsltStylesheetPtr xslt = NULL; 972 xsltTransformContextPtr tranCtxt = NULL; 973 char *errorStr = NULL; 974 975 try 953 /* parse the XSLT template */ 976 954 { 977 /* parse the XSLT */ 978 { 979 Input *xsltInput = 980 m->inputResolver->resolveEntity (m->autoConv.xslt, NULL); 981 /* NOTE: new InputCtxt instance will be deleted when the 982 * stream is closed by the libxml2 API */ 983 xsltDoc = xmlCtxtReadIO (m->ctxt, 984 ReadCallback, CloseCallback, 985 new Data::InputCtxt (xsltInput, m->trappedErr), 986 m->autoConv.xslt, NULL, 987 0); 988 delete xsltInput; 989 } 990 991 if (xsltDoc == NULL) 992 { 993 /* look if there was a forwared exception from the lower level */ 994 if (m->trappedErr.get() != NULL) 995 m->trappedErr->rethrow(); 996 997 throw XmlError (xmlCtxtGetLastError (m->ctxt)); 998 } 999 1000 xslt = xsltParseStylesheetDoc (xsltDoc); 1001 if (xslt == NULL) 1002 throw LogicError (RT_SRC_POS); 1003 1004 /* setup transformation error reporting */ 1005 tranCtxt = xsltNewTransformContext (xslt, xsltDoc); 1006 if (tranCtxt == NULL) 1007 throw LogicError (RT_SRC_POS); 1008 xsltSetTransformErrorFunc (tranCtxt, &errorStr, ValidityErrorCallback); 1009 1010 xmlDocPtr newDoc = xsltApplyStylesheetUser (xslt, doc, NULL, 1011 NULL, NULL, tranCtxt); 1012 if (newDoc == NULL) 1013 throw LogicError (RT_SRC_POS); 1014 1015 if (errorStr != NULL) 1016 { 1017 xmlFreeDoc (newDoc); 1018 throw Error (errorStr); 1019 /* errorStr is freed in catch(...) below */ 1020 } 1021 1022 /* replace the old document on success */ 1023 xmlFreeDoc (doc); 1024 doc = newDoc; 1025 955 Input *xsltInput = 956 m->inputResolver->resolveEntity 957 (m->autoConverter->templateUri(), NULL); 958 /* NOTE: new InputCtxt instance will be deleted when the 959 * stream is closed by the libxml2 API */ 960 xsltDoc = xmlCtxtReadIO (m->ctxt, 961 ReadCallback, CloseCallback, 962 new Data::InputCtxt (xsltInput, m->trappedErr), 963 m->autoConverter->templateUri(), 964 NULL, 0); 965 delete xsltInput; 966 } 967 968 if (xsltDoc == NULL) 969 { 970 /* look if there was a forwared exception from the lower level */ 971 if (m->trappedErr.get() != NULL) 972 m->trappedErr->rethrow(); 973 974 throw XmlError (xmlCtxtGetLastError (m->ctxt)); 975 } 976 977 xslt = xsltParseStylesheetDoc (xsltDoc); 978 if (xslt == NULL) 979 throw LogicError (RT_SRC_POS); 980 981 /* setup transformation error reporting */ 982 tranCtxt = xsltNewTransformContext (xslt, xsltDoc); 983 if (tranCtxt == NULL) 984 throw LogicError (RT_SRC_POS); 985 xsltSetTransformErrorFunc (tranCtxt, &errorStr, ValidityErrorCallback); 986 987 xmlDocPtr newDoc = xsltApplyStylesheetUser (xslt, doc, NULL, 988 NULL, NULL, tranCtxt); 989 if (newDoc == NULL) 990 throw LogicError (RT_SRC_POS); 991 992 if (errorStr != NULL) 993 { 994 xmlFreeDoc (newDoc); 995 throw Error (errorStr); 996 /* errorStr is freed in catch(...) below */ 997 } 998 999 /* replace the old document on success */ 1000 xmlFreeDoc (doc); 1001 doc = newDoc; 1002 1003 xsltFreeTransformContext (tranCtxt); 1004 1005 /* NOTE: xsltFreeStylesheet() also fress the document 1006 * passed to xsltParseStylesheetDoc(). */ 1007 xsltFreeStylesheet (xslt); 1008 } 1009 catch (...) 1010 { 1011 /* restore the previous entity resolver */ 1012 xmlSetExternalEntityLoader (oldEntityLoader); 1013 sThat = NULL; 1014 1015 RTStrFree (errorStr); 1016 1017 if (tranCtxt != NULL) 1026 1018 xsltFreeTransformContext (tranCtxt); 1027 1019 1028 /* NOTE: xsltFreeStylesheet() also fress the document 1029 * passed to xsltParseStylesheetDoc(). */ 1020 /* NOTE: xsltFreeStylesheet() also fress the document 1021 * passed to xsltParseStylesheetDoc(). */ 1022 if (xslt != NULL) 1030 1023 xsltFreeStylesheet (xslt); 1031 } 1032 catch (...) 1033 { 1034 /* restore the previous entity resolver */ 1035 xmlSetExternalEntityLoader (oldEntityLoader); 1036 sThat = NULL; 1037 1038 RTStrFree (errorStr); 1039 1040 if (tranCtxt != NULL) 1041 xsltFreeTransformContext (tranCtxt); 1042 1043 /* NOTE: xsltFreeStylesheet() also fress the document 1044 * passed to xsltParseStylesheetDoc(). */ 1045 if (xslt != NULL) 1046 xsltFreeStylesheet (xslt); 1047 else if (xsltDoc != NULL) 1048 xmlFreeDoc (xsltDoc); 1049 1050 throw; 1051 } 1024 else if (xsltDoc != NULL) 1025 xmlFreeDoc (xsltDoc); 1026 1027 RTStrFree (oldVersion); 1028 1029 throw; 1052 1030 } 1053 1031 } … … 1130 1108 xmlSchemaFreeParserCtxt (schemaCtxt); 1131 1109 1110 RTStrFree (oldVersion); 1111 1132 1112 throw; 1133 1113 } … … 1144 1124 /* assign the root key */ 1145 1125 m->root = Key (new XmlKeyBackend (xmlDocGetRootElement (m->doc))); 1126 1127 /* memorize the old version string also used as a flag that 1128 * the conversion has been performed (transfers ownership) */ 1129 m->oldVersion = oldVersion; 1146 1130 } 1147 1131 … … 1187 1171 void XmlTreeBackend::reset() 1188 1172 { 1173 RTStrFree (m->oldVersion); 1174 m->oldVersion = NULL; 1175 1189 1176 if (m->doc) 1190 1177 {
Note:
See TracChangeset
for help on using the changeset viewer.