[PATCH 1/2] Implement a query through IXmlReaderInput for underlying stream interface, fix instance sharing between reader and reader input.

Nikolay Sivov bunglehead at gmail.com
Sat Jan 23 10:05:50 CST 2010


---
 dlls/xmllite/reader.c       |   56 ++++++++++++++-----
 dlls/xmllite/tests/reader.c |  133 +++++++++++++++++++++++++++++++++++++++---
 2 files changed, 165 insertions(+), 24 deletions(-)

diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c
index 97476d9..07b54d6 100644
--- a/dlls/xmllite/reader.c
+++ b/dlls/xmllite/reader.c
@@ -21,6 +21,7 @@
 #define COBJMACROS
 
 #include <stdarg.h>
+#include <assert.h>
 #include "windef.h"
 #include "winbase.h"
 #include "initguid.h"
@@ -34,17 +35,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 +102,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 +133,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 +329,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 +384,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 +417,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 +446,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 cb55181..e64b63b 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)
-- 
1.5.6.5


--=-rOLLv6cZh/ynDplgXCnP--




More information about the wine-patches mailing list