Commit 7b7011e5 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

xmllite: Implement a query through IXmlReaderInput for underlying stream interface,.

parent 37b7de2b
...@@ -34,17 +34,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(xmllite); ...@@ -34,17 +34,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(xmllite);
/* not defined in public headers */ /* not defined in public headers */
DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda); 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 typedef struct _xmlreader
{ {
const IXmlReaderVtbl *lpVtbl; const IXmlReaderVtbl *lpVtbl;
LONG ref; LONG ref;
IXmlReaderInput *input; IXmlReaderInput *input;
ISequentialStream *stream;/* stored as sequential stream, cause currently
optimizations possible with IStream aren't implemented */
} xmlreader; } xmlreader;
typedef struct _xmlreaderinput typedef struct _xmlreaderinput
{ {
const IUnknownVtbl *lpVtbl; const IUnknownVtbl *lpVtbl;
LONG ref; LONG ref;
IUnknown *input; /* reference passed on IXmlReaderInput creation */
} xmlreaderinput; } xmlreaderinput;
static inline xmlreader *impl_from_IXmlReader(IXmlReader *iface) static inline xmlreader *impl_from_IXmlReader(IXmlReader *iface)
...@@ -96,7 +101,11 @@ static ULONG WINAPI xmlreader_Release(IXmlReader *iface) ...@@ -96,7 +101,11 @@ static ULONG WINAPI xmlreader_Release(IXmlReader *iface)
ref = InterlockedDecrement(&This->ref); ref = InterlockedDecrement(&This->ref);
if (ref == 0) 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); HeapFree(GetProcessHeap(), 0, This);
} }
...@@ -123,22 +132,22 @@ static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input) ...@@ -123,22 +132,22 @@ static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input)
hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&This->input); hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&This->input);
if (hr != S_OK) 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 */ /* create IXmlReaderInput basing on supplied interface */
IUnknown_Release(stream_input); hr = CreateXmlReaderInputWithEncodingName(input,
return CreateXmlReaderInputWithEncodingName(stream_input,
NULL, NULL, FALSE, NULL, &This->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) static HRESULT WINAPI xmlreader_GetProperty(IXmlReader* iface, UINT property, LONG_PTR *value)
...@@ -319,7 +328,22 @@ static const struct IXmlReaderVtbl xmlreader_vtbl = ...@@ -319,7 +328,22 @@ static const struct IXmlReaderVtbl xmlreader_vtbl =
xmlreader_IsEOF 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) static HRESULT WINAPI xmlreaderinput_QueryInterface(IXmlReaderInput *iface, REFIID riid, void** ppvObject)
{ {
xmlreaderinput *This = impl_from_IXmlReaderInput(iface); xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
...@@ -359,6 +383,7 @@ static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface) ...@@ -359,6 +383,7 @@ static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface)
ref = InterlockedDecrement(&This->ref); ref = InterlockedDecrement(&This->ref);
if (ref == 0) if (ref == 0)
{ {
if (This->input) IUnknown_Release(This->input);
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
} }
...@@ -391,6 +416,7 @@ HRESULT WINAPI CreateXmlReader(REFIID riid, void **pObject, IMalloc *pMalloc) ...@@ -391,6 +416,7 @@ HRESULT WINAPI CreateXmlReader(REFIID riid, void **pObject, IMalloc *pMalloc)
reader->lpVtbl = &xmlreader_vtbl; reader->lpVtbl = &xmlreader_vtbl;
reader->ref = 1; reader->ref = 1;
reader->stream = NULL;
reader->input = NULL; reader->input = NULL;
*pObject = &reader->lpVtbl; *pObject = &reader->lpVtbl;
...@@ -419,6 +445,7 @@ HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream, ...@@ -419,6 +445,7 @@ HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream,
readerinput->lpVtbl = &xmlreaderinput_vtbl; readerinput->lpVtbl = &xmlreaderinput_vtbl;
readerinput->ref = 1; readerinput->ref = 1;
IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&readerinput->input);
*ppInput = (IXmlReaderInput*)&readerinput->lpVtbl; *ppInput = (IXmlReaderInput*)&readerinput->lpVtbl;
......
...@@ -58,15 +58,37 @@ typedef struct input_iids_t { ...@@ -58,15 +58,37 @@ typedef struct input_iids_t {
static const IID *setinput_full[] = { static const IID *setinput_full[] = {
&IID_IXmlReaderInput, &IID_IXmlReaderInput,
&IID_IStream,
&IID_ISequentialStream, &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 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) { if (todo) {
todo_wine todo_wine
...@@ -78,11 +100,12 @@ static void ok_iids_(const input_iids_t *iids, const IID **expected, int size, i ...@@ -78,11 +100,12 @@ static void ok_iids_(const input_iids_t *iids, const IID **expected, int size, i
if (iids->count != size) return; if (iids->count != size) return;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]), ok_(__FILE__, line)(IsEqualGUID(&iids->iids[i], expected[i]) ||
"Wrong IID(%d), got (%s)\n", i, debugstr_guid(&iids->iids[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 typedef struct _testinput
{ {
...@@ -199,7 +222,7 @@ static void test_reader_create(void) ...@@ -199,7 +222,7 @@ static void test_reader_create(void)
input_iids.count = 0; input_iids.count = 0;
hr = IXmlReader_SetInput(reader, input); hr = IXmlReader_SetInput(reader, input);
ok(hr == E_NOINTERFACE, "Expected E_NOINTERFACE, got %08x\n", hr); 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); IUnknown_Release(input);
...@@ -209,7 +232,8 @@ static void test_reader_create(void) ...@@ -209,7 +232,8 @@ static void test_reader_create(void)
static void test_readerinput(void) static void test_readerinput(void)
{ {
IXmlReaderInput *reader_input; IXmlReaderInput *reader_input;
IUnknown *obj; IXmlReader *reader, *reader2;
IUnknown *obj, *input;
IStream *stream; IStream *stream;
HRESULT hr; HRESULT hr;
LONG ref; LONG ref;
...@@ -228,11 +252,40 @@ static void test_readerinput(void) ...@@ -228,11 +252,40 @@ static void test_readerinput(void)
hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input); hr = pCreateXmlReaderInputWithEncodingName((IUnknown*)stream, NULL, NULL, FALSE, NULL, &reader_input);
ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 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); 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); 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 */ /* IID_IXmlReaderInput */
/* it returns a kind of private undocumented vtable incompatible with IUnknown, /* it returns a kind of private undocumented vtable incompatible with IUnknown,
so it's not a COM interface actually. so it's not a COM interface actually.
...@@ -246,6 +299,66 @@ static void test_readerinput(void) ...@@ -246,6 +299,66 @@ static void test_readerinput(void)
IUnknown_Release(reader_input); IUnknown_Release(reader_input);
IStream_Release(stream); 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) START_TEST(reader)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment