d3d10core: COM cleanup for the ID3D10SamplerState iface.
[wine] / dlls / mscoree / config.c
1 /*
2  * Configuration file parsing
3  *
4  * Copyright 2010 Vincent Povirk
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "ole2.h"
29 #include "msxml2.h"
30 #include "metahost.h"
31 #include "wine/list.h"
32 #include "mscoree_private.h"
33 #include "shlwapi.h"
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
38
39 enum parse_state
40 {
41     STATE_ROOT,
42     STATE_CONFIGURATION,
43     STATE_STARTUP,
44     STATE_UNKNOWN
45 };
46
47 typedef struct ConfigFileHandler
48 {
49     ISAXContentHandler ISAXContentHandler_iface;
50     ISAXErrorHandler ISAXErrorHandler_iface;
51     LONG ref;
52     enum parse_state states[16];
53     int statenum;
54     parsed_config_file *result;
55 } ConfigFileHandler;
56
57 static inline ConfigFileHandler *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
58 {
59     return CONTAINING_RECORD(iface, ConfigFileHandler, ISAXContentHandler_iface);
60 }
61
62 static inline ConfigFileHandler *impl_from_ISAXErrorHandler(ISAXErrorHandler *iface)
63 {
64     return CONTAINING_RECORD(iface, ConfigFileHandler, ISAXErrorHandler_iface);
65 }
66
67 static HRESULT WINAPI ConfigFileHandler_QueryInterface(ISAXContentHandler *iface,
68     REFIID riid, void **ppvObject)
69 {
70     if (IsEqualGUID(riid, &IID_ISAXContentHandler) ||
71         IsEqualGUID(riid, &IID_IUnknown))
72     {
73         *ppvObject = iface;
74     }
75     else
76     {
77         WARN("Unsupported interface %s\n", debugstr_guid(riid));
78         return E_NOINTERFACE;
79     }
80
81     ISAXContentHandler_AddRef(iface);
82
83     return S_OK;
84 }
85
86 static ULONG WINAPI ConfigFileHandler_AddRef(ISAXContentHandler *iface)
87 {
88     ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
89     return InterlockedIncrement(&This->ref);
90 }
91
92 static ULONG WINAPI ConfigFileHandler_Release(ISAXContentHandler *iface)
93 {
94     ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
95     ULONG ref = InterlockedDecrement(&This->ref);
96
97     if (ref == 0)
98         HeapFree(GetProcessHeap(), 0, This);
99
100     return ref;
101 }
102
103 static HRESULT WINAPI ConfigFileHandler_putDocumentLocator(ISAXContentHandler *iface,
104     ISAXLocator *pLocator)
105 {
106     return S_OK;
107 }
108
109 static HRESULT WINAPI ConfigFileHandler_startDocument(ISAXContentHandler *iface)
110 {
111     return S_OK;
112 }
113
114 static HRESULT WINAPI ConfigFileHandler_endDocument(ISAXContentHandler *iface)
115 {
116     return S_OK;
117 }
118
119 static HRESULT WINAPI ConfigFileHandler_startPrefixMapping(ISAXContentHandler *iface,
120     const WCHAR *pPrefix, int nPrefix, const WCHAR *pUri, int nUri)
121 {
122     return S_OK;
123 }
124
125 static HRESULT WINAPI ConfigFileHandler_endPrefixMapping(ISAXContentHandler *iface,
126     const WCHAR *pPrefix, int nPrefix)
127 {
128     return S_OK;
129 }
130
131 static HRESULT parse_startup(ConfigFileHandler *This, ISAXAttributes *pAttr)
132 {
133     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};
134     static const WCHAR empty[] = {0};
135     LPCWSTR value;
136     int value_size;
137     HRESULT hr;
138
139     hr = ISAXAttributes_getValueFromName(pAttr, empty, 0, legacy, lstrlenW(legacy), &value, &value_size);
140     if (SUCCEEDED(hr))
141         FIXME("useLegacyV2RuntimeActivationPolicy=%s not implemented\n", debugstr_wn(value, value_size));
142     hr = S_OK;
143
144     return hr;
145 }
146
147 static HRESULT parse_supported_runtime(ConfigFileHandler *This, ISAXAttributes *pAttr)
148 {
149     static const WCHAR version[] = {'v','e','r','s','i','o','n',0};
150     static const WCHAR sku[] = {'s','k','u',0};
151     static const WCHAR empty[] = {0};
152     LPCWSTR value;
153     int value_size;
154     HRESULT hr;
155     supported_runtime *entry;
156
157     hr = ISAXAttributes_getValueFromName(pAttr, empty, 0, version, lstrlenW(version), &value, &value_size);
158     if (SUCCEEDED(hr))
159     {
160         TRACE("%s\n", debugstr_wn(value, value_size));
161         entry = HeapAlloc(GetProcessHeap(), 0, sizeof(supported_runtime));
162         if (entry)
163         {
164             entry->version = HeapAlloc(GetProcessHeap(), 0, (value_size + 1) * sizeof(WCHAR));
165             if (entry->version)
166             {
167                 lstrcpyW(entry->version, value);
168                 list_add_tail(&This->result->supported_runtimes, &entry->entry);
169             }
170             else
171             {
172                 HeapFree(GetProcessHeap(), 0, entry);
173                 hr = E_OUTOFMEMORY;
174             }
175         }
176         else
177             hr = E_OUTOFMEMORY;
178     }
179     else
180         WARN("Missing version attribute\n");
181
182     if (SUCCEEDED(hr))
183     {
184         hr = ISAXAttributes_getValueFromName(pAttr, empty, 0, sku, lstrlenW(sku), &value, &value_size);
185         if (SUCCEEDED(hr))
186             FIXME("sku=%s not implemented\n", debugstr_wn(value, value_size));
187         hr = S_OK;
188     }
189
190     return hr;
191 }
192
193 static HRESULT WINAPI ConfigFileHandler_startElement(ISAXContentHandler *iface,
194     const WCHAR *pNamespaceUri, int nNamespaceUri, const WCHAR *pLocalName,
195     int nLocalName, const WCHAR *pQName, int nQName, ISAXAttributes *pAttr)
196 {
197     ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
198     static const WCHAR configuration[] = {'c','o','n','f','i','g','u','r','a','t','i','o','n',0};
199     static const WCHAR startup[] = {'s','t','a','r','t','u','p',0};
200     static const WCHAR supportedRuntime[] = {'s','u','p','p','o','r','t','e','d','R','u','n','t','i','m','e',0};
201     HRESULT hr = S_OK;
202
203     TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri,nNamespaceUri),
204         debugstr_wn(pLocalName,nLocalName), debugstr_wn(pQName,nQName));
205
206     if (This->statenum == sizeof(This->states) / sizeof(This->states[0]) - 1)
207     {
208         ERR("file has too much nesting\n");
209         return E_FAIL;
210     }
211
212     switch (This->states[This->statenum])
213     {
214     case STATE_ROOT:
215         if (nLocalName == sizeof(configuration)/sizeof(WCHAR)-1 &&
216             lstrcmpW(pLocalName, configuration) == 0)
217         {
218             This->states[++This->statenum] = STATE_CONFIGURATION;
219             break;
220         }
221         else
222             goto unknown;
223     case STATE_CONFIGURATION:
224         if (nLocalName == sizeof(startup)/sizeof(WCHAR)-1 &&
225             lstrcmpW(pLocalName, startup) == 0)
226         {
227             hr = parse_startup(This, pAttr);
228             This->states[++This->statenum] = STATE_STARTUP;
229             break;
230         }
231         else
232             goto unknown;
233     case STATE_STARTUP:
234         if (nLocalName == sizeof(supportedRuntime)/sizeof(WCHAR)-1 &&
235             lstrcmpW(pLocalName, supportedRuntime) == 0)
236         {
237             hr = parse_supported_runtime(This, pAttr);
238             This->states[++This->statenum] = STATE_UNKNOWN;
239             break;
240         }
241         else
242             goto unknown;
243     default:
244         goto unknown;
245     }
246
247     return hr;
248
249 unknown:
250     FIXME("Unknown element %s in state %u\n", debugstr_wn(pLocalName,nLocalName),
251         This->states[This->statenum]);
252
253     This->states[++This->statenum] = STATE_UNKNOWN;
254
255     return S_OK;
256 }
257
258 static HRESULT WINAPI ConfigFileHandler_endElement(ISAXContentHandler *iface,
259     const WCHAR *pNamespaceUri, int nNamespaceUri, const WCHAR *pLocalName,
260     int nLocalName, const WCHAR *pQName, int nQName)
261 {
262     ConfigFileHandler *This = impl_from_ISAXContentHandler(iface);
263
264     TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri,nNamespaceUri),
265         debugstr_wn(pLocalName,nLocalName), debugstr_wn(pQName,nQName));
266
267     if (This->statenum > 0)
268     {
269         This->statenum--;
270     }
271     else
272     {
273         ERR("element end does not match a start\n");
274         return E_FAIL;
275     }
276
277     return S_OK;
278 }
279
280 static HRESULT WINAPI ConfigFileHandler_characters(ISAXContentHandler *iface,
281     const WCHAR *pChars, int nChars)
282 {
283     TRACE("%s\n", debugstr_wn(pChars,nChars));
284
285     return S_OK;
286 }
287
288 static HRESULT WINAPI ConfigFileHandler_ignorableWhitespace(ISAXContentHandler *iface,
289     const WCHAR *pChars, int nChars)
290 {
291     return S_OK;
292 }
293
294 static HRESULT WINAPI ConfigFileHandler_processingInstruction(ISAXContentHandler *iface,
295     const WCHAR *pTarget, int nTarget, const WCHAR *pData, int nData)
296 {
297     return S_OK;
298 }
299
300 static HRESULT WINAPI ConfigFileHandler_skippedEntity(ISAXContentHandler *iface,
301     const WCHAR * pName, int nName)
302 {
303     TRACE("%s\n", debugstr_wn(pName,nName));
304     return S_OK;
305 }
306
307 static const struct ISAXContentHandlerVtbl ConfigFileHandlerVtbl =
308 {
309     ConfigFileHandler_QueryInterface,
310     ConfigFileHandler_AddRef,
311     ConfigFileHandler_Release,
312     ConfigFileHandler_putDocumentLocator,
313     ConfigFileHandler_startDocument,
314     ConfigFileHandler_endDocument,
315     ConfigFileHandler_startPrefixMapping,
316     ConfigFileHandler_endPrefixMapping,
317     ConfigFileHandler_startElement,
318     ConfigFileHandler_endElement,
319     ConfigFileHandler_characters,
320     ConfigFileHandler_ignorableWhitespace,
321     ConfigFileHandler_processingInstruction,
322     ConfigFileHandler_skippedEntity
323 };
324
325 static HRESULT WINAPI ConfigFileHandler_Error_QueryInterface(ISAXErrorHandler *iface,
326     REFIID riid, void **ppvObject)
327 {
328     if (IsEqualGUID(riid, &IID_ISAXErrorHandler) ||
329         IsEqualGUID(riid, &IID_IUnknown))
330     {
331         *ppvObject = iface;
332     }
333     else
334     {
335         WARN("Unsupported interface %s\n", debugstr_guid(riid));
336         return E_NOINTERFACE;
337     }
338
339     ISAXErrorHandler_AddRef(iface);
340
341     return S_OK;
342 }
343
344 static ULONG WINAPI ConfigFileHandler_Error_AddRef(ISAXErrorHandler *iface)
345 {
346     ConfigFileHandler *This = impl_from_ISAXErrorHandler(iface);
347     return IUnknown_AddRef((IUnknown*)This);
348 }
349
350 static ULONG WINAPI ConfigFileHandler_Error_Release(ISAXErrorHandler *iface)
351 {
352     ConfigFileHandler *This = impl_from_ISAXErrorHandler(iface);
353     return IUnknown_Release((IUnknown*)This);
354 }
355
356 static HRESULT WINAPI ConfigFileHandler_error(ISAXErrorHandler *iface,
357     ISAXLocator * pLocator, const WCHAR * pErrorMessage, HRESULT hrErrorCode)
358 {
359     WARN("%s,%x\n", debugstr_w(pErrorMessage), hrErrorCode);
360     return S_OK;
361 }
362
363 static HRESULT WINAPI ConfigFileHandler_fatalError(ISAXErrorHandler *iface,
364     ISAXLocator * pLocator, const WCHAR * pErrorMessage, HRESULT hrErrorCode)
365 {
366     WARN("%s,%x\n", debugstr_w(pErrorMessage), hrErrorCode);
367     return S_OK;
368 }
369
370 static HRESULT WINAPI ConfigFileHandler_ignorableWarning(ISAXErrorHandler *iface,
371     ISAXLocator * pLocator, const WCHAR * pErrorMessage, HRESULT hrErrorCode)
372 {
373     WARN("%s,%x\n", debugstr_w(pErrorMessage), hrErrorCode);
374     return S_OK;
375 }
376
377 static const struct ISAXErrorHandlerVtbl ConfigFileHandlerErrorVtbl =
378 {
379     ConfigFileHandler_Error_QueryInterface,
380     ConfigFileHandler_Error_AddRef,
381     ConfigFileHandler_Error_Release,
382     ConfigFileHandler_error,
383     ConfigFileHandler_fatalError,
384     ConfigFileHandler_ignorableWarning
385 };
386
387 static void init_config(parsed_config_file *config)
388 {
389     list_init(&config->supported_runtimes);
390 }
391
392 static HRESULT parse_config(VARIANT input, parsed_config_file *result)
393 {
394     ISAXXMLReader *reader;
395     ConfigFileHandler *handler;
396     HRESULT hr;
397
398     handler = HeapAlloc(GetProcessHeap(), 0, sizeof(ConfigFileHandler));
399     if (!handler)
400         return E_OUTOFMEMORY;
401
402     handler->ISAXContentHandler_iface.lpVtbl = &ConfigFileHandlerVtbl;
403     handler->ISAXErrorHandler_iface.lpVtbl = &ConfigFileHandlerErrorVtbl;
404     handler->ref = 1;
405     handler->states[0] = STATE_ROOT;
406     handler->statenum = 0;
407     handler->result = result;
408
409     hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
410         &IID_ISAXXMLReader, (LPVOID*)&reader);
411
412     if (SUCCEEDED(hr))
413     {
414         hr = ISAXXMLReader_putContentHandler(reader, &handler->ISAXContentHandler_iface);
415
416         if (SUCCEEDED(hr))
417             hr = ISAXXMLReader_putErrorHandler(reader, &handler->ISAXErrorHandler_iface);
418
419         if (SUCCEEDED(hr))
420             hr = ISAXXMLReader_parse(reader, input);
421
422         ISAXXMLReader_Release(reader);
423     }
424
425     IUnknown_Release((IUnknown*)handler);
426
427     return S_OK;
428 }
429
430 extern HRESULT parse_config_file(LPCWSTR filename, parsed_config_file *result)
431 {
432     IStream *stream;
433     VARIANT var;
434     HRESULT hr;
435     HRESULT initresult;
436
437     init_config(result);
438
439     initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
440
441     hr = SHCreateStreamOnFileW(filename, STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE, &stream);
442
443     if (SUCCEEDED(hr))
444     {
445         V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
446         V_UNKNOWN(&var) = (IUnknown*)stream;
447
448         hr = parse_config(var, result);
449
450         IStream_Release(stream);
451     }
452
453     if (SUCCEEDED(initresult))
454         CoUninitialize();
455
456     return hr;
457 }
458
459 void free_parsed_config_file(parsed_config_file *file)
460 {
461     supported_runtime *cursor, *cursor2;
462
463     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &file->supported_runtimes, supported_runtime, entry)
464     {
465         HeapFree(GetProcessHeap(), 0, cursor->version);
466         list_remove(&cursor->entry);
467         HeapFree(GetProcessHeap(), 0, cursor);
468     }
469 }