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);
/* 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);
/* create IXmlReaderInput basing on supplied interface */
hr = CreateXmlReaderInputWithEncodingName(input,
NULL, NULL, FALSE, NULL, &This->input);
if (hr != S_OK) return hr;
}
/* create IXmlReaderInput basing on supplied interface */
IUnknown_Release(stream_input);
return CreateXmlReaderInputWithEncodingName(stream_input,
NULL, NULL, FALSE, NULL, &This->input);
/* 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 S_OK;
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;
......
......@@ -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]),
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)
......
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