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
== ARRAY_SIZE(This
->states
) - 1)
422 ERR("file has too much nesting\n");
426 switch (This
->states
[This
->statenum
])
429 if (nLocalName
== ARRAY_SIZE(configuration
) - 1 && lstrcmpW(pLocalName
, configuration
) == 0)
431 This
->states
[++This
->statenum
] = STATE_CONFIGURATION
;
436 case STATE_CONFIGURATION
:
437 if (nLocalName
== ARRAY_SIZE(startup
) - 1 && lstrcmpW(pLocalName
, startup
) == 0)
439 hr
= parse_startup(This
, pAttr
);
440 This
->states
[++This
->statenum
] = STATE_STARTUP
;
443 else if (nLocalName
== ARRAY_SIZE(runtime
) - 1 && lstrcmpW(pLocalName
, runtime
) == 0)
445 This
->states
[++This
->statenum
] = STATE_RUNTIME
;
451 if (nLocalName
== ARRAY_SIZE(assemblyBinding
) - 1 &&
452 lstrcmpW(pLocalName
, assemblyBinding
) == 0)
454 This
->states
[++This
->statenum
] = STATE_ASSEMBLY_BINDING
;
459 case STATE_ASSEMBLY_BINDING
:
460 if (nLocalName
== ARRAY_SIZE(probing
) - 1 && lstrcmpW(pLocalName
, probing
) == 0)
462 hr
= parse_probing(This
, pAttr
);
463 This
->states
[++This
->statenum
] = STATE_PROBING
;
469 if (nLocalName
== ARRAY_SIZE(supportedRuntime
) - 1 &&
470 lstrcmpW(pLocalName
, supportedRuntime
) == 0)
472 hr
= parse_supported_runtime(This
, pAttr
);
473 This
->states
[++This
->statenum
] = STATE_UNKNOWN
;
485 FIXME("Unknown element %s in state %u\n", debugstr_wn(pLocalName
,nLocalName
),
486 This
->states
[This
->statenum
]);
488 This
->states
[++This
->statenum
] = STATE_UNKNOWN
;
493 static HRESULT WINAPI
ConfigFileHandler_endElement(ISAXContentHandler
*iface
,
494 const WCHAR
*pNamespaceUri
, int nNamespaceUri
, const WCHAR
*pLocalName
,
495 int nLocalName
, const WCHAR
*pQName
, int nQName
)
497 ConfigFileHandler
*This
= impl_from_ISAXContentHandler(iface
);
499 TRACE("%s %s %s\n", debugstr_wn(pNamespaceUri
,nNamespaceUri
),
500 debugstr_wn(pLocalName
,nLocalName
), debugstr_wn(pQName
,nQName
));
502 if (This
->statenum
> 0)
508 ERR("element end does not match a start\n");
515 static HRESULT WINAPI
ConfigFileHandler_characters(ISAXContentHandler
*iface
,
516 const WCHAR
*pChars
, int nChars
)
518 TRACE("%s\n", debugstr_wn(pChars
,nChars
));
523 static HRESULT WINAPI
ConfigFileHandler_ignorableWhitespace(ISAXContentHandler
*iface
,
524 const WCHAR
*pChars
, int nChars
)
529 static HRESULT WINAPI
ConfigFileHandler_processingInstruction(ISAXContentHandler
*iface
,
530 const WCHAR
*pTarget
, int nTarget
, const WCHAR
*pData
, int nData
)
535 static HRESULT WINAPI
ConfigFileHandler_skippedEntity(ISAXContentHandler
*iface
,
536 const WCHAR
* pName
, int nName
)
538 TRACE("%s\n", debugstr_wn(pName
,nName
));
542 static const struct ISAXContentHandlerVtbl ConfigFileHandlerVtbl
=
544 ConfigFileHandler_QueryInterface
,
545 ConfigFileHandler_AddRef
,
546 ConfigFileHandler_Release
,
547 ConfigFileHandler_putDocumentLocator
,
548 ConfigFileHandler_startDocument
,
549 ConfigFileHandler_endDocument
,
550 ConfigFileHandler_startPrefixMapping
,
551 ConfigFileHandler_endPrefixMapping
,
552 ConfigFileHandler_startElement
,
553 ConfigFileHandler_endElement
,
554 ConfigFileHandler_characters
,
555 ConfigFileHandler_ignorableWhitespace
,
556 ConfigFileHandler_processingInstruction
,
557 ConfigFileHandler_skippedEntity
560 static HRESULT WINAPI
ConfigFileHandler_Error_QueryInterface(ISAXErrorHandler
*iface
,
561 REFIID riid
, void **ppvObject
)
563 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
564 return ISAXContentHandler_QueryInterface(&This
->ISAXContentHandler_iface
, riid
, ppvObject
);
567 static ULONG WINAPI
ConfigFileHandler_Error_AddRef(ISAXErrorHandler
*iface
)
569 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
570 return ISAXContentHandler_AddRef(&This
->ISAXContentHandler_iface
);
573 static ULONG WINAPI
ConfigFileHandler_Error_Release(ISAXErrorHandler
*iface
)
575 ConfigFileHandler
*This
= impl_from_ISAXErrorHandler(iface
);
576 return ISAXContentHandler_Release(&This
->ISAXContentHandler_iface
);
579 static HRESULT WINAPI
ConfigFileHandler_error(ISAXErrorHandler
*iface
,
580 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
582 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
586 static HRESULT WINAPI
ConfigFileHandler_fatalError(ISAXErrorHandler
*iface
,
587 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
589 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
593 static HRESULT WINAPI
ConfigFileHandler_ignorableWarning(ISAXErrorHandler
*iface
,
594 ISAXLocator
* pLocator
, const WCHAR
* pErrorMessage
, HRESULT hrErrorCode
)
596 WARN("%s,%x\n", debugstr_w(pErrorMessage
), hrErrorCode
);
600 static const struct ISAXErrorHandlerVtbl ConfigFileHandlerErrorVtbl
=
602 ConfigFileHandler_Error_QueryInterface
,
603 ConfigFileHandler_Error_AddRef
,
604 ConfigFileHandler_Error_Release
,
605 ConfigFileHandler_error
,
606 ConfigFileHandler_fatalError
,
607 ConfigFileHandler_ignorableWarning
610 static void init_config(parsed_config_file
*config
)
612 list_init(&config
->supported_runtimes
);
615 static HRESULT
parse_config(VARIANT input
, parsed_config_file
*result
)
617 ISAXXMLReader
*reader
;
618 ConfigFileHandler
*handler
;
621 handler
= HeapAlloc(GetProcessHeap(), 0, sizeof(ConfigFileHandler
));
623 return E_OUTOFMEMORY
;
625 handler
->ISAXContentHandler_iface
.lpVtbl
= &ConfigFileHandlerVtbl
;
626 handler
->ISAXErrorHandler_iface
.lpVtbl
= &ConfigFileHandlerErrorVtbl
;
628 handler
->states
[0] = STATE_ROOT
;
629 handler
->statenum
= 0;
630 handler
->result
= result
;
632 hr
= CoCreateInstance(&CLSID_SAXXMLReader
, NULL
, CLSCTX_INPROC_SERVER
,
633 &IID_ISAXXMLReader
, (LPVOID
*)&reader
);
637 hr
= ISAXXMLReader_putContentHandler(reader
, &handler
->ISAXContentHandler_iface
);
640 hr
= ISAXXMLReader_putErrorHandler(reader
, &handler
->ISAXErrorHandler_iface
);
643 hr
= ISAXXMLReader_parse(reader
, input
);
645 ISAXXMLReader_Release(reader
);
648 ISAXContentHandler_Release(&handler
->ISAXContentHandler_iface
);
653 HRESULT
parse_config_file(LPCWSTR filename
, parsed_config_file
*result
)
663 hr
= CreateConfigStream(filename
, &stream
);
667 initresult
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
668 V_VT(&var
) = VT_UNKNOWN
;
669 V_UNKNOWN(&var
) = (IUnknown
*)stream
;
671 hr
= parse_config(var
, result
);
673 IStream_Release(stream
);
674 if (SUCCEEDED(initresult
))
680 void free_parsed_config_file(parsed_config_file
*file
)
682 supported_runtime
*cursor
, *cursor2
;
684 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &file
->supported_runtimes
, supported_runtime
, entry
)
686 HeapFree(GetProcessHeap(), 0, cursor
->version
);
687 list_remove(&cursor
->entry
);
688 HeapFree(GetProcessHeap(), 0, cursor
);