mscoree: Implement config file parsing.
authorVincent Povirk <vincent@codeweavers.com>
Mon, 4 Oct 2010 22:37:00 +0000 (17:37 -0500)
committerAlexandre Julliard <julliard@winehq.org>
Thu, 11 Nov 2010 15:25:10 +0000 (16:25 +0100)
dlls/mscoree/Makefile.in
dlls/mscoree/assembly.c
dlls/mscoree/config.c [new file with mode: 0644]
dlls/mscoree/corruntimehost.c
dlls/mscoree/metahost.c
dlls/mscoree/mscoree_main.c
dlls/mscoree/mscoree_private.h

index dfbd58a84b3b445b4cdf3c6e6d7112b5aa36b799..284b18f0631a5cbbab6219e827956b3ac4ef90fd 100644 (file)
@@ -1,8 +1,9 @@
 MODULE    = mscoree.dll
-IMPORTS   = dbghelp uuid shell32 advapi32
+IMPORTS   = dbghelp uuid shell32 advapi32 ole32 oleaut32 shlwapi
 
 C_SRCS = \
        assembly.c \
+       config.c \
        corruntimehost.c \
        metahost.c \
        mscoree_main.c
index 04e5d23d16657018b149f292308db7af3e7e6007..40279a535ebbf8807a75a9611e77c7c5f10b7dd0 100644 (file)
@@ -29,6 +29,7 @@
 #include "ole2.h"
 #include "corhdr.h"
 #include "metahost.h"
+#include "wine/list.h"
 #include "mscoree_private.h"
 
 #include "wine/debug.h"
