2 * Configuration file parsing
4 * Copyright 2010 Vincent Povirk
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.
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.
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
34 #include "wine/list.h"
35 #include "mscoree_private.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL( mscoree
);
44 STATE_ASSEMBLY_BINDING
,
53 typedef struct ConfigFileHandler
55 ISAXContentHandler ISAXContentHandler_iface
;
56 ISAXErrorHandler ISAXErrorHandler_iface
;
58 enum parse_state states
[16];
60 parsed_config_file
*result
;
63 static inline ConfigFileHandler
*impl_from_ISAXContentHandler(ISAXContentHandler
*iface
)
65 return CONTAINING_RECORD(iface
, ConfigFileHandler
, ISAXContentHandler_iface
);
68 static inline ConfigFileHandler
*impl_from_ISAXErrorHandler(ISAXErrorHandler
*iface
)
70 return CONTAINING_RECORD(iface
, ConfigFileHandler
, ISAXErrorHandler_iface
);
73 static HRESULT WINAPI
ConfigFileHandler_QueryInterface(ISAXContentHandler
*iface
,
74 REFIID riid
, void **ppvObject
)
76 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
78 if (IsEqualGUID(riid
, &IID_ISAXContentHandler
) || IsEqualGUID(riid
, &IID_IUnknown
))
79 *ppvObject
= &This
->ISAXContentHandler_iface
;
80 else if (IsEqualGUID(riid
, &IID_ISAXErrorHandler
))
81 *ppvObject
= &This
->ISAXErrorHandler_iface
;
84 WARN("Unsupported interface %s\n", debugstr_guid(riid
));
88 IUnknown_AddRef((IUnknown
*)*ppvObject
);
93 static ULONG WINAPI
ConfigFileHandler_AddRef(ISAXContentHandler
*iface
)
95 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
96 return InterlockedIncrement(&This
->ref
);
99 static ULONG WINAPI
ConfigFileHandler_Release(ISAXContentHandler
*iface
)
101 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
102 ULONG ref
= InterlockedDecrement(&This
->ref
);
105 HeapFree(GetProcessHeap(), 0, This
);
110 static HRESULT WINAPI
ConfigFileHandler_putDocumentLocator(ISAXContentHandler
*iface
,
111 ISAXLocator
*pLocator
)
116 static HRESULT WINAPI
ConfigFileHandler_startDocument(ISAXContentHandler
*iface
)
121 static HRESULT WINAPI
ConfigFileHandler_endDocument(ISAXContentHandler
*iface
)
126 static HRESULT WINAPI
ConfigFileHandler_startPrefixMapping(ISAXContentHandler
*iface
,
127 const WCHAR
*pPrefix
, int nPrefix
, const WCHAR
*pUri
, int nUri
)
132 static HRESULT WINAPI
ConfigFileHandler_endPrefixMapping(ISAXContentHandler
*iface
,
133 const WCHAR
*pPrefix
, int nPrefix
)
138 static HRESULT
parse_startup(ConfigFileHandler
*This
, ISAXAttributes
*pAttr
)
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};
146 hr
= ISAXAttributes_getValueFromName(pAttr
, empty
, 0, legacy
, lstrlenW(legacy
), &value
, &value_size
);
148 FIXME("useLegacyV2RuntimeActivationPolicy=%s not implemented\n", debugstr_wn(value
, value_size
));
154 static HRESULT
parse_probing(ConfigFileHandler
*This
, ISAXAttributes
*pAttr
)
156 static const WCHAR privatePath
[] = {'p','r','i','v','a','t','e','P','a','t','h',0};
157 static const WCHAR empty
[] = {0};
162 hr
= ISAXAttributes_getValueFromName(pAttr
, empty
, 0, privatePath
, lstrlenW(privatePath
), &value
, &value_size
);
164 FIXME("privatePath=%s not implemented\n", debugstr_wn(value
, value_size
));
171 static HRESULT
parse_supported_runtime(ConfigFileHandler
*This
, ISAXAttributes
*pAttr
)
173 static const WCHAR version
[] = {'v','e','r','s','i','o','n',0};
174 static const WCHAR sku
[] = {'s','k','u',0};
175 static const WCHAR empty
[] = {0};
179 supported_runtime
*entry
;
181 hr
= ISAXAttributes_getValueFromName(pAttr
, empty
, 0, version
, lstrlenW(version
), &value
, &value_size
);
184 TRACE("%s\n", debugstr_wn(value
, value_size
));
185 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(supported_runtime
));
188 entry
->version
= HeapAlloc(GetProcessHeap(), 0, (value_size
+ 1) * sizeof(WCHAR
));
191 lstrcpyW(entry
->version
, value
);
192 list_add_tail(&This
->result
->supported_runtimes
, &entry
->entry
);
196 HeapFree(GetProcessHeap(), 0, entry
);
204 WARN("Missing version attribute\n");
208 hr
= ISAXAttributes_getValueFromName(pAttr
, empty
, 0, sku
, lstrlenW(sku
), &value
, &value_size
);
210 FIXME("sku=%s not implemented\n", debugstr_wn(value
, value_size
));
217 static HRESULT WINAPI
ConfigFileHandler_startElement(ISAXContentHandler
*iface
,
218 const WCHAR
*pNamespaceUri
, int nNamespaceUri
, const WCHAR
*pLocalName
,
219 int nLocalName
, const WCHAR
*pQName
, int nQName
, ISAXAttributes
*pAttr
)
221 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
222 static const WCHAR configuration
[] = {'c','o','n','f','i','g','u','r','a','t','i','o','n',0};
223 static const WCHAR assemblyBinding
[] = {'a','s','s','e','m','b','l','y','B','i','n','d','i','n','g',0};
224 static const WCHAR probing
[] = {'p','r','o','b','i','n','g',0};
225 static const WCHAR runtime
[] = {'r','u','n','t','i','m','e',0};
226 static const WCHAR startup
[] = {'s','t','a','r','t','u','p',0};
227 static const WCHAR supportedRuntime
[] = {'s','u','p','p','o','r','t','e','d','R','u','n','t','i','m','e',0};
231 TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri
,nNamespaceUri
),
232 debugstr_wn(pLocalName
,nLocalName
), debugstr_wn(pQName
,nQName
));
234 if (This
->statenum
== sizeof(This
->states
) / sizeof(This
->states
[0]) - 1)
236 ERR("file has too much nesting\n");
240 switch (This
->states
[This
->statenum
])
243 if (nLocalName
== sizeof(configuration
)/sizeof(WCHAR
)-1 &&
244 lstrcmpW(pLocalName
, configuration
) == 0)
246 This
->states
[++This
->statenum
] = STATE_CONFIGURATION
;
251 case STATE_CONFIGURATION
:
252 if (nLocalName
== sizeof(startup
)/sizeof(WCHAR
)-1 &&
253 lstrcmpW(pLocalName
, startup
) == 0)
255 hr
= parse_startup(This
, pAttr
);
256 This
->states
[++This
->statenum
] = STATE_STARTUP
;
259 else if (nLocalName
== sizeof(runtime
)/sizeof(WCHAR
)-1 &&
260 lstrcmpW(pLocalName
, runtime
) == 0)
262 This
->states
[++This
->statenum
] = STATE_RUNTIME
;
268 if (nLocalName
== sizeof(assemblyBinding
)/sizeof(WCHAR
)-1 &&
269 lstrcmpW(pLocalName
, assemblyBinding
) == 0)
271 This
->states
[++This
->statenum
] = STATE_ASSEMBLY_BINDING
;
276 case STATE_ASSEMBLY_BINDING
:
277 if (nLocalName
== sizeof(probing
)/sizeof(WCHAR
)-1 &&
278 lstrcmpW(pLocalName
, probing
) == 0)
280 hr
= parse_probing(This
, pAttr
);
281 This
->states
[++This
->statenum
] = STATE_PROBING
;
287 if (nLocalName
== sizeof(supportedRuntime
)/sizeof(WCHAR
)-1 &&
288 lstrcmpW(pLocalName
, supportedRuntime
) == 0)
290 hr
= parse_supported_runtime(This
, pAttr
);
291 This
->states
[++This
->statenum
] = STATE_UNKNOWN
;
303 FIXME("Unknown element %s in state %u\n", debugstr_wn(pLocalName
,nLocalName
),
304 This
->states
[This
->statenum
]);
306 This
->states
[++This
->statenum
] = STATE_UNKNOWN
;
311 static HRESULT WINAPI
ConfigFileHandler_endElement(ISAXContentHandler
*iface
,
312 const WCHAR
*pNamespaceUri
, int nNamespaceUri
, const WCHAR
*pLocalName
,
313 int nLocalName
, const WCHAR
*pQName
, int nQName
)
315 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
317 TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri
,nNamespaceUri
),
318 debugstr_wn(pLocalName
,nLocalName
), debugstr_wn(pQName
,nQName
));
320 if (This
->statenum
> 0)
326 ERR("element end does not match a start\n");
333 static HRESULT WINAPI
ConfigFileHandler_characters(ISAXContentHandler
*iface
,
334 const WCHAR
*pChars
, int nChars
)
336 TRACE("%s\n", debugstr_wn(pChars
,nChars
));
341 static HRESULT WINAPI
ConfigFileHandler_ignorableWhitespace(ISAXContentHandler
*iface
,
342 const WCHAR
*pChars
, int nChars
)
347 static HRESULT WINAPI
ConfigFileHandler_processingInstruction(ISAXContentHandler
*iface
,
348 const WCHAR
*pTarget
, int nTarget
, const WCHAR
*pData
, int nData
)
353 static HRESULT WINAPI
ConfigFileHandler_skippedEntity(ISAXContentHandler
*iface
,
354 const WCHAR
* pName
, int nName
)
356 TRACE("%s\n", debugstr_wn(pName
,nName
));
360 static const struct ISAXContentHandlerVtbl ConfigFileHandlerVtbl
=
362 ConfigFileHandler_QueryInterface
,
363 ConfigFileHandler_AddRef
,
364 ConfigFileHandler_Release
,
365 ConfigFileHandler_putDocumentLocator
,
366 ConfigFileHandler_startDocument
,
367 ConfigFileHandler_endDocument
,
368 ConfigFileHandler_startPrefixMapping
,
369 ConfigFileHandler_endPrefixMapping
,
370 ConfigFileHandler_startElement
,
371 ConfigFileHandler_endElement
,
372 ConfigFileHandler_characters
,
373 ConfigFileHandler_ignorableWhitespace
,
374 ConfigFileHandler_processingInstruction
,
375 ConfigFileHandler_skippedEntity
378 static HRESULT WINAPI
ConfigFileHandler_Error_QueryInterface(ISAXErrorHandler
*iface
,
379 REFIID riid
, void **ppvObject
)
381 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
382 return ISAXContentHandler_QueryInterface(&This
->ISAXContentHandler_iface
, riid
, ppvObject
);
385 static ULONG WINAPI
ConfigFileHandler_Error_AddRef(ISAXErrorHandler
*iface
)
387 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
388 return ISAXContentHandler_AddRef(&This
->ISAXContentHandler_iface
);
391 static ULONG WINAPI
ConfigFileHandler_Error_Release(ISAXErrorHandler
*iface
)
393 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
394 return ISAXContentHandler_Release(&This
->ISAXContentHandler_iface
);
397 static HRESULT WINAPI
ConfigFileHandler_error(ISAXErrorHandler
*iface
,
398 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
400 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
404 static HRESULT WINAPI
ConfigFileHandler_fatalError(ISAXErrorHandler
*iface
,
405 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
407 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
411 static HRESULT WINAPI
ConfigFileHandler_ignorableWarning(ISAXErrorHandler
*iface
,
412 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
414 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
418 static const struct ISAXErrorHandlerVtbl ConfigFileHandlerErrorVtbl
=
420 ConfigFileHandler_Error_QueryInterface
,
421 ConfigFileHandler_Error_AddRef
,
422 ConfigFileHandler_Error_Release
,
423 ConfigFileHandler_error
,
424 ConfigFileHandler_fatalError
,
425 ConfigFileHandler_ignorableWarning
428 static void init_config(parsed_config_file
*config
)
430 list_init(&config
->supported_runtimes
);
433 static HRESULT
parse_config(VARIANT input
, parsed_config_file
*result
)
435 ISAXXMLReader
*reader
;
436 ConfigFileHandler
*handler
;
439 handler
= HeapAlloc(GetProcessHeap(), 0, sizeof(ConfigFileHandler
));
441 return E_OUTOFMEMORY
;
443 handler
->ISAXContentHandler_iface
.lpVtbl
= &ConfigFileHandlerVtbl
;
444 handler
->ISAXErrorHandler_iface
.lpVtbl
= &ConfigFileHandlerErrorVtbl
;
446 handler
->states
[0] = STATE_ROOT
;
447 handler
->statenum
= 0;
448 handler
->result
= result
;
450 hr
= CoCreateInstance(&CLSID_SAXXMLReader
, NULL
, CLSCTX_INPROC_SERVER
,
451 &IID_ISAXXMLReader
, (LPVOID
*)&reader
);
455 hr
= ISAXXMLReader_putContentHandler(reader
, &handler
->ISAXContentHandler_iface
);
458 hr
= ISAXXMLReader_putErrorHandler(reader
, &handler
->ISAXErrorHandler_iface
);
461 hr
= ISAXXMLReader_parse(reader
, input
);
463 ISAXXMLReader_Release(reader
);
466 ISAXContentHandler_Release(&handler
->ISAXContentHandler_iface
);
471 HRESULT
parse_config_file(LPCWSTR filename
, parsed_config_file
*result
)
480 initresult
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
482 hr
= SHCreateStreamOnFileW(filename
, STGM_SHARE_DENY_WRITE
| STGM_READ
| STGM_FAILIFTHERE
, &stream
);
486 V_VT(&var
) = VT_UNKNOWN
;
487 V_UNKNOWN(&var
) = (IUnknown
*)stream
;
489 hr
= parse_config(var
, result
);
491 IStream_Release(stream
);
494 if (SUCCEEDED(initresult
))
500 void free_parsed_config_file(parsed_config_file
*file
)
502 supported_runtime
*cursor
, *cursor2
;
504 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &file
->supported_runtimes
, supported_runtime
, entry
)
506 HeapFree(GetProcessHeap(), 0, cursor
->version
);
507 list_remove(&cursor
->entry
);
508 HeapFree(GetProcessHeap(), 0, cursor
);