From cedd2ab370ba839a74b2e663197241f646ee0295 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Mon, 4 Oct 2010 17:37:00 -0500 Subject: [PATCH 2/8] mscoree: Implement config file parsing. --- dlls/mscoree/Makefile.in | 3 +- dlls/mscoree/assembly.c | 1 + dlls/mscoree/config.c | 469 ++++++++++++++++++++++++++++++++++++++++ dlls/mscoree/corruntimehost.c | 2 +- dlls/mscoree/metahost.c | 44 ++++- dlls/mscoree/mscoree_main.c | 4 + dlls/mscoree/mscoree_private.h | 15 ++ 7 files changed, 533 insertions(+), 5 deletions(-) create mode 100644 dlls/mscoree/config.c diff --git a/dlls/mscoree/Makefile.in b/dlls/mscoree/Makefile.in index dfbd58a..284b18f 100644 --- a/dlls/mscoree/Makefile.in +++ b/dlls/mscoree/Makefile.in @@ -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 diff --git a/dlls/mscoree/assembly.c b/dlls/mscoree/assembly.c index 04e5d23..40279a5 100644 --- a/dlls/mscoree/assembly.c +++ b/dlls/mscoree/assembly.c @@ -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 index 0000000..3a00194 --- /dev/null +++ b/dlls/mscoree/config.c @@ -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 + +#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); + } +} diff --git a/dlls/mscoree/corruntimehost.c b/dlls/mscoree/corruntimehost.c index 46b9f91..58d5e3b 100644 --- a/dlls/mscoree/corruntimehost.c +++ b/dlls/mscoree/corruntimehost.c @@ -32,10 +32,10 @@ #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 ); diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index 35e0e32..3f572f7 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -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); diff --git a/dlls/mscoree/mscoree_main.c b/dlls/mscoree/mscoree_main.c index e0d1e95..c913e6e 100644 --- a/dlls/mscoree/mscoree_main.c +++ b/dlls/mscoree/mscoree_main.c @@ -32,12 +32,16 @@ #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" diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index 00c3652..49cd6a2 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -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; -- 1.7.1