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
35 #include "wine/list.h"
36 #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
;
65 IStream IStream_iface
;
70 static inline ConfigStream
*impl_from_IStream(IStream
*iface
)
72 return CONTAINING_RECORD(iface
, ConfigStream
, IStream_iface
);
75 static HRESULT WINAPI
ConfigStream_QueryInterface(IStream
*iface
, REFIID riid
, void **ppv
)
77 ConfigStream
*This
= impl_from_IStream(iface
);
79 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
81 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IStream
))
82 *ppv
= &This
->IStream_iface
;
85 WARN("Not supported iface %s\n", debugstr_guid(riid
));
90 IUnknown_AddRef((IUnknown
*)*ppv
);
94 static ULONG WINAPI
ConfigStream_AddRef(IStream
*iface
)
96 ConfigStream
*This
= impl_from_IStream(iface
);
97 ULONG ref
= InterlockedIncrement(&This
->ref
);
99 TRACE("(%p) ref=%u\n", This
, ref
);
104 static ULONG WINAPI
ConfigStream_Release(IStream
*iface
)
106 ConfigStream
*This
= impl_from_IStream(iface
);
107 ULONG ref
= InterlockedDecrement(&This
->ref
);
109 TRACE("(%p) ref=%u\n",This
, ref
);
113 CloseHandle(This
->file
);
114 HeapFree(GetProcessHeap(), 0, This
);
120 static HRESULT WINAPI
ConfigStream_Read(IStream
*iface
, void *buf
, ULONG size
, ULONG
*ret_read
)
122 ConfigStream
*This
= impl_from_IStream(iface
);
125 TRACE("(%p)->(%p %u %p)\n", This
, buf
, size
, ret_read
);
127 if (!ReadFile(This
->file
, buf
, size
, &read
, NULL
))
129 WARN("error %d reading file\n", GetLastError());
130 return HRESULT_FROM_WIN32(GetLastError());
133 if (ret_read
) *ret_read
= read
;
137 static HRESULT WINAPI
ConfigStream_Write(IStream
*iface
, const void *buf
, ULONG size
, ULONG
*written
)
139 ConfigStream
*This
= impl_from_IStream(iface
);
140 TRACE("(%p)->(%p %u %p)\n", This
, buf
, size
, written
);
144 static HRESULT WINAPI
ConfigStream_Seek(IStream
*iface
, LARGE_INTEGER dlibMove
,
145 DWORD dwOrigin
, ULARGE_INTEGER
*pNewPos
)
147 ConfigStream
*This
= impl_from_IStream(iface
);
148 TRACE("(%p)->(%d %d %p)\n", This
, dlibMove
.u
.LowPart
, dwOrigin
, pNewPos
);
152 static HRESULT WINAPI
ConfigStream_SetSize(IStream
*iface
, ULARGE_INTEGER libNewSize
)
154 ConfigStream
*This
= impl_from_IStream(iface
);
155 TRACE("(%p)->(%d)\n", This
, libNewSize
.u
.LowPart
);
159 static HRESULT WINAPI
ConfigStream_CopyTo(IStream
*iface
, IStream
*stream
, ULARGE_INTEGER size
,
160 ULARGE_INTEGER
*read
, ULARGE_INTEGER
*written
)
162 ConfigStream
*This
= impl_from_IStream(iface
);
163 FIXME("(%p)->(%p %d %p %p)\n", This
, stream
, size
.u
.LowPart
, read
, written
);
167 static HRESULT WINAPI
ConfigStream_Commit(IStream
*iface
, DWORD flags
)
169 ConfigStream
*This
= impl_from_IStream(iface
);
170 FIXME("(%p,%d)\n", This
, flags
);
174 static HRESULT WINAPI
ConfigStream_Revert(IStream
*iface
)
176 ConfigStream
*This
= impl_from_IStream(iface
);
177 TRACE("(%p)\n", This
);
181 static HRESULT WINAPI
ConfigStream_LockUnlockRegion(IStream
*iface
, ULARGE_INTEGER libOffset
,
182 ULARGE_INTEGER cb
, DWORD dwLockType
)
184 ConfigStream
*This
= impl_from_IStream(iface
);
185 TRACE("(%p,%d,%d,%d)\n", This
, libOffset
.u
.LowPart
, cb
.u
.LowPart
, dwLockType
);
189 static HRESULT WINAPI
ConfigStream_Stat(IStream
*iface
, STATSTG
*lpStat
, DWORD grfStatFlag
)
191 ConfigStream
*This
= impl_from_IStream(iface
);
192 FIXME("(%p,%p,%d)\n", This
, lpStat
, grfStatFlag
);
196 static HRESULT WINAPI
ConfigStream_Clone(IStream
*iface
, IStream
**ppstm
)
198 ConfigStream
*This
= impl_from_IStream(iface
);
199 TRACE("(%p)\n",This
);
203 static const IStreamVtbl ConfigStreamVtbl
= {
204 ConfigStream_QueryInterface
,
206 ConfigStream_Release
,
210 ConfigStream_SetSize
,
214 ConfigStream_LockUnlockRegion
,
215 ConfigStream_LockUnlockRegion
,
220 HRESULT WINAPI
CreateConfigStream(const WCHAR
*filename
, IStream
**stream
)
222 ConfigStream
*config_stream
;
225 TRACE("(%s, %p)\n", debugstr_w(filename
), stream
);
228 return COR_E_NULLREFERENCE
;
230 file
= CreateFileW(filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0);
231 if (file
== INVALID_HANDLE_VALUE
)
232 return GetLastError() == ERROR_FILE_NOT_FOUND
? COR_E_FILENOTFOUND
: E_FAIL
;
234 config_stream
= HeapAlloc(GetProcessHeap(), 0, sizeof(*config_stream
));
238 return E_OUTOFMEMORY
;
241 config_stream
->IStream_iface
.lpVtbl
= &ConfigStreamVtbl
;
242 config_stream
->ref
= 1;
243 config_stream
->file
= file
;
245 *stream
= &config_stream
->IStream_iface
;
249 static inline ConfigFileHandler
*impl_from_ISAXContentHandler(ISAXContentHandler
*iface
)
251 return CONTAINING_RECORD(iface
, ConfigFileHandler
, ISAXContentHandler_iface
);
254 static inline ConfigFileHandler
*impl_from_ISAXErrorHandler(ISAXErrorHandler
*iface
)
256 return CONTAINING_RECORD(iface
, ConfigFileHandler
, ISAXErrorHandler_iface
);
259 static HRESULT WINAPI
ConfigFileHandler_QueryInterface(ISAXContentHandler
*iface
,
260 REFIID riid
, void **ppvObject
)
262 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
264 if (IsEqualGUID(riid
, &IID_ISAXContentHandler
) || IsEqualGUID(riid
, &IID_IUnknown
))
265 *ppvObject
= &This
->ISAXContentHandler_iface
;
266 else if (IsEqualGUID(riid
, &IID_ISAXErrorHandler
))
267 *ppvObject
= &This
->ISAXErrorHandler_iface
;
270 WARN("Unsupported interface %s\n", debugstr_guid(riid
));
271 return E_NOINTERFACE
;
274 IUnknown_AddRef((IUnknown
*)*ppvObject
);
279 static ULONG WINAPI
ConfigFileHandler_AddRef(ISAXContentHandler
*iface
)
281 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
282 return InterlockedIncrement(&This
->ref
);
285 static ULONG WINAPI
ConfigFileHandler_Release(ISAXContentHandler
*iface
)
287 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
288 ULONG ref
= InterlockedDecrement(&This
->ref
);
291 HeapFree(GetProcessHeap(), 0, This
);
296 static HRESULT WINAPI
ConfigFileHandler_putDocumentLocator(ISAXContentHandler
*iface
,
297 ISAXLocator
*pLocator
)
302 static HRESULT WINAPI
ConfigFileHandler_startDocument(ISAXContentHandler
*iface
)
307 static HRESULT WINAPI
ConfigFileHandler_endDocument(ISAXContentHandler
*iface
)
312 static HRESULT WINAPI
ConfigFileHandler_startPrefixMapping(ISAXContentHandler
*iface
,
313 const WCHAR
*pPrefix
, int nPrefix
, const WCHAR
*pUri
, int nUri
)
318 static HRESULT WINAPI
ConfigFileHandler_endPrefixMapping(ISAXContentHandler
*iface
,
319 const WCHAR
*pPrefix
, int nPrefix
)
324 static HRESULT
parse_startup(ConfigFileHandler
*This
, ISAXAttributes
*pAttr
)
326 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};
327 static const WCHAR empty
[] = {0};
332 hr
= ISAXAttributes_getValueFromName(pAttr
, empty
, 0, legacy
, lstrlenW(legacy
), &value
, &value_size
);
334 FIXME("useLegacyV2RuntimeActivationPolicy=%s not implemented\n", debugstr_wn(value
, value_size
));
340 static HRESULT
parse_probing(ConfigFileHandler
*This
, ISAXAttributes
*pAttr
)
342 static const WCHAR privatePath
[] = {'p','r','i','v','a','t','e','P','a','t','h',0};
343 static const WCHAR empty
[] = {0};
348 hr
= ISAXAttributes_getValueFromName(pAttr
, empty
, 0, privatePath
, lstrlenW(privatePath
), &value
, &value_size
);
351 TRACE("%s\n", debugstr_wn(value
, value_size
));
353 This
->result
->private_path
= HeapAlloc(GetProcessHeap(), 0, (value_size
+ 1) * sizeof(WCHAR
));
354 if (This
->result
->private_path
)
355 wcscpy(This
->result
->private_path
, value
);
364 static HRESULT
parse_supported_runtime(ConfigFileHandler
*This
, ISAXAttributes
*pAttr
)
366 static const WCHAR version
[] = {'v','e','r','s','i','o','n',0};
367 static const WCHAR sku
[] = {'s','k','u',0};
368 static const WCHAR empty
[] = {0};
372 supported_runtime
*entry
;
374 hr
= ISAXAttributes_getValueFromName(pAttr
, empty
, 0, version
, lstrlenW(version
), &value
, &value_size
);
377 TRACE("%s\n", debugstr_wn(value
, value_size
));
378 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(supported_runtime
));
381 entry
->version
= HeapAlloc(GetProcessHeap(), 0, (value_size
+ 1) * sizeof(WCHAR
));
384 lstrcpyW(entry
->version
, value
);
385 list_add_tail(&This
->result
->supported_runtimes
, &entry
->entry
);
389 HeapFree(GetProcessHeap(), 0, entry
);
397 WARN("Missing version attribute\n");
401 hr
= ISAXAttributes_getValueFromName(pAttr
, empty
, 0, sku
, lstrlenW(sku
), &value
, &value_size
);
403 FIXME("sku=%s not implemented\n", debugstr_wn(value
, value_size
));
410 static HRESULT WINAPI
ConfigFileHandler_startElement(ISAXContentHandler
*iface
,
411 const WCHAR
*pNamespaceUri
, int nNamespaceUri
, const WCHAR
*pLocalName
,
412 int nLocalName
, const WCHAR
*pQName
, int nQName
, ISAXAttributes
*pAttr
)
414 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
415 static const WCHAR configuration
[] = {'c','o','n','f','i','g','u','r','a','t','i','o','n',0};
416 static const WCHAR assemblyBinding
[] = {'a','s','s','e','m','b','l','y','B','i','n','d','i','n','g',0};
417 static const WCHAR probing
[] = {'p','r','o','b','i','n','g',0};
418 static const WCHAR runtime
[] = {'r','u','n','t','i','m','e',0};
419 static const WCHAR startup
[] = {'s','t','a','r','t','u','p',0};
420 static const WCHAR supportedRuntime
[] = {'s','u','p','p','o','r','t','e','d','R','u','n','t','i','m','e',0};
424 TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri
,nNamespaceUri
),
425 debugstr_wn(pLocalName
,nLocalName
), debugstr_wn(pQName
,nQName
));
427 if (This
->statenum
== ARRAY_SIZE(This
->states
) - 1)
429 ERR("file has too much nesting\n");
433 switch (This
->states
[This
->statenum
])
436 if (nLocalName
== ARRAY_SIZE(configuration
) - 1 && wcscmp(pLocalName
, configuration
) == 0)
438 This
->states
[++This
->statenum
] = STATE_CONFIGURATION
;
443 case STATE_CONFIGURATION
:
444 if (nLocalName
== ARRAY_SIZE(startup
) - 1 && wcscmp(pLocalName
, startup
) == 0)
446 hr
= parse_startup(This
, pAttr
);
447 This
->states
[++This
->statenum
] = STATE_STARTUP
;
450 else if (nLocalName
== ARRAY_SIZE(runtime
) - 1 && wcscmp(pLocalName
, runtime
) == 0)
452 This
->states
[++This
->statenum
] = STATE_RUNTIME
;
458 if (nLocalName
== ARRAY_SIZE(assemblyBinding
) - 1 &&
459 wcscmp(pLocalName
, assemblyBinding
) == 0)
461 This
->states
[++This
->statenum
] = STATE_ASSEMBLY_BINDING
;
466 case STATE_ASSEMBLY_BINDING
:
467 if (nLocalName
== ARRAY_SIZE(probing
) - 1 && wcscmp(pLocalName
, probing
) == 0)
469 hr
= parse_probing(This
, pAttr
);
470 This
->states
[++This
->statenum
] = STATE_PROBING
;
476 if (nLocalName
== ARRAY_SIZE(supportedRuntime
) - 1 &&
477 wcscmp(pLocalName
, supportedRuntime
) == 0)
479 hr
= parse_supported_runtime(This
, pAttr
);
480 This
->states
[++This
->statenum
] = STATE_UNKNOWN
;
492 TRACE("Unknown element %s in state %u\n", debugstr_wn(pLocalName
,nLocalName
),
493 This
->states
[This
->statenum
]);
495 This
->states
[++This
->statenum
] = STATE_UNKNOWN
;
500 static HRESULT WINAPI
ConfigFileHandler_endElement(ISAXContentHandler
*iface
,
501 const WCHAR
*pNamespaceUri
, int nNamespaceUri
, const WCHAR
*pLocalName
,
502 int nLocalName
, const WCHAR
*pQName
, int nQName
)
504 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
506 TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri
,nNamespaceUri
),
507 debugstr_wn(pLocalName
,nLocalName
), debugstr_wn(pQName
,nQName
));
509 if (This
->statenum
> 0)
515 ERR("element end does not match a start\n");
522 static HRESULT WINAPI
ConfigFileHandler_characters(ISAXContentHandler
*iface
,
523 const WCHAR
*pChars
, int nChars
)
525 TRACE("%s\n", debugstr_wn(pChars
,nChars
));
530 static HRESULT WINAPI
ConfigFileHandler_ignorableWhitespace(ISAXContentHandler
*iface
,
531 const WCHAR
*pChars
, int nChars
)
536 static HRESULT WINAPI
ConfigFileHandler_processingInstruction(ISAXContentHandler
*iface
,
537 const WCHAR
*pTarget
, int nTarget
, const WCHAR
*pData
, int nData
)
542 static HRESULT WINAPI
ConfigFileHandler_skippedEntity(ISAXContentHandler
*iface
,
543 const WCHAR
* pName
, int nName
)
545 TRACE("%s\n", debugstr_wn(pName
,nName
));
549 static const struct ISAXContentHandlerVtbl ConfigFileHandlerVtbl
=
551 ConfigFileHandler_QueryInterface
,
552 ConfigFileHandler_AddRef
,
553 ConfigFileHandler_Release
,
554 ConfigFileHandler_putDocumentLocator
,
555 ConfigFileHandler_startDocument
,
556 ConfigFileHandler_endDocument
,
557 ConfigFileHandler_startPrefixMapping
,
558 ConfigFileHandler_endPrefixMapping
,
559 ConfigFileHandler_startElement
,
560 ConfigFileHandler_endElement
,
561 ConfigFileHandler_characters
,
562 ConfigFileHandler_ignorableWhitespace
,
563 ConfigFileHandler_processingInstruction
,
564 ConfigFileHandler_skippedEntity
567 static HRESULT WINAPI
ConfigFileHandler_Error_QueryInterface(ISAXErrorHandler
*iface
,
568 REFIID riid
, void **ppvObject
)
570 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
571 return ISAXContentHandler_QueryInterface(&This
->ISAXContentHandler_iface
, riid
, ppvObject
);
574 static ULONG WINAPI
ConfigFileHandler_Error_AddRef(ISAXErrorHandler
*iface
)
576 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
577 return ISAXContentHandler_AddRef(&This
->ISAXContentHandler_iface
);
580 static ULONG WINAPI
ConfigFileHandler_Error_Release(ISAXErrorHandler
*iface
)
582 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
583 return ISAXContentHandler_Release(&This
->ISAXContentHandler_iface
);
586 static HRESULT WINAPI
ConfigFileHandler_error(ISAXErrorHandler
*iface
,
587 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
589 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
593 static HRESULT WINAPI
ConfigFileHandler_fatalError(ISAXErrorHandler
*iface
,
594 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
596 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
600 static HRESULT WINAPI
ConfigFileHandler_ignorableWarning(ISAXErrorHandler
*iface
,
601 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
603 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
607 static const struct ISAXErrorHandlerVtbl ConfigFileHandlerErrorVtbl
=
609 ConfigFileHandler_Error_QueryInterface
,
610 ConfigFileHandler_Error_AddRef
,
611 ConfigFileHandler_Error_Release
,
612 ConfigFileHandler_error
,
613 ConfigFileHandler_fatalError
,
614 ConfigFileHandler_ignorableWarning
617 static void init_config(parsed_config_file
*config
)
619 list_init(&config
->supported_runtimes
);
622 static HRESULT
parse_config(VARIANT input
, parsed_config_file
*result
)
624 ISAXXMLReader
*reader
;
625 ConfigFileHandler
*handler
;
628 handler
= HeapAlloc(GetProcessHeap(), 0, sizeof(ConfigFileHandler
));
630 return E_OUTOFMEMORY
;
632 handler
->ISAXContentHandler_iface
.lpVtbl
= &ConfigFileHandlerVtbl
;
633 handler
->ISAXErrorHandler_iface
.lpVtbl
= &ConfigFileHandlerErrorVtbl
;
635 handler
->states
[0] = STATE_ROOT
;
636 handler
->statenum
= 0;
637 handler
->result
= result
;
639 hr
= CoCreateInstance(&CLSID_SAXXMLReader
, NULL
, CLSCTX_INPROC_SERVER
,
640 &IID_ISAXXMLReader
, (LPVOID
*)&reader
);
644 hr
= ISAXXMLReader_putContentHandler(reader
, &handler
->ISAXContentHandler_iface
);
647 hr
= ISAXXMLReader_putErrorHandler(reader
, &handler
->ISAXErrorHandler_iface
);
650 hr
= ISAXXMLReader_parse(reader
, input
);
652 ISAXXMLReader_Release(reader
);
655 ISAXContentHandler_Release(&handler
->ISAXContentHandler_iface
);
660 HRESULT
parse_config_stream(IStream
*stream
, parsed_config_file
*result
)
668 initresult
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
669 V_VT(&var
) = VT_UNKNOWN
;
670 V_UNKNOWN(&var
) = (IUnknown
*)stream
;
672 hr
= parse_config(var
, result
);
674 if (SUCCEEDED(initresult
))
680 HRESULT
parse_config_file(LPCWSTR filename
, parsed_config_file
*result
)
687 hr
= CreateConfigStream(filename
, &stream
);
691 hr
= parse_config_stream(stream
, result
);
693 IStream_Release(stream
);
698 void free_parsed_config_file(parsed_config_file
*file
)
700 supported_runtime
*cursor
, *cursor2
;
702 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &file
->supported_runtimes
, supported_runtime
, entry
)
704 HeapFree(GetProcessHeap(), 0, cursor
->version
);
705 list_remove(&cursor
->entry
);
706 HeapFree(GetProcessHeap(), 0, cursor
);
709 HeapFree(GetProcessHeap(), 0, file
->private_path
);