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
);
350 FIXME("privatePath=%s not implemented\n", debugstr_wn(value
, value_size
));
357 static HRESULT
parse_supported_runtime(ConfigFileHandler
*This
, ISAXAttributes
*pAttr
)
359 static const WCHAR version
[] = {'v','e','r','s','i','o','n',0};
360 static const WCHAR sku
[] = {'s','k','u',0};
361 static const WCHAR empty
[] = {0};
365 supported_runtime
*entry
;
367 hr
= ISAXAttributes_getValueFromName(pAttr
, empty
, 0, version
, lstrlenW(version
), &value
, &value_size
);
370 TRACE("%s\n", debugstr_wn(value
, value_size
));
371 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(supported_runtime
));
374 entry
->version
= HeapAlloc(GetProcessHeap(), 0, (value_size
+ 1) * sizeof(WCHAR
));
377 lstrcpyW(entry
->version
, value
);
378 list_add_tail(&This
->result
->supported_runtimes
, &entry
->entry
);
382 HeapFree(GetProcessHeap(), 0, entry
);
390 WARN("Missing version attribute\n");
394 hr
= ISAXAttributes_getValueFromName(pAttr
, empty
, 0, sku
, lstrlenW(sku
), &value
, &value_size
);
396 FIXME("sku=%s not implemented\n", debugstr_wn(value
, value_size
));
403 static HRESULT WINAPI
ConfigFileHandler_startElement(ISAXContentHandler
*iface
,
404 const WCHAR
*pNamespaceUri
, int nNamespaceUri
, const WCHAR
*pLocalName
,
405 int nLocalName
, const WCHAR
*pQName
, int nQName
, ISAXAttributes
*pAttr
)
407 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
408 static const WCHAR configuration
[] = {'c','o','n','f','i','g','u','r','a','t','i','o','n',0};
409 static const WCHAR assemblyBinding
[] = {'a','s','s','e','m','b','l','y','B','i','n','d','i','n','g',0};
410 static const WCHAR probing
[] = {'p','r','o','b','i','n','g',0};
411 static const WCHAR runtime
[] = {'r','u','n','t','i','m','e',0};
412 static const WCHAR startup
[] = {'s','t','a','r','t','u','p',0};
413 static const WCHAR supportedRuntime
[] = {'s','u','p','p','o','r','t','e','d','R','u','n','t','i','m','e',0};
417 TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri
,nNamespaceUri
),
418 debugstr_wn(pLocalName
,nLocalName
), debugstr_wn(pQName
,nQName
));
420 if (This
->statenum
== sizeof(This
->states
) / sizeof(This
->states
[0]) - 1)
422 ERR("file has too much nesting\n");
426 switch (This
->states
[This
->statenum
])
429 if (nLocalName
== sizeof(configuration
)/sizeof(WCHAR
)-1 &&
430 lstrcmpW(pLocalName
, configuration
) == 0)
432 This
->states
[++This
->statenum
] = STATE_CONFIGURATION
;
437 case STATE_CONFIGURATION
:
438 if (nLocalName
== sizeof(startup
)/sizeof(WCHAR
)-1 &&
439 lstrcmpW(pLocalName
, startup
) == 0)
441 hr
= parse_startup(This
, pAttr
);
442 This
->states
[++This
->statenum
] = STATE_STARTUP
;
445 else if (nLocalName
== sizeof(runtime
)/sizeof(WCHAR
)-1 &&
446 lstrcmpW(pLocalName
, runtime
) == 0)
448 This
->states
[++This
->statenum
] = STATE_RUNTIME
;
454 if (nLocalName
== sizeof(assemblyBinding
)/sizeof(WCHAR
)-1 &&
455 lstrcmpW(pLocalName
, assemblyBinding
) == 0)
457 This
->states
[++This
->statenum
] = STATE_ASSEMBLY_BINDING
;
462 case STATE_ASSEMBLY_BINDING
:
463 if (nLocalName
== sizeof(probing
)/sizeof(WCHAR
)-1 &&
464 lstrcmpW(pLocalName
, probing
) == 0)
466 hr
= parse_probing(This
, pAttr
);
467 This
->states
[++This
->statenum
] = STATE_PROBING
;
473 if (nLocalName
== sizeof(supportedRuntime
)/sizeof(WCHAR
)-1 &&
474 lstrcmpW(pLocalName
, supportedRuntime
) == 0)
476 hr
= parse_supported_runtime(This
, pAttr
);
477 This
->states
[++This
->statenum
] = STATE_UNKNOWN
;
489 FIXME("Unknown element %s in state %u\n", debugstr_wn(pLocalName
,nLocalName
),
490 This
->states
[This
->statenum
]);
492 This
->states
[++This
->statenum
] = STATE_UNKNOWN
;
497 static HRESULT WINAPI
ConfigFileHandler_endElement(ISAXContentHandler
*iface
,
498 const WCHAR
*pNamespaceUri
, int nNamespaceUri
, const WCHAR
*pLocalName
,
499 int nLocalName
, const WCHAR
*pQName
, int nQName
)
501 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
503 TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri
,nNamespaceUri
),
504 debugstr_wn(pLocalName
,nLocalName
), debugstr_wn(pQName
,nQName
));
506 if (This
->statenum
> 0)
512 ERR("element end does not match a start\n");
519 static HRESULT WINAPI
ConfigFileHandler_characters(ISAXContentHandler
*iface
,
520 const WCHAR
*pChars
, int nChars
)
522 TRACE("%s\n", debugstr_wn(pChars
,nChars
));
527 static HRESULT WINAPI
ConfigFileHandler_ignorableWhitespace(ISAXContentHandler
*iface
,
528 const WCHAR
*pChars
, int nChars
)
533 static HRESULT WINAPI
ConfigFileHandler_processingInstruction(ISAXContentHandler
*iface
,
534 const WCHAR
*pTarget
, int nTarget
, const WCHAR
*pData
, int nData
)
539 static HRESULT WINAPI
ConfigFileHandler_skippedEntity(ISAXContentHandler
*iface
,
540 const WCHAR
* pName
, int nName
)
542 TRACE("%s\n", debugstr_wn(pName
,nName
));
546 static const struct ISAXContentHandlerVtbl ConfigFileHandlerVtbl
=
548 ConfigFileHandler_QueryInterface
,
549 ConfigFileHandler_AddRef
,
550 ConfigFileHandler_Release
,
551 ConfigFileHandler_putDocumentLocator
,
552 ConfigFileHandler_startDocument
,
553 ConfigFileHandler_endDocument
,
554 ConfigFileHandler_startPrefixMapping
,
555 ConfigFileHandler_endPrefixMapping
,
556 ConfigFileHandler_startElement
,
557 ConfigFileHandler_endElement
,
558 ConfigFileHandler_characters
,
559 ConfigFileHandler_ignorableWhitespace
,
560 ConfigFileHandler_processingInstruction
,
561 ConfigFileHandler_skippedEntity
564 static HRESULT WINAPI
ConfigFileHandler_Error_QueryInterface(ISAXErrorHandler
*iface
,
565 REFIID riid
, void **ppvObject
)
567 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
568 return ISAXContentHandler_QueryInterface(&This
->ISAXContentHandler_iface
, riid
, ppvObject
);
571 static ULONG WINAPI
ConfigFileHandler_Error_AddRef(ISAXErrorHandler
*iface
)
573 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
574 return ISAXContentHandler_AddRef(&This
->ISAXContentHandler_iface
);
577 static ULONG WINAPI
ConfigFileHandler_Error_Release(ISAXErrorHandler
*iface
)
579 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
580 return ISAXContentHandler_Release(&This
->ISAXContentHandler_iface
);
583 static HRESULT WINAPI
ConfigFileHandler_error(ISAXErrorHandler
*iface
,
584 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
586 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
590 static HRESULT WINAPI
ConfigFileHandler_fatalError(ISAXErrorHandler
*iface
,
591 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
593 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
597 static HRESULT WINAPI
ConfigFileHandler_ignorableWarning(ISAXErrorHandler
*iface
,
598 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
600 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
604 static const struct ISAXErrorHandlerVtbl ConfigFileHandlerErrorVtbl
=
606 ConfigFileHandler_Error_QueryInterface
,
607 ConfigFileHandler_Error_AddRef
,
608 ConfigFileHandler_Error_Release
,
609 ConfigFileHandler_error
,
610 ConfigFileHandler_fatalError
,
611 ConfigFileHandler_ignorableWarning
614 static void init_config(parsed_config_file
*config
)
616 list_init(&config
->supported_runtimes
);
619 static HRESULT
parse_config(VARIANT input
, parsed_config_file
*result
)
621 ISAXXMLReader
*reader
;
622 ConfigFileHandler
*handler
;
625 handler
= HeapAlloc(GetProcessHeap(), 0, sizeof(ConfigFileHandler
));
627 return E_OUTOFMEMORY
;
629 handler
->ISAXContentHandler_iface
.lpVtbl
= &ConfigFileHandlerVtbl
;
630 handler
->ISAXErrorHandler_iface
.lpVtbl
= &ConfigFileHandlerErrorVtbl
;
632 handler
->states
[0] = STATE_ROOT
;
633 handler
->statenum
= 0;
634 handler
->result
= result
;
636 hr
= CoCreateInstance(&CLSID_SAXXMLReader
, NULL
, CLSCTX_INPROC_SERVER
,
637 &IID_ISAXXMLReader
, (LPVOID
*)&reader
);
641 hr
= ISAXXMLReader_putContentHandler(reader
, &handler
->ISAXContentHandler_iface
);
644 hr
= ISAXXMLReader_putErrorHandler(reader
, &handler
->ISAXErrorHandler_iface
);
647 hr
= ISAXXMLReader_parse(reader
, input
);
649 ISAXXMLReader_Release(reader
);
652 ISAXContentHandler_Release(&handler
->ISAXContentHandler_iface
);
657 HRESULT
parse_config_file(LPCWSTR filename
, parsed_config_file
*result
)
667 hr
= CreateConfigStream(filename
, &stream
);
671 initresult
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
672 V_VT(&var
) = VT_UNKNOWN
;
673 V_UNKNOWN(&var
) = (IUnknown
*)stream
;
675 hr
= parse_config(var
, result
);
677 IStream_Release(stream
);
678 if (SUCCEEDED(initresult
))
684 void free_parsed_config_file(parsed_config_file
*file
)
686 supported_runtime
*cursor
, *cursor2
;
688 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &file
->supported_runtimes
, supported_runtime
, entry
)
690 HeapFree(GetProcessHeap(), 0, cursor
->version
);
691 list_remove(&cursor
->entry
);
692 HeapFree(GetProcessHeap(), 0, cursor
);