diff --git a/dlls/mscoree/config.c b/dlls/mscoree/config.c
new file mode 100644 (file)
index 0000000..3a00194
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Configuration file parsing
+ *
+ * Copyright 2010 Vincent Povirk
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "ole2.h"
+#include "msxml2.h"
+#include "metahost.h"
+#include "wine/list.h"
+#include "mscoree_private.h"
+#include "shlwapi.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
+
+enum parse_state
+{
+    STATE_ROOT,
+    STATE_CONFIGURATION,
+    STATE_STARTUP,
+    STATE_UNKNOWN
+};
+
+typedef struct ConfigFileHandler
+{
+    const struct ISAXContentHandlerVtbl *lpVtbl;
+    const struct ISAXErrorHandlerVtbl *lpErrorVtbl;
+    LONG ref;
+    enum parse_state states[16];
+    int statenum;
+    parsed_config_file *result;
+} ConfigFileHandler;
+
+static inline ConfigFileHandler *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
+{
+    return (ConfigFileHandler *)((char*)iface - FIELD_OFFSET(ConfigFileHandler, lpVtbl));
+}
+
+static inline ConfigFileHandler *impl_from_ISAXErrorHandler(ISAXErrorHandler *iface)
+{
+    return (ConfigFileHandler *)((char*)iface - FIELD_OFFSET(ConfigFileHandler, lpErrorVtbl));
+}
+
+static HRESULT WINAPI ConfigFileHandler_QueryInterface(ISAXContentHandler *iface,
+    REFIID riid, void **ppvObject)
+{
+    if (IsEqualGUID(riid, &IID_ISAXContentHandler) ||
+        IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *ppvObject = iface;
+    }
+    else
+    {
+        WARN("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ISAXContentHandler_AddRef(iface);
+
+    return S_OK;
+}
+
+static ULONG WINAPI ConfigFileHandler_AddRef(ISAXContentHandler *iface)
+{
+    ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI ConfigFileHandler_Release(ISAXContentHandler *iface)
+{
+    ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if (ref == 0)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+static HRESULT WINAPI ConfigFileHandler_putDocumentLocator(ISAXContentHandler *iface,
+    ISAXLocator *pLocator)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_startDocument(ISAXContentHandler *iface)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_endDocument(ISAXContentHandler *iface)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_startPrefixMapping(ISAXContentHandler *iface,
+    const WCHAR *pPrefix, int nPrefix, const WCHAR *pUri, int nUri)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_endPrefixMapping(ISAXContentHandler *iface,
+    const WCHAR *pPrefix, int nPrefix)
+{
+    return S_OK;
+}
+
+static HRESULT parse_startup(ConfigFileHandler *This, ISAXAttributes *pAttr)
+{
+    static const WCHAR legacy[] = {'u','s','e','L','e','g','a','c','y','V','2','R','u','n','t','i','m','e','A','c','t','i','v','a','t','i','o','n','P','o','l','i','c','y',0};
+    static const WCHAR empty[] = {0};
+    LPCWSTR value;
+    int value_size;
+    HRESULT hr;
+
+    hr = ISAXAttributes_getValueFromName(pAttr, empty, 0, legacy, lstrlenW(legacy), &value, &value_size);
+    if (SUCCEEDED(hr))
+        FIXME("useLegacyV2RuntimeActivationPolicy=%s not implemented\n", debugstr_wn(value, value_size));
+    hr = S_OK;
+
+    return hr;
+}
+
+static HRESULT parse_supported_runtime(ConfigFileHandler *This, ISAXAttributes *pAttr)
+{
+    static const WCHAR version[] = {'v','e','r','s','i','o','n',0};
+    static const WCHAR sku[] = {'s','k','u',0};
+    static const WCHAR empty[] = {0};
+    LPCWSTR value;
+    int value_size;
+    HRESULT hr;
+    supported_runtime *entry;
+
+    hr = ISAXAttributes_getValueFromName(pAttr, empty, 0, version, lstrlenW(version), &value, &value_size);
+    if (SUCCEEDED(hr))
+    {
+        TRACE("%s\n", debugstr_wn(value, value_size));
+        entry = HeapAlloc(GetProcessHeap(), 0, sizeof(supported_runtime));
+        if (entry)
+        {
+            entry->version = HeapAlloc(GetProcessHeap(), 0, (value_size + 1) * sizeof(WCHAR));
+            if (entry->version)
+            {
+                lstrcpyW(entry->version, value);
+                list_add_tail(&This->result->supported_runtimes, &entry->entry);
+            }
+            else
+            {
+                HeapFree(GetProcessHeap(), 0, entry);
+                hr = E_OUTOFMEMORY;
+            }
+        }
+        else
+            hr = E_OUTOFMEMORY;
+    }
+    else
+        WARN("Missing version attribute\n");
+
+    if (SUCCEEDED(hr))
+    {
+        hr = ISAXAttributes_getValueFromName(pAttr, empty, 0, sku, lstrlenW(sku), &value, &value_size);
+        if (SUCCEEDED(hr))
+            FIXME("sku=%s not implemented\n", debugstr_wn(value, value_size));
+        hr = S_OK;
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI ConfigFileHandler_startElement(ISAXContentHandler *iface,
+    const WCHAR *pNamespaceUri, int nNamespaceUri, const WCHAR *pLocalName,
+    int nLocalName, const WCHAR *pQName, int nQName, ISAXAttributes *pAttr)
+{
+    ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
+    static const WCHAR configuration[] = {'c','o','n','f','i','g','u','r','a','t','i','o','n',0};
+    static const WCHAR startup[] = {'s','t','a','r','t','u','p',0};
+    static const WCHAR supportedRuntime[] = {'s','u','p','p','o','r','t','e','d','R','u','n','t','i','m','e',0};
+    HRESULT hr = S_OK;
+
+    TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri,nNamespaceUri),
+        debugstr_wn(pLocalName,nLocalName), debugstr_wn(pQName,nQName));
+
+    if (This->statenum == sizeof(This->states) / sizeof(This->states[0]) - 1)
+    {
+        ERR("file has too much nesting\n");
+        return E_FAIL;
+    }
+
+    switch (This->states[This->statenum])
+    {
+    case STATE_ROOT:
+        if (nLocalName == sizeof(configuration)/sizeof(WCHAR)-1 &&
+            lstrcmpW(pLocalName, configuration) == 0)
+        {
+            This->states[++This->statenum] = STATE_CONFIGURATION;
+            break;
+        }
+        else
+            goto unknown;
+    case STATE_CONFIGURATION:
+        if (nLocalName == sizeof(startup)/sizeof(WCHAR)-1 &&
+            lstrcmpW(pLocalName, startup) == 0)
+        {
+            hr = parse_startup(This, pAttr);
+            This->states[++This->statenum] = STATE_STARTUP;
+            break;
+        }
+        else
+            goto unknown;
+    case STATE_STARTUP:
+        if (nLocalName == sizeof(supportedRuntime)/sizeof(WCHAR)-1 &&
+            lstrcmpW(pLocalName, supportedRuntime) == 0)
+        {
+            hr = parse_supported_runtime(This, pAttr);
+            This->states[++This->statenum] = STATE_UNKNOWN;
+            break;
+        }
+        else
+            goto unknown;
+    default:
+        goto unknown;
+    }
+
+    return hr;
+
+unknown:
+    FIXME("Unknown element %s in state %u\n", debugstr_wn(pLocalName,nLocalName),
+        This->states[This->statenum]);
+
+    This->states[++This->statenum] = STATE_UNKNOWN;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_endElement(ISAXContentHandler *iface,
+    const WCHAR *pNamespaceUri, int nNamespaceUri, const WCHAR *pLocalName,
+    int nLocalName, const WCHAR *pQName, int nQName)
+{
+    ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
+
+    TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri,nNamespaceUri),
+        debugstr_wn(pLocalName,nLocalName), debugstr_wn(pQName,nQName));
+
+    if (This->statenum > 0)
+    {
+        This->statenum--;
+    }
+    else
+    {
+        ERR("element end does not match a start\n");
+        return E_FAIL;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_characters(ISAXContentHandler *iface,
+    const WCHAR *pChars, int nChars)
+{
+    TRACE("%s\n", debugstr_wn(pChars,nChars));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_ignorableWhitespace(ISAXContentHandler *iface,
+    const WCHAR *pChars, int nChars)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_processingInstruction(ISAXContentHandler *iface,
+    const WCHAR *pTarget, int nTarget, const WCHAR *pData, int nData)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_skippedEntity(ISAXContentHandler *iface,
+    const WCHAR * pName, int nName)
+{
+    TRACE("%s\n", debugstr_wn(pName,nName));
+    return S_OK;
+}
+
+static const struct ISAXContentHandlerVtbl ConfigFileHandlerVtbl =
+{
+    ConfigFileHandler_QueryInterface,
+    ConfigFileHandler_AddRef,
+    ConfigFileHandler_Release,
+    ConfigFileHandler_putDocumentLocator,
+    ConfigFileHandler_startDocument,
+    ConfigFileHandler_endDocument,
+    ConfigFileHandler_startPrefixMapping,
+    ConfigFileHandler_endPrefixMapping,
+    ConfigFileHandler_startElement,
+    ConfigFileHandler_endElement,
+    ConfigFileHandler_characters,
+    ConfigFileHandler_ignorableWhitespace,
+    ConfigFileHandler_processingInstruction,
+    ConfigFileHandler_skippedEntity
+};
+
+static HRESULT WINAPI ConfigFileHandler_Error_QueryInterface(ISAXErrorHandler *iface,
+    REFIID riid, void **ppvObject)
+{
+    if (IsEqualGUID(riid, &IID_ISAXErrorHandler) ||
+        IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *ppvObject = iface;
+    }
+    else
+    {
+        WARN("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ISAXErrorHandler_AddRef(iface);
+
+    return S_OK;
+}
+
+static ULONG WINAPI ConfigFileHandler_Error_AddRef(ISAXErrorHandler *iface)
+{
+    ConfigFileHandler *This = impl_from_ISAXErrorHandler(iface);
+    return IUnknown_AddRef((IUnknown*)This);
+}
+
+static ULONG WINAPI ConfigFileHandler_Error_Release(ISAXErrorHandler *iface)
+{
+    ConfigFileHandler *This = impl_from_ISAXErrorHandler(iface);
+    return IUnknown_Release((IUnknown*)This);
+}
+
+static HRESULT WINAPI ConfigFileHandler_error(ISAXErrorHandler *iface,
+    ISAXLocator * pLocator, const WCHAR * pErrorMessage, HRESULT hrErrorCode)
+{
+    WARN("%s,%x\n", debugstr_w(pErrorMessage), hrErrorCode);
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_fatalError(ISAXErrorHandler *iface,
+    ISAXLocator * pLocator, const WCHAR * pErrorMessage, HRESULT hrErrorCode)
+{
+    WARN("%s,%x\n", debugstr_w(pErrorMessage), hrErrorCode);
+    return S_OK;
+}
+
+static HRESULT WINAPI ConfigFileHandler_ignorableWarning(ISAXErrorHandler *iface,
+    ISAXLocator * pLocator, const WCHAR * pErrorMessage, HRESULT hrErrorCode)
+{
+    WARN("%s,%x\n", debugstr_w(pErrorMessage), hrErrorCode);
+    return S_OK;
+}
+
+static const struct ISAXErrorHandlerVtbl ConfigFileHandlerErrorVtbl =
+{
+    ConfigFileHandler_Error_QueryInterface,
+    ConfigFileHandler_Error_AddRef,
+    ConfigFileHandler_Error_Release,
+    ConfigFileHandler_error,
+    ConfigFileHandler_fatalError,
+    ConfigFileHandler_ignorableWarning
+};
+
+static void init_config(parsed_config_file *config)
+{
+    list_init(&config->supported_runtimes);
+}
+
+static HRESULT parse_config(VARIANT input, parsed_config_file *result)
+{
+    ISAXXMLReader *reader;
+    ConfigFileHandler *handler;
+    HRESULT hr;
+
+    handler = HeapAlloc(GetProcessHeap(), 0, sizeof(ConfigFileHandler));
+    if (!handler)
+        return E_OUTOFMEMORY;
+
+    handler->lpVtbl = &ConfigFileHandlerVtbl;
+    handler->lpErrorVtbl = &ConfigFileHandlerErrorVtbl;
+    handler->ref = 1;
+    handler->states[0] = STATE_ROOT;
+    handler->statenum = 0;
+    handler->result = result;
+
+    hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
+        &IID_ISAXXMLReader, (LPVOID*)&reader);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = ISAXXMLReader_putContentHandler(reader, (ISAXContentHandler*)&handler->lpVtbl);
+
+        if (SUCCEEDED(hr))
+            hr = ISAXXMLReader_putErrorHandler(reader, (ISAXErrorHandler*)&handler->lpErrorVtbl);
+
+        if (SUCCEEDED(hr))
+            hr = ISAXXMLReader_parse(reader, input);
+
+        ISAXXMLReader_Release(reader);
+    }
+
+    IUnknown_Release((IUnknown*)handler);
+
+    return S_OK;
+}
+
+extern HRESULT parse_config_file(LPCWSTR filename, parsed_config_file *result)
+{
+    IStream *stream;
+    VARIANT var;
+    HRESULT hr;
+    HRESULT initresult;
+
+    init_config(result);
+
+    initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+    hr = SHCreateStreamOnFileW(filename, STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE, &stream);
+
+    if (SUCCEEDED(hr))
+    {
+        V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
+        V_UNKNOWN(&var) = (IUnknown*)stream;
+
+        hr = parse_config(var, result);
+
+        IStream_Release(stream);
+    }
+
+    if (SUCCEEDED(initresult))
+        CoUninitialize();
+
+    return hr;
+}
+
+void free_parsed_config_file(parsed_config_file *file)
+{
+    supported_runtime *cursor, *cursor2;
+
+    LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &file->supported_runtimes, supported_runtime, entry)
+    {
+        HeapFree(GetProcessHeap(), 0, cursor->version);
+        list_remove(&cursor->entry);
+        HeapFree(GetProcessHeap(), 0, cursor);
+    }
+}
index 46b9f91280e2c1e94c926b6fa767a7abac7f36e3..58d5e3bdb32311307649c70c39b0615ac348eefc 100644 (file)
 #include "cor.h"
 #include "mscoree.h"
 #include "metahost.h"
+#include "wine/list.h"
 #include "mscoree_private.h"
 
 #include "wine/debug.h"
-#include "wine/list.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
 
index 35e0e329f117ff418e7d4f59b50f25f2824ea7f1..3f572f7cd938fa690bb05d8507c666c99047829a 100644 (file)
@@ -34,6 +34,7 @@
 #include "corerror.h"
 #include "mscoree.h"
 #include "metahost.h"
+#include "wine/list.h"
 #include "mscoree_private.h"
 
 #include "wine/debug.h"
@@ -1041,15 +1042,15 @@ extern HRESULT CLRMetaHost_CreateInstance(REFIID riid, void **ppobj)
 HRESULT get_runtime_info(LPCWSTR exefile, LPCWSTR version, LPCWSTR config_file,
     DWORD startup_flags, DWORD runtimeinfo_flags, BOOL legacy, ICLRRuntimeInfo **result)
 {
+    static const WCHAR dotconfig[] = {'.','c','o','n','f','i','g',0};
     static const DWORD supported_startup_flags = 0;
     static const DWORD supported_runtime_flags = RUNTIME_INFO_UPGRADE_VERSION;
     int i;
     WCHAR local_version[MAX_PATH];
     ULONG local_version_size = MAX_PATH;
+    WCHAR local_config_file[MAX_PATH];
     HRESULT hr;
-
-    if (config_file)
-        FIXME("ignoring config filename %s\n", debugstr_w(config_file));
+    parsed_config_file parsed_config;
 
     if (startup_flags & ~supported_startup_flags)
         FIXME("unsupported startup flags %x\n", startup_flags & ~supported_startup_flags);
@@ -1057,6 +1058,43 @@ HRESULT get_runtime_info(LPCWSTR exefile, LPCWSTR version, LPCWSTR config_file,
     if (runtimeinfo_flags & ~supported_runtime_flags)
         FIXME("unsupported runtimeinfo flags %x\n", runtimeinfo_flags & ~supported_runtime_flags);
 
+    if (exefile && !config_file)
+    {
+        strcpyW(local_config_file, exefile);
+        strcatW(local_config_file, dotconfig);
+
+        config_file = local_config_file;
+    }
+
+    if (config_file)
+    {
+        int found=0;
+        hr = parse_config_file(config_file, &parsed_config);
+
+        if (SUCCEEDED(hr))
+        {
+            supported_runtime *entry;
+            LIST_FOR_EACH_ENTRY(entry, &parsed_config.supported_runtimes, supported_runtime, entry)
+            {
+                hr = CLRMetaHost_GetRuntime(0, entry->version, &IID_ICLRRuntimeInfo, (void**)result);
+                if (SUCCEEDED(hr))
+                {
+                    found = 1;
+                    break;
+                }
+            }
+        }
+        else
+        {
+            WARN("failed to parse config file %s, hr=%x\n", debugstr_w(config_file), hr);
+        }
+
+        free_parsed_config_file(&parsed_config);
+
+        if (found)
+            return S_OK;
+    }
+
     if (exefile && !version)
     {
         hr = CLRMetaHost_GetVersionFromFile(0, exefile, local_version, &local_version_size);
index e0d1e95e2b9fdaba5916183415812fe5b7806246..c913e6ed2abd38abbb9dcbcd01cc6cfae4f38262 100644 (file)
 #include "ole2.h"
 #include "ocidl.h"
 #include "shellapi.h"
+#include "xmldom.h"
+#include "xmldso.h"
 
 #include "initguid.h"
+#include "msxml2.h"
 #include "cor.h"
 #include "corerror.h"
 #include "mscoree.h"
 #include "metahost.h"
+#include "wine/list.h"
 #include "mscoree_private.h"
 
 #include "wine/debug.h"
index 00c36526fd54074ed886bd313d316c70d258ac12..49cd6a298ddc48ff53b28b91caf9e5589a0ccc89 100644 (file)
@@ -54,6 +54,21 @@ extern HRESULT force_get_runtime_info(ICLRRuntimeInfo **result);
 
 extern HRESULT ICLRRuntimeInfo_GetRuntimeHost(ICLRRuntimeInfo *iface, RuntimeHost **result);
 
+typedef struct parsed_config_file
+{
+    struct list supported_runtimes;
+} parsed_config_file;
+
+typedef struct supported_runtime
+{
+    struct list entry;
+    LPWSTR version;
+} supported_runtime;
+
+extern HRESULT parse_config_file(LPCWSTR filename, parsed_config_file *result);
+
+extern void free_parsed_config_file(parsed_config_file *file);
+
 /* Mono 2.6 embedding */
 typedef struct _MonoDomain MonoDomain;
 typedef struct _MonoAssembly MonoAssembly;