From 7b7011e59560992e5eaaa362f96e388715fa42ec Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Sat, 23 Jan 2010 19:05:50 +0300 Subject: [PATCH] xmllite: Implement a query through IXmlReaderInput for underlying stream interface,. --- dlls/xmllite/reader.c | 55 +++++++++++---- dlls/xmllite/tests/reader.c | 133 +++++++++++++++++++++++++++++++++--- 2 files changed, 164 insertions(+), 24 deletions(-) diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c index 97476d9bbb7..51fe44d8d14 100644 --- a/dlls/xmllite/reader.c +++ b/dlls/xmllite/reader.c @@ -34,17 +34,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(xmllite); /* not defined in public headers */ DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda); +static HRESULT xmlreaderinput_query_for_stream(IXmlReaderInput *iface, void **pObj); + typedef struct _xmlreader { const IXmlReaderVtbl *lpVtbl; LONG ref; IXmlReaderInput *input; + ISequentialStream *stream;/* stored as sequential stream, cause currently + optimizations possible with IStream aren't implemented */ } xmlreader; typedef struct _xmlreaderinput { const IUnknownVtbl *lpVtbl; LONG ref; + IUnknown *input; /* reference passed on IXmlReaderInput creation */ } xmlreaderinput; static inline xmlreader *impl_from_IXmlReader(IXmlReader *iface) @@ -96,7 +101,11 @@ static ULONG WINAPI xmlreader_Release(IXmlReader *iface) ref = InterlockedDecrement(&This->ref); if (ref == 0) { - if (This->input) IUnknown_Release(This->input); + if (This->input) + { + IUnknown_Release(This->stream); + IUnknown_Release(This->input); + } HeapFree(GetProcessHeap(), 0, This); } @@ -123,22 +132,22 @@ static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input) hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&This->input); if (hr != S_OK) { - IUnknown *stream_input = NULL; - - hr = IUnknown_QueryInterface(input, &IID_ISequentialStream, (void**)&stream_input); - if (hr != S_OK) - { - hr = IUnknown_QueryInterface(input, &IID_IStream, (void**)&stream_input); - if (hr != S_OK) return hr; - } - /* create IXmlReaderInput basing on supplied interface */ - IUnknown_Release(stream_input); - return CreateXmlReaderInputWithEncodingName(stream_input, + hr = CreateXmlReaderInputWithEncodingName(input, NULL, NULL, FALSE, NULL, &This->input); + if (hr != S_OK) return hr; } - return S_OK; + /* set stream for supplied IXmlReaderInput */ + hr = xmlreaderinput_query_for_stream(This->input, (void**)&This->stream); + if (hr != S_OK) + { + /* IXmlReaderInput doesn't provide streaming interface */ + IUnknown_Release(This->input); + This->input = NULL; + } + + return hr; } static HRESULT WINAPI xmlreader_GetProperty(IXmlReader* iface, UINT property, LONG_PTR *value) @@ -319,7 +328,22 @@ static const struct IXmlReaderVtbl xmlreader_vtbl = xmlreader_IsEOF }; -/* IXmlReaderInput */ +/** IXmlReaderInput **/ + +/* Queries already stored interface for IStream/ISequentialStream. + Interface supplied on creation will be overwritten */ +static HRESULT xmlreaderinput_query_for_stream(IXmlReaderInput *iface, void **pObj) +{ + xmlreaderinput *This = impl_from_IXmlReaderInput(iface); + HRESULT hr; + + hr = IUnknown_QueryInterface(This->input, &IID_IStream, pObj); + if (hr != S_OK) + hr = IUnknown_QueryInterface(This->input, &IID_ISequentialStream, pObj); + + return hr; +} + static HRESULT WINAPI xmlreaderinput_QueryInterface(IXmlReaderInput *iface, REFIID riid, void** ppvObject) { xmlreaderinput *This = impl_from_IXmlReaderInput(iface); @@ -359,6 +383,7 @@ static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface) ref = InterlockedDecrement(&This->ref); if (ref == 0) { + if (This->input) IUnknown_Release(This->input); HeapFree(GetProcessHeap(), 0, This); } @@ -391,6 +416,7 @@ HRESULT WINAPI CreateXmlReader(REFIID riid, void **pObject, IMalloc *pMalloc) reader->lpVtbl = &xmlreader_vtbl; reader->ref = 1; + reader->stream = NULL; reader->input = NULL; *pObject = &reader->lpVtbl; @@ -419,6 +445,7 @@ HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream, readerinput->lpVtbl = &xmlreaderinput_vtbl; readerinput->ref = 1; + IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&readerinput->input); *ppInput = (IXmlReaderInput*)&readerinput->lpVtbl; diff --git a/dlls/xmllite/tests/reader.c b/dlls/xmllite/tests/reader.c index cb55181b5d6..e64b63b9067 100644 --- a/dlls/xmllite/tests/reader.c +++ b/dlls/xmllite/tests/reader.c @@ -58,15 +58,37 @@ typedef struct input_iids_t { static const IID *setinput_full[] = { &IID_IXmlReaderInput, + &IID_IStream, &IID_ISequentialStream, - &IID_IStream + NULL +}; + +/* this applies to early xmllite versions */ +static const IID *setinput_full_old[] = { + &IID_IXmlReaderInput, + &IID_ISequentialStream, + &IID_IStream, + NULL +}; + +/* after ::SetInput(IXmlReaderInput*) */ +static const IID *setinput_readerinput[] = { + &IID_IStream, + &IID_ISequentialStream, + NULL +}; + +static const IID *empty_seq[] = { + NULL }; static input_iids_t input_iids; -static void ok_iids_(const input_iids_t *iids, const IID **expected, int size, int todo, int line) +static void ok_iids_(const input_iids_t *iids, const IID **expected, const IID **exp_broken, int todo, int line) { - int i; + int i = 0, size = 0; + + while (expected[i++]) size++; if (todo) { todo_wine @@ -78,11 +100,12 @@ static void ok_iids_(const input_iids_t *iids, const IID **expected, int size, i if (iids->count != size) return; for (i = 0; i < size; i++) { - ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]), - "Wrong IID(%d), got (%s)\n", i, debugstr_guid(&iids->iids[i])); + ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]) || + (exp_broken ? broken(IsEqualGUID(&iids->iids[i], exp_broken[i])) : FALSE), + "Wrong IID(%d), got (%s)\n", i, debugstr_guid(&iids->iids[i])); } } -#define ok_iids(got, exp, size, todo) ok_iids_(got, exp, size, todo, __LINE__) +#define ok_iids(got, exp, brk, todo) ok_iids_(got, exp, brk, todo, __LINE__) typedef struct _testinput { @@ -199,7 +222,7 @@ static void test_reader_create(void) input_iids.count = 0; hr = IXmlReader_SetInput(reader, input); ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr); - ok_iids(&input_iids, setinput_full, sizeof(setinput_full)/sizeof(REFIID), FALSE); + ok_iids(&input_iids, setinput_full, setinput_full_old, FALSE); IUnknown_Release(input); @@ -209,7 +232,8 @@ static void test_reader_create(void) static void test_readerinput(void) { IXmlReaderInput *reader_input; - IUnknown *obj; + IXmlReader *reader, *reader2; + IUnknown *obj, *input; IStream *stream; HRESULT hr; LONG ref; @@ -228,11 +252,40 @@ static void test_readerinput(void) hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); - /* IXmlReader grabs a stream reference */ + /* IXmlReaderInput grabs a stream reference */ ref = IStream_AddRef(stream); - todo_wine ok(ref == 3, "Expected 3, got %d\n", ref); + ok(ref == 3, "Expected 3, got %d\n", ref); IStream_Release(stream); + /* try ::SetInput() with valid IXmlReaderInput */ + hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + ref = IUnknown_AddRef(reader_input); + ok(ref == 2, "Expected 2, got %d\n", ref); + IUnknown_Release(reader_input); + + hr = IXmlReader_SetInput(reader, reader_input); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + /* IXmlReader grabs a IXmlReaderInput reference */ + ref = IUnknown_AddRef(reader_input); + ok(ref == 3, "Expected 3, got %d\n", ref); + IUnknown_Release(reader_input); + + ref = IStream_AddRef(stream); + ok(ref == 4, "Expected 4, got %d\n", ref); + IStream_Release(stream); + + IXmlReader_Release(reader); + + ref = IStream_AddRef(stream); + ok(ref == 3, "Expected 3, got %d\n", ref); + IStream_Release(stream); + + ref = IUnknown_AddRef(reader_input); + ok(ref == 2, "Expected 2, got %d\n", ref); + IUnknown_Release(reader_input); + /* IID_IXmlReaderInput */ /* it returns a kind of private undocumented vtable incompatible with IUnknown, so it's not a COM interface actually. @@ -246,6 +299,66 @@ static void test_readerinput(void) IUnknown_Release(reader_input); IStream_Release(stream); + + /* test input interface selection sequence */ + hr = testinput_createinstance((void**)&input); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + input_iids.count = 0; + ref = IUnknown_AddRef(input); + ok(ref == 2, "Expected 2, got %d\n", ref); + IUnknown_Release(input); + hr = pCreateXmlReaderInputWithEncodingName(input, NULL, NULL, FALSE, NULL, &reader_input); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_iids(&input_iids, empty_seq, NULL, FALSE); + /* IXmlReaderInput stores stream interface as IUnknown */ + ref = IUnknown_AddRef(input); + ok(ref == 3, "Expected 3, got %d\n", ref); + IUnknown_Release(input); + + hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + input_iids.count = 0; + ref = IUnknown_AddRef(reader_input); + ok(ref == 2, "Expected 2, got %d\n", ref); + IUnknown_Release(reader_input); + ref = IUnknown_AddRef(input); + ok(ref == 3, "Expected 3, got %d\n", ref); + IUnknown_Release(input); + hr = IXmlReader_SetInput(reader, reader_input); + ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr); + ok_iids(&input_iids, setinput_readerinput, NULL, FALSE); + + ref = IUnknown_AddRef(input); + ok(ref == 3, "Expected 3, got %d\n", ref); + IUnknown_Release(input); + + ref = IUnknown_AddRef(reader_input); + ok(ref == 2, "Expected 2, got %d\n", ref); + IUnknown_Release(reader_input); + /* repeat another time, no check or caching here */ + input_iids.count = 0; + hr = IXmlReader_SetInput(reader, reader_input); + ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr); + ok_iids(&input_iids, setinput_readerinput, NULL, FALSE); + + /* another reader */ + hr = pCreateXmlReader(&IID_IXmlReader, (LPVOID*)&reader2, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + /* resolving from IXmlReaderInput to IStream/ISequentialStream is done at + ::SetInput() level, each time it's called */ + input_iids.count = 0; + hr = IXmlReader_SetInput(reader2, reader_input); + ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr); + ok_iids(&input_iids, setinput_readerinput, NULL, FALSE); + + IXmlReader_Release(reader2); + IXmlReader_Release(reader); + + IUnknown_Release(reader_input); + IUnknown_Release(input); } START_TEST(reader)