Index: trunk/src/VBox/Main/xml/Settings.cpp
===================================================================
--- trunk/src/VBox/Main/xml/Settings.cpp	(revision 7309)
+++ trunk/src/VBox/Main/xml/Settings.cpp	(revision 7315)
@@ -797,5 +797,6 @@
 {
     Data() : ctxt (NULL), doc (NULL)
-           , inputResolver (NULL) {}
+           , inputResolver (NULL)
+           , autoConverter (NULL), oldVersion (NULL) {}
 
     xmlParserCtxtPtr ctxt;
@@ -806,27 +807,8 @@
     InputResolver *inputResolver;
 
+    AutoConverter *autoConverter;
+    char *oldVersion;
+
     std::auto_ptr <stdx::exception_trap_base> trappedErr;
-
-    struct AutoConv
-    {
-        AutoConv() : root (NULL), attr (NULL), version (NULL), xslt (NULL) {}
-        ~AutoConv() { uninit(); }
-
-        void uninit()
-        {
-            RTStrFree (xslt); xslt = NULL;
-            RTStrFree (version); version = NULL;
-            RTStrFree (attr); attr = NULL;
-            RTStrFree (root); root = NULL;
-        }
-
-        bool isNull() { return xslt == NULL; }
-
-        char *root;
-        char *attr;
-        char *version;
-        char *xslt;
-    }
-    autoConv;
 
     /**
@@ -896,20 +878,17 @@
 }
 
-void XmlTreeBackend::setAutoConversion (const char *aRoot, const char *aAttr,
-                                        const char *aVersion, const char *aTemplate)
-{
-    if (aRoot == NULL && aAttr == NULL && aVersion == NULL && aTemplate == NULL)
-    {
-        m->autoConv.uninit();
-        return;
-    }
-
-    if (aRoot == NULL || aAttr == NULL || aVersion == NULL || aTemplate == NULL)
-        throw EInvalidArg (RT_SRC_POS);
-
-    m->autoConv.root = RTStrDup (aRoot);
-    m->autoConv.attr = RTStrDup (aAttr);
-    m->autoConv.version = RTStrDup (aVersion);
-    m->autoConv.xslt = RTStrDup (aTemplate);
+void XmlTreeBackend::setAutoConverter (AutoConverter &aConverter)
+{
+    m->autoConverter = &aConverter;
+}
+
+void XmlTreeBackend::resetAutoConverter()
+{
+    m->autoConverter = NULL;
+}
+
+const char *XmlTreeBackend::oldVersion() const
+{
+    return m->oldVersion;
 }
 
@@ -957,97 +936,96 @@
     }
 
+    char *oldVersion = NULL;
+
     /* perform automatic document transformation if necessary */
-    if (!m->autoConv.isNull())
+    if (m->autoConverter != NULL)
     {
         Key root = Key (new XmlKeyBackend (xmlDocGetRootElement (doc)));
-        if (!strcmp (root.name(), m->autoConv.root))
+        if (m->autoConverter->needsConversion (root, oldVersion))
         {
-            const char *ver = root.stringValue (m->autoConv.attr);
-            if (strcmp (ver, m->autoConv.version))
+            xmlDocPtr xsltDoc = NULL;
+            xsltStylesheetPtr xslt = NULL;
+            xsltTransformContextPtr tranCtxt = NULL;
+            char *errorStr = NULL;
+
+            try
             {
-                /* version mismatch */
-
-                xmlDocPtr xsltDoc = NULL;
-                xsltStylesheetPtr xslt = NULL;
-                xsltTransformContextPtr tranCtxt = NULL;
-                char *errorStr = NULL;
-
-                try
+                /* parse the XSLT template */
                 {
-                    /* parse the XSLT */
-                    {
-                        Input *xsltInput =
-                            m->inputResolver->resolveEntity (m->autoConv.xslt, NULL);
-                        /* NOTE: new InputCtxt instance will be deleted when the
-                         * stream is closed by the libxml2 API */
-                        xsltDoc = xmlCtxtReadIO (m->ctxt,
-                                                 ReadCallback, CloseCallback,
-                                                 new Data::InputCtxt (xsltInput, m->trappedErr),
-                                                 m->autoConv.xslt, NULL,
-                                                 0);
-                        delete xsltInput;
-                    }
-
-                    if (xsltDoc == NULL)
-                    {
-                        /* look if there was a forwared exception from the lower level */
-                        if (m->trappedErr.get() != NULL)
-                            m->trappedErr->rethrow();
-
-                        throw XmlError (xmlCtxtGetLastError (m->ctxt));
-                    }
-
-                    xslt = xsltParseStylesheetDoc (xsltDoc);
-                    if (xslt == NULL)
-                        throw LogicError (RT_SRC_POS);
-
-                    /* setup transformation error reporting */
-                    tranCtxt = xsltNewTransformContext (xslt, xsltDoc);
-                    if (tranCtxt == NULL)
-                        throw LogicError (RT_SRC_POS);
-                    xsltSetTransformErrorFunc (tranCtxt, &errorStr, ValidityErrorCallback);
-
-                    xmlDocPtr newDoc = xsltApplyStylesheetUser (xslt, doc, NULL,
-                                                                NULL, NULL, tranCtxt);
-                    if (newDoc == NULL)
-                        throw LogicError (RT_SRC_POS);
-
-                    if (errorStr != NULL)
-                    {
-                        xmlFreeDoc (newDoc);
-                        throw Error (errorStr);
-                        /* errorStr is freed in catch(...) below */
-                    }
-
-                    /* replace the old document on success */
-                    xmlFreeDoc (doc);
-                    doc = newDoc;
-
+                    Input *xsltInput =
+                        m->inputResolver->resolveEntity
+                            (m->autoConverter->templateUri(), NULL);
+                    /* NOTE: new InputCtxt instance will be deleted when the
+                     * stream is closed by the libxml2 API */
+                    xsltDoc = xmlCtxtReadIO (m->ctxt,
+                                             ReadCallback, CloseCallback,
+                                             new Data::InputCtxt (xsltInput, m->trappedErr),
+                                             m->autoConverter->templateUri(),
+                                             NULL, 0);
+                    delete xsltInput;
+                }
+
+                if (xsltDoc == NULL)
+                {
+                    /* look if there was a forwared exception from the lower level */
+                    if (m->trappedErr.get() != NULL)
+                        m->trappedErr->rethrow();
+
+                    throw XmlError (xmlCtxtGetLastError (m->ctxt));
+                }
+
+                xslt = xsltParseStylesheetDoc (xsltDoc);
+                if (xslt == NULL)
+                    throw LogicError (RT_SRC_POS);
+
+                /* setup transformation error reporting */
+                tranCtxt = xsltNewTransformContext (xslt, xsltDoc);
+                if (tranCtxt == NULL)
+                    throw LogicError (RT_SRC_POS);
+                xsltSetTransformErrorFunc (tranCtxt, &errorStr, ValidityErrorCallback);
+
+                xmlDocPtr newDoc = xsltApplyStylesheetUser (xslt, doc, NULL,
+                                                            NULL, NULL, tranCtxt);
+                if (newDoc == NULL)
+                    throw LogicError (RT_SRC_POS);
+
+                if (errorStr != NULL)
+                {
+                    xmlFreeDoc (newDoc);
+                    throw Error (errorStr);
+                    /* errorStr is freed in catch(...) below */
+                }
+
+                /* replace the old document on success */
+                xmlFreeDoc (doc);
+                doc = newDoc;
+
+                xsltFreeTransformContext (tranCtxt);
+
+                /* NOTE: xsltFreeStylesheet() also fress the document
+                 * passed to xsltParseStylesheetDoc(). */
+                xsltFreeStylesheet (xslt);
+            }
+            catch (...)
+            {
+                /* restore the previous entity resolver */
+                xmlSetExternalEntityLoader (oldEntityLoader);
+                sThat = NULL;
+
+                RTStrFree (errorStr);
+
+                if (tranCtxt != NULL)
                     xsltFreeTransformContext (tranCtxt);
 
-                    /* NOTE: xsltFreeStylesheet() also fress the document
-                     * passed to xsltParseStylesheetDoc(). */
+                /* NOTE: xsltFreeStylesheet() also fress the document
+                 * passed to xsltParseStylesheetDoc(). */
+                if (xslt != NULL)
                     xsltFreeStylesheet (xslt);
-                }
-                catch (...)
-                {
-                    /* restore the previous entity resolver */
-                    xmlSetExternalEntityLoader (oldEntityLoader);
-                    sThat = NULL;
-
-                    RTStrFree (errorStr);
-
-                    if (tranCtxt != NULL)
-                        xsltFreeTransformContext (tranCtxt);
-
-                    /* NOTE: xsltFreeStylesheet() also fress the document
-                     * passed to xsltParseStylesheetDoc(). */
-                    if (xslt != NULL)
-                        xsltFreeStylesheet (xslt);
-                    else if (xsltDoc != NULL)
-                        xmlFreeDoc (xsltDoc);
-
-                    throw;
-                }
+                else if (xsltDoc != NULL)
+                    xmlFreeDoc (xsltDoc);
+
+                RTStrFree (oldVersion);
+
+                throw;
             }
         }
@@ -1130,4 +1108,6 @@
                 xmlSchemaFreeParserCtxt (schemaCtxt);
 
+            RTStrFree (oldVersion);
+
             throw;
         }
@@ -1144,4 +1124,8 @@
     /* assign the root key */
     m->root = Key (new XmlKeyBackend (xmlDocGetRootElement (m->doc)));
+
+    /* memorize the old version string also used as a flag that
+     * the conversion has been performed (transfers ownership) */
+    m->oldVersion = oldVersion;
 }
 
@@ -1187,4 +1171,7 @@
 void XmlTreeBackend::reset()
 {
+    RTStrFree (m->oldVersion);
+    m->oldVersion = NULL;
+
     if (m->doc)
     {
