Changeset 7387 in vbox
- Timestamp:
- Mar 9, 2008 11:54:02 PM (17 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/VirtualBoxImplExtra.cpp
r7341 r7387 75 75 * 76 76 * The implementation normally checks for the "version" value of the 77 * root key to determine if the conversion is necessary. The 78 * implementation must return a string representing the old version 79 * (before conversion) in the @c aOldVersion argument -- this string is 80 * used by XmlTreeBackend::oldVersion() and must be non-NULL to indicate 81 * that the conversion has been performed on the tree. The returned 82 * string must be allocated using RTStrDup or such. 77 * root key to determine if the conversion is necessary. When the 78 * @a aOldVersion argument is not NULL, the implementation must return a 79 * non-NULL non-empty string representing the old version (before 80 * conversion) in it this string is used by XmlTreeBackend::oldVersion() 81 * and must be non-NULL to indicate that the conversion has been 82 * performed on the tree. The returned string must be allocated using 83 * RTStrDup() or such. 84 * 85 * This method is called again after the successful transformation to 86 * let the implementation retry the version check and request another 87 * transformation if necessary. This may be used to perform multi-step 88 * conversion like this: 1.1 => 1.2, 1.2 => 1.3 (instead of 1.1 => 1.3) 89 * which saves from the need to update all previous conversion 90 * templates to make each of them convert directly to the recent 91 * version. 92 * 93 * @note Multi-step transformations are performed in a loop that exits 94 * only when this method returns @false. It's up to the 95 * implementation to detect cycling (repeated requests to convert 96 * from the same version) wrong version order, etc. and throw an 97 * EConversionCycle exception to break the loop without returning 98 * @false (which means the transformation succeeded). 83 99 * 84 100 * @param aRoot Root settings key. 85 * @param aOldVersionString Old version string (allocated by86 * RTStrDup or such).101 * @param aOldVersionString Where to store old version string 102 * pointer. May be NULL. 87 103 */ 88 104 bool VirtualBox::SettingsTreeHelper:: 89 needsConversion (const settings::Key &aRoot, char * &aOldVersion) const105 needsConversion (const settings::Key &aRoot, char **aOldVersion) const 90 106 { 91 107 if (strcmp (aRoot.name(), "VirtualBox") == 0) … … 98 114 { 99 115 /* version mismatch */ 100 aOldVersion = RTStrDup (version); 116 if (aOldVersion != NULL) 117 *aOldVersion = RTStrDup (version); 118 101 119 return true; 102 120 } -
trunk/src/VBox/Main/include/VirtualBoxImpl.h
r7349 r7387 272 272 273 273 // AutoConverter interface 274 bool needsConversion (const settings::Key &aRoot, char * &aOldVersion) const;274 bool needsConversion (const settings::Key &aRoot, char **aOldVersion) const; 275 275 const char *templateUri() const; 276 276 }; -
trunk/src/VBox/Main/xml/Settings.cpp
r7315 r7387 893 893 } 894 894 895 extern "C" xmlGenericErrorFunc xsltGenericError; 896 extern "C" void *xsltGenericErrorContext; 897 895 898 void XmlTreeBackend::rawRead (Input &aInput, const char *aSchema /* = NULL */, 896 899 int aFlags /* = 0 */) … … 905 908 * mutex and b) requiring our API caller not to use libxml2 on some other 906 909 * thread (which is not practically possible). So, our API is not 907 * thread-safe for now. */ 910 * thread-safe for now (note that there are more thread-unsafe assumptions 911 * below like xsltGenericError which is also a libxslt limitation).*/ 908 912 xmlExternalEntityLoader oldEntityLoader = xmlGetExternalEntityLoader(); 909 913 sThat = this; 910 914 xmlSetExternalEntityLoader (ExternalEntityLoader); 911 915 912 /* Note: when parsing we use XML_PARSE_NOBLANKS to instruct libxml2 to913 * remove text nodes that contain only blanks. This is important because 914 * otherwise xmlSaveDoc() won't be able to do proper indentation on915 * output. */916 917 /* parse the stream */918 /* NOTE: new InputCtxt instance will be deleted when the stream is closed by919 * the libxml2 API (e.g. when calling xmlFreeParserCtxt())*/920 xmlDocPtr doc = xmlCtxtReadIO (m->ctxt, 921 ReadCallback, CloseCallback,922 new Data::InputCtxt (&aInput, m->trappedErr),923 aInput.uri(), NULL,924 XML_PARSE_NOBLANKS);925 if (doc == NULL)926 {927 /* restore the previous entity resolver */928 xmlSetExternalEntityLoader (oldEntityLoader);929 sThat = NULL;930 931 /* look if there was a forwared exception from the lower level */932 if (m->trappedErr.get() != NULL)933 m->trappedErr->rethrow();934 935 throw XmlError (xmlCtxtGetLastError (m->ctxt));936 }937 938 char *oldVersion = NULL;939 940 /* perform automatic document transformation if necessary */941 if (m->autoConverter != NULL)942 {943 Key root = Key (new XmlKeyBackend (xmlDocGetRootElement (doc)));944 if (m->autoConverter->needsConversion (root,oldVersion))916 xmlDocPtr doc = NULL; 917 918 try 919 { 920 /* Note: when parsing we use XML_PARSE_NOBLANKS to instruct libxml2 to 921 * remove text nodes that contain only blanks. This is important because 922 * otherwise xmlSaveDoc() won't be able to do proper indentation on 923 * output. */ 924 925 /* parse the stream */ 926 /* NOTE: new InputCtxt instance will be deleted when the stream is closed by 927 * the libxml2 API (e.g. when calling xmlFreeParserCtxt()) */ 928 doc = xmlCtxtReadIO (m->ctxt, 929 ReadCallback, CloseCallback, 930 new Data::InputCtxt (&aInput, m->trappedErr), 931 aInput.uri(), NULL, 932 XML_PARSE_NOBLANKS); 933 if (doc == NULL) 934 { 935 /* look if there was a forwared exception from the lower level */ 936 if (m->trappedErr.get() != NULL) 937 m->trappedErr->rethrow(); 938 939 throw XmlError (xmlCtxtGetLastError (m->ctxt)); 940 } 941 942 char *oldVersion = NULL; 943 944 /* perform automatic document transformation if necessary */ 945 if (m->autoConverter != NULL && 946 m->autoConverter-> 947 needsConversion (Key (new XmlKeyBackend (xmlDocGetRootElement (doc))), 948 &oldVersion)) 945 949 { 946 950 xmlDocPtr xsltDoc = NULL; 947 951 xsltStylesheetPtr xslt = NULL; 948 xsltTransformContextPtr tranCtxt = NULL;949 952 char *errorStr = NULL; 953 954 xmlGenericErrorFunc oldXsltGenericError = xsltGenericError; 955 void *oldXsltGenericErrorContext = xsltGenericErrorContext; 950 956 951 957 try … … 975 981 } 976 982 983 /* setup stylesheet compilation and transformation error 984 * reporting. Note that we could create a new transform context 985 * for doing xsltApplyStylesheetUser and use 986 * xsltSetTransformErrorFunc() on it to set a dedicated error 987 * handler but as long as we already do several non-thread-safe 988 * hacks, this is not really important. */ 989 990 xsltGenericError = ValidityErrorCallback; 991 xsltGenericErrorContext = &errorStr; 992 977 993 xslt = xsltParseStylesheetDoc (xsltDoc); 978 994 if (xslt == NULL) 995 { 996 if (errorStr != NULL) 997 throw LogicError (errorStr); 998 /* errorStr is freed in catch(...) below */ 999 979 1000 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) 1001 } 1002 1003 /* repeat transformations until autoConverter is satisfied */ 1004 do 993 1005 { 994 xmlFreeDoc (newDoc); 995 throw Error (errorStr); 996 /* errorStr is freed in catch(...) below */ 1006 xmlDocPtr newDoc = xsltApplyStylesheet (xslt, doc, NULL); 1007 if (newDoc == NULL) 1008 throw LogicError (RT_SRC_POS); 1009 1010 if (errorStr != NULL) 1011 { 1012 xmlFreeDoc (newDoc); 1013 throw Error (errorStr); 1014 /* errorStr is freed in catch(...) below */ 1015 } 1016 1017 /* replace the old document on success */ 1018 xmlFreeDoc (doc); 1019 doc = newDoc; 997 1020 } 998 999 /* replace the old document on success */ 1000 xmlFreeDoc (doc); 1001 doc = newDoc; 1002 1003 xsltFreeTransformContext (tranCtxt); 1021 while (m->autoConverter-> 1022 needsConversion (Key (new XmlKeyBackend (xmlDocGetRootElement (doc))), 1023 NULL)); 1024 1025 RTStrFree (errorStr); 1004 1026 1005 1027 /* NOTE: xsltFreeStylesheet() also fress the document 1006 1028 * passed to xsltParseStylesheetDoc(). */ 1007 1029 xsltFreeStylesheet (xslt); 1030 1031 /* restore the previous generic error func */ 1032 xsltGenericError = oldXsltGenericError; 1033 xsltGenericErrorContext = oldXsltGenericErrorContext; 1008 1034 } 1009 1035 catch (...) 1010 1036 { 1011 /* restore the previous entity resolver */1012 xmlSetExternalEntityLoader (oldEntityLoader);1013 sThat = NULL;1014 1015 1037 RTStrFree (errorStr); 1016 1017 if (tranCtxt != NULL)1018 xsltFreeTransformContext (tranCtxt);1019 1038 1020 1039 /* NOTE: xsltFreeStylesheet() also fress the document … … 1025 1044 xmlFreeDoc (xsltDoc); 1026 1045 1046 /* restore the previous generic error func */ 1047 xsltGenericError = oldXsltGenericError; 1048 xsltGenericErrorContext = oldXsltGenericErrorContext; 1049 1027 1050 RTStrFree (oldVersion); 1028 1051 … … 1030 1053 } 1031 1054 } 1032 } 1033 1034 /* validate the document */ 1035 if (aSchema != NULL) 1036 { 1037 xmlSchemaParserCtxtPtr schemaCtxt = NULL; 1038 xmlSchemaPtr schema = NULL; 1039 xmlSchemaValidCtxtPtr validCtxt = NULL; 1040 char *errorStr = NULL; 1041 1042 try 1055 1056 /* validate the document */ 1057 if (aSchema != NULL) 1043 1058 { 1044 bool valid = false; 1045 1046 schemaCtxt = xmlSchemaNewParserCtxt (aSchema); 1047 if (schemaCtxt == NULL) 1048 throw LogicError (RT_SRC_POS); 1049 1050 /* set our error handlers */ 1051 xmlSchemaSetParserErrors (schemaCtxt, ValidityErrorCallback, 1052 ValidityWarningCallback, &errorStr); 1053 xmlSchemaSetParserStructuredErrors (schemaCtxt, 1054 StructuredErrorCallback, 1055 &errorStr); 1056 /* load schema */ 1057 schema = xmlSchemaParse (schemaCtxt); 1058 if (schema != NULL) 1059 xmlSchemaParserCtxtPtr schemaCtxt = NULL; 1060 xmlSchemaPtr schema = NULL; 1061 xmlSchemaValidCtxtPtr validCtxt = NULL; 1062 char *errorStr = NULL; 1063 1064 try 1059 1065 { 1060 validCtxt = xmlSchemaNewValidCtxt (schema); 1061 if (validCtxt == NULL) 1066 bool valid = false; 1067 1068 schemaCtxt = xmlSchemaNewParserCtxt (aSchema); 1069 if (schemaCtxt == NULL) 1062 1070 throw LogicError (RT_SRC_POS); 1063 1071 1064 /* instruct to create default attribute's values in the document */1065 if (aFlags & Read_AddDefaults)1066 xmlSchemaSetValidOptions (validCtxt, XML_SCHEMA_VAL_VC_I_CREATE);1067 1068 1072 /* set our error handlers */ 1069 xmlSchemaSetValidErrors (validCtxt, ValidityErrorCallback, 1070 ValidityWarningCallback, &errorStr); 1071 1072 /* finally, validate */ 1073 valid = xmlSchemaValidateDoc (validCtxt, doc) == 0; 1073 xmlSchemaSetParserErrors (schemaCtxt, ValidityErrorCallback, 1074 ValidityWarningCallback, &errorStr); 1075 xmlSchemaSetParserStructuredErrors (schemaCtxt, 1076 StructuredErrorCallback, 1077 &errorStr); 1078 /* load schema */ 1079 schema = xmlSchemaParse (schemaCtxt); 1080 if (schema != NULL) 1081 { 1082 validCtxt = xmlSchemaNewValidCtxt (schema); 1083 if (validCtxt == NULL) 1084 throw LogicError (RT_SRC_POS); 1085 1086 /* instruct to create default attribute's values in the document */ 1087 if (aFlags & Read_AddDefaults) 1088 xmlSchemaSetValidOptions (validCtxt, XML_SCHEMA_VAL_VC_I_CREATE); 1089 1090 /* set our error handlers */ 1091 xmlSchemaSetValidErrors (validCtxt, ValidityErrorCallback, 1092 ValidityWarningCallback, &errorStr); 1093 1094 /* finally, validate */ 1095 valid = xmlSchemaValidateDoc (validCtxt, doc) == 0; 1096 } 1097 1098 if (!valid) 1099 { 1100 /* look if there was a forwared exception from the lower level */ 1101 if (m->trappedErr.get() != NULL) 1102 m->trappedErr->rethrow(); 1103 1104 if (errorStr == NULL) 1105 throw LogicError (RT_SRC_POS); 1106 1107 throw Error (errorStr); 1108 /* errorStr is freed in catch(...) below */ 1109 } 1110 1111 RTStrFree (errorStr); 1112 1113 xmlSchemaFreeValidCtxt (validCtxt); 1114 xmlSchemaFree (schema); 1115 xmlSchemaFreeParserCtxt (schemaCtxt); 1074 1116 } 1075 1076 if (!valid) 1117 catch (...) 1077 1118 { 1078 /* look if there was a forwared exception from the lower level */ 1079 if (m->trappedErr.get() != NULL) 1080 m->trappedErr->rethrow(); 1081 1082 if (errorStr == NULL) 1083 throw LogicError (RT_SRC_POS); 1084 1085 throw Error (errorStr); 1086 /* errorStr is freed in catch(...) below */ 1119 RTStrFree (errorStr); 1120 1121 if (validCtxt) 1122 xmlSchemaFreeValidCtxt (validCtxt); 1123 if (schema) 1124 xmlSchemaFree (schema); 1125 if (schemaCtxt) 1126 xmlSchemaFreeParserCtxt (schemaCtxt); 1127 1128 RTStrFree (oldVersion); 1129 1130 throw; 1087 1131 } 1088 1089 RTStrFree (errorStr);1090 1091 xmlSchemaFreeValidCtxt (validCtxt);1092 xmlSchemaFree (schema);1093 xmlSchemaFreeParserCtxt (schemaCtxt);1094 1132 } 1095 catch (...) 1096 { 1097 /* restore the previous entity resolver */ 1098 xmlSetExternalEntityLoader (oldEntityLoader); 1099 sThat = NULL; 1100 1101 RTStrFree (errorStr); 1102 1103 if (validCtxt) 1104 xmlSchemaFreeValidCtxt (validCtxt); 1105 if (schema) 1106 xmlSchemaFree (schema); 1107 if (schemaCtxt) 1108 xmlSchemaFreeParserCtxt (schemaCtxt); 1109 1110 RTStrFree (oldVersion); 1111 1112 throw; 1113 } 1114 } 1115 1116 /* restore the previous entity resolver */ 1117 xmlSetExternalEntityLoader (oldEntityLoader); 1118 sThat = NULL; 1119 1120 /* reset the previous tree on success */ 1121 reset(); 1122 1123 m->doc = doc; 1124 /* assign the root key */ 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; 1133 1134 /* reset the previous tree on success */ 1135 reset(); 1136 1137 m->doc = doc; 1138 /* assign the root key */ 1139 m->root = Key (new XmlKeyBackend (xmlDocGetRootElement (m->doc))); 1140 1141 /* memorize the old version string also used as a flag that 1142 * the conversion has been performed (transfers ownership) */ 1143 m->oldVersion = oldVersion; 1144 1145 /* restore the previous entity resolver */ 1146 xmlSetExternalEntityLoader (oldEntityLoader); 1147 sThat = NULL; 1148 } 1149 catch (...) 1150 { 1151 if (doc != NULL) 1152 xmlFreeDoc (doc); 1153 1154 /* restore the previous entity resolver */ 1155 xmlSetExternalEntityLoader (oldEntityLoader); 1156 sThat = NULL; 1157 1158 throw; 1159 } 1130 1160 } 1131 1161 -
trunk/src/VBox/Main/xml/SettingsConverter.xsl
r7341 r7387 51 51 * Forbid non-VirtualBox root nodes 52 52 --> 53 54 53 <xsl:template match="/*"> 55 54 <xsl:message terminate="yes"> … … 61 60 * Forbid all unsupported VirtualBox settings versions 62 61 --> 63 64 62 <xsl:template match="/vb:VirtualBox"> 65 63 <xsl:if test="@version=concat($recentVer,'-',$curVerPlat)"> … … 76 74 77 75 <!-- 78 * Accept supported settings versions (source setting filess to convert) 76 * Accept supported settings versions (source setting files we can convert) 77 * 78 * Note that in order to simplify conversion from versions prior to the previous 79 * one, we support multi-step conversion like this: step 1: 1.0 => 1.1, 80 * step 2: 1.1 => 1.2, where 1.2 is the most recent version. If you want to use 81 * such multi-step mode, you need to ensure that only 1.0 => 1.1 is possible, by 82 * using the 'mode=1.1' attribute on both 'apply-templates' within the starting 83 * '/vb:VirtualBox[1.0]' template and within all templates that this 84 * 'apply-templates' should apply. 85 * 86 * If no 'mode' attribute is used as described above, then a direct conversion 87 * (1.0 => 1.2 in the above example) will happen when version 1.0 of the settings 88 * files is detected. Note that the direct conversion from pre-previous versions 89 * will require to patch their conversion templates so that they include all 90 * modifications from all newer versions, which is error-prone. It's better to 91 * use the milt-step mode. 79 92 --> 80 93 81 94 <!-- @todo temporary --> 82 <xsl:template match="/vb:VirtualBox[substring-before(@version,'-')='1.999']"> 95 <xsl:template match="/vb:VirtualBox[substring-before(@version,'-')='0.1']"> 96 <xsl:copy> 97 <xsl:attribute name="version"><xsl:value-of select="concat('0.2','-',$curVerPlat)"/></xsl:attribute> 98 <xsl:apply-templates select="node()" mode="v0.2"/> 99 </xsl:copy> 100 </xsl:template> 101 <xsl:template match="/vb:VirtualBox[substring-before(@version,'-')='0.2']"> 102 <xsl:copy> 103 <xsl:attribute name="version"><xsl:value-of select="concat('0.3','-',$curVerPlat)"/></xsl:attribute> 104 <xsl:apply-templates select="node()" mode="v0.3"/> 105 </xsl:copy> 106 </xsl:template> 107 108 <xsl:template match="/vb:VirtualBox[substring-before(@version,'-')='0.1']/vb:Machine" 109 mode="v0.2"> 110 <Machine> 111 0.2 112 </Machine> 113 </xsl:template> 114 115 <xsl:template match="/vb:VirtualBox[substring-before(@version,'-')='0.2']/vb:Machine" 116 mode="v0.3"> 117 <Machine> 118 0.3 119 </Machine> 120 </xsl:template> 121 122 <!-- 123 * all non-root elements that are not explicitly matched are copied as is 124 --> 125 <xsl:template match="@*|node()[../..]" mode="v0.2"> 126 <xsl:copy> 127 <xsl:apply-templates select="@*|node()[../..]" mode="v0.2"/> 128 </xsl:copy> 129 </xsl:template> 130 131 <!-- 132 * all non-root elements that are not explicitly matched are copied as is 133 --> 134 <xsl:template match="@*|node()[../..]" mode="v0.3"> 135 <xsl:copy> 136 <xsl:apply-templates select="@*|node()[../..]" mode="v0.3"/> 137 </xsl:copy> 138 </xsl:template> 139 140 <!-- @todo do 1.1 => 1.2 => current? --> 141 <!--xsl:template match="/vb:VirtualBox[substring-before(@version,'-')='1.1']"> 83 142 <xsl:copy> 84 143 <xsl:attribute name="version"><xsl:value-of select="concat($recentVer,'-',$curVerPlat)"/></xsl:attribute> 85 144 <xsl:apply-templates select="node()"/> 86 145 </xsl:copy> 87 </xsl:template> 88 89 <xsl:template match="/vb:VirtualBox[substring-before(@version,'-')='1.1']"> 146 </xsl:template--> 147 148 <!-- 149 <xsl:template match="/vb:VirtualBox[substring-before(@version,'-')='1.2"]"> 90 150 <xsl:copy> 91 151 <xsl:attribute name="version"><xsl:value-of select="concat($recentVer,'-',$curVerPlat)"/></xsl:attribute> … … 93 153 </xsl:copy> 94 154 </xsl:template> 95 96 <!-- 97 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 98 * Individual conversions 99 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100 --> 101 102 <!-- 103 * all non-root elements that are not explicitly matched are copied as is 104 --> 105 <xsl:template match="@*|node()[../..]"> 106 <xsl:copy> 107 <xsl:apply-templates select="@*|node()[../..]"/> 108 </xsl:copy> 109 </xsl:template> 155 --> 156 157 <!-- 158 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 159 * 1.1 => 1.2 ??? 160 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 161 --> 110 162 111 163 <!-- … … 167 219 </xsl:template> 168 220 221 <!-- 222 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 223 * 1.2 => current 224 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 225 --> 226 169 227 </xsl:stylesheet>
Note:
See TracChangeset
for help on using the changeset viewer.