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