>From c83190af2f7e82fa6e5c75d046d5299083268d42 Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov@codeweavers.com>
Date: Sat, 24 Dec 2011 16:10:33 +0300
Subject: [PATCH 1/1] Implement element stack and use it in related callbacks

---
 dlls/msxml3/saxreader.c       |  415 ++++++++++++++++++++---------------------
 dlls/msxml3/tests/saxreader.c |   15 +-
 2 files changed, 218 insertions(+), 212 deletions(-)

diff --git a/dlls/msxml3/saxreader.c b/dlls/msxml3/saxreader.c
index 924a979..16b85ed 100644
--- a/dlls/msxml3/saxreader.c
+++ b/dlls/msxml3/saxreader.c
@@ -42,6 +42,7 @@
 #include "shlwapi.h"
 
 #include "wine/debug.h"
+#include "wine/list.h"
 
 #include "msxml_private.h"
 
@@ -77,6 +78,22 @@ struct bstrpool
 
 typedef struct
 {
+    BSTR prefix;
+    BSTR uri;
+} ns;
+
+typedef struct
+{
+    struct list entry;
+    BSTR prefix;
+    BSTR local;
+    BSTR qname;
+    ns *ns; /* namespaces defined in this particular element */
+    int ns_count;
+} element_entry;
+
+typedef struct
+{
     DispatchEx dispex;
     IVBSAXXMLReader IVBSAXXMLReader_iface;
     ISAXXMLReader ISAXXMLReader_iface;
@@ -111,14 +128,7 @@ typedef struct
     int line;
     int column;
     BOOL vbInterface;
-    int nsStackSize;
-    int nsStackLast;
-    struct nsstack
-    {
-        const xmlChar *ptr;
-        BSTR prefix;
-        BSTR uri;
-    } *nsStack;
+    struct list elements;
 
     BSTR namespaceUri;
     int attributesSize;
@@ -259,73 +269,126 @@ static inline BOOL has_error_handler(const saxlocator *locator)
           (!locator->vbInterface && locator->saxreader->errorHandler);
 }
 
-static HRESULT namespacePush(saxlocator *locator, const xmlChar *prefix,
-        const xmlChar *uri)
+static BSTR build_qname(BSTR prefix, BSTR local)
 {
-    if(locator->nsStackLast>=locator->nsStackSize)
+    if (prefix && *prefix)
     {
-        struct nsstack *new_stack;
+        BSTR qname = SysAllocStringLen(NULL, SysStringLen(prefix) + SysStringLen(local) + 1);
+        WCHAR *ptr;
 
-        new_stack = HeapReAlloc(GetProcessHeap(), 0,
-                locator->nsStack, sizeof(struct nsstack)*locator->nsStackSize*2);
-        if(!new_stack) return E_OUTOFMEMORY;
-        locator->nsStack = new_stack;
-        locator->nsStackSize *= 2;
+        ptr = qname;
+        strcpyW(ptr, prefix);
+        ptr += SysStringLen(prefix);
+        *ptr++ = ':';
+        strcpyW(ptr, local);
+        return qname;
     }
+    else
+        return SysAllocString(local);
+}
+
+static element_entry* alloc_element_entry(const xmlChar *local, const xmlChar *prefix, int nb_ns,
+    const xmlChar **namespaces)
+{
+    element_entry *ret;
+    int i;
+
+    ret = heap_alloc(sizeof(*ret));
+    if (!ret) return ret;
 
-    locator->nsStack[locator->nsStackLast].ptr = uri;
-    if(uri)
+    ret->local  = bstr_from_xmlChar(local);
+    ret->prefix = bstr_from_xmlChar(prefix);
+    ret->qname  = build_qname(ret->prefix, ret->local);
+    ret->ns = nb_ns ? heap_alloc(nb_ns*sizeof(ns)) : NULL;
+    ret->ns_count = nb_ns;
+
+    for (i=0; i < nb_ns; i++)
     {
-        locator->nsStack[locator->nsStackLast].prefix = bstr_from_xmlChar(prefix);
-        if(!locator->nsStack[locator->nsStackLast].prefix)
-            return E_OUTOFMEMORY;
-        locator->nsStack[locator->nsStackLast].uri = bstr_from_xmlChar(uri);
-        if(!locator->nsStack[locator->nsStackLast].uri)
-        {
-            SysFreeString(locator->nsStack[locator->nsStackLast].prefix);
-            return E_OUTOFMEMORY;
-        }
+        ret->ns[i].prefix = bstr_from_xmlChar(namespaces[2*i]);
+        ret->ns[i].uri = bstr_from_xmlChar(namespaces[2*i+1]);
     }
-    else
+
+    return ret;
+}
+
+static void free_element_entry(element_entry *element)
+{
+    int i;
+
+    for (i=0; i<element->ns_count;i++)
     {
-        locator->nsStack[locator->nsStackLast].prefix = NULL;
-        locator->nsStack[locator->nsStackLast].uri = NULL;
+        SysFreeString(element->ns[i].prefix);
+        SysFreeString(element->ns[i].uri);
     }
 
-    locator->nsStackLast++;
+    SysFreeString(element->prefix);
+    SysFreeString(element->local);
 
-    return S_OK;
+    heap_free(element->ns);
+    heap_free(element);
 }
 
-static HRESULT namespacePop(saxlocator *locator)
+static void push_element_ns(saxlocator *locator, element_entry *element)
 {
-    if(locator->nsStackLast == 0)
-    {
-        ERR("namespace stack is empty\n");
-        return E_UNEXPECTED;
-    }
+    list_add_head(&locator->elements, &element->entry);
+}
 
-    SysFreeString(locator->nsStack[--locator->nsStackLast].prefix);
-    SysFreeString(locator->nsStack[locator->nsStackLast].uri);
-    locator->nsStack[locator->nsStackLast].prefix = NULL;
-    locator->nsStack[locator->nsStackLast].uri = NULL;
-    return S_OK;
+static element_entry * pop_element_ns(saxlocator *locator)
+{
+    element_entry *element = LIST_ENTRY(list_head(&locator->elements), element_entry, entry);
+
+    if (element)
+        list_remove(&element->entry);
+
+    return element;
 }
 
-static BSTR namespaceFind(saxlocator *locator, const xmlChar *ptr)
+static BSTR find_element_uri(saxlocator *locator, const xmlChar *uri)
 {
+    element_entry *element;
+    BSTR uriW;
     int i;
 
-    for(i=locator->nsStackLast-1; i>=0; i--)
+    if (!uri) return NULL;
+
+    uriW = bstr_from_xmlChar(uri);
+
+    LIST_FOR_EACH_ENTRY(element, &locator->elements, element_entry, entry)
     {
-        if(ptr == locator->nsStack[i].ptr)
-            return locator->nsStack[i].uri;
+        for (i=0; i < element->ns_count; i++)
+            if (!strcmpW(uriW, element->ns[i].uri))
+            {
+                SysFreeString(uriW);
+                return element->ns[i].uri;
+            }
     }
 
-    ERR("namespace not found\n");
+    SysFreeString(uriW);
+    ERR("namespace uri not found, %s\n", debugstr_a((char*)uri));
     return NULL;
 }
 
+/* used to localize version dependent error check behaviour */
+static inline BOOL sax_callback_failed(saxlocator *This, HRESULT hr)
+{
+    return This->saxreader->version >= MSXML6 ? FAILED(hr) : hr != S_OK;
+}
+
+/* index value -1 means it tries to loop for a first time */
+static inline BOOL iterate_endprefix_index(saxlocator *This, const element_entry *element, int *i)
+{
+    if (This->saxreader->version >= MSXML6)
+    {
+        if (*i == -1) *i = 0; else ++*i;
+        return *i < element->ns_count;
+    }
+    else
+    {
+        if (*i == -1) *i = element->ns_count-1; else --*i;
+        return *i >= 0;
+    }
+}
+
 static BOOL bstr_pool_insert(struct bstrpool *pool, BSTR pool_entry)
 {
     if (!pool->pool)
@@ -427,19 +490,6 @@ static BSTR pooled_bstr_from_xmlCharN(struct bstrpool *pool, const xmlChar *buf,
     return pool_entry;
 }
 
-static BSTR pooled_QName_from_xmlChar(struct bstrpool *pool, const xmlChar *prefix, const xmlChar *name)
-{
-    BSTR pool_entry = QName_from_xmlChar(prefix, name);
-
-    if (pool_entry && !bstr_pool_insert(pool, pool_entry))
-    {
-        SysFreeString(pool_entry);
-        return NULL;
-    }
-
-    return pool_entry;
-}
-
 static void format_error_message_from_id(saxlocator *This, HRESULT hr)
 {
     xmlStopParser(This->pParserCtxt);
@@ -1086,7 +1136,7 @@ static HRESULT SAXAttributes_populate(saxlocator *locator,
     for(index=0; index<nb_attributes; index++)
     {
         attrs[index].szLocalname = bstr_from_xmlChar(xmlAttributes[index*5]);
-        attrs[index].szURI = namespaceFind(locator, xmlAttributes[index*5+2]);
+        attrs[index].szURI = find_element_uri(locator, xmlAttributes[index*5+2]);
         attrs[index].szValue = bstr_from_xmlCharN(xmlAttributes[index*5+3],
                 xmlAttributes[index*5+4]-xmlAttributes[index*5+3]);
         attrs[index].szQName = QName_from_xmlChar(xmlAttributes[index*5+1],
@@ -1124,7 +1174,7 @@ static void libxmlStartDocument(void *ctx)
         else
             hr = ISAXContentHandler_startDocument(This->saxreader->contentHandler);
 
-        if(This->saxreader->version>=MSXML6 ? FAILED(hr) : hr!=S_OK)
+        if (sax_callback_failed(This, hr))
             format_error_message_from_id(This, hr);
     }
 }
@@ -1153,7 +1203,7 @@ static void libxmlEndDocument(void *ctx)
         else
             hr = ISAXContentHandler_endDocument(This->saxreader->contentHandler);
 
-        if(This->saxreader->version>=MSXML6 ? FAILED(hr) : hr!=S_OK)
+        if (sax_callback_failed(This, hr))
             format_error_message_from_id(This, hr);
     }
 }
@@ -1169,10 +1219,9 @@ static void libxmlStartElementNS(
         int nb_defaulted,
         const xmlChar **attributes)
 {
-    BSTR NamespaceUri, LocalName, QName;
     saxlocator *This = ctx;
-    HRESULT hr;
-    int index;
+    element_entry *element;
+    HRESULT hr = S_OK;
 
     update_position(This, TRUE);
     if(*(This->pParserCtxt->input->cur) == '/')
@@ -1180,58 +1229,54 @@ static void libxmlStartElementNS(
     if(This->saxreader->version < MSXML6)
         This->column++;
 
-    hr = namespacePush(This, NULL, NULL);
-    for(index=0; hr==S_OK && index<nb_namespaces; index++)
-        hr = namespacePush(This, namespaces[2*index], namespaces[2*index+1]);
-    if(hr != S_OK)
-    {
-        for(; index>=0; index--)
-            namespacePop(This);
-        namespacePop(This);
-    }
+    element = alloc_element_entry(localname, prefix, nb_namespaces, namespaces);
+    push_element_ns(This, element);
 
-    if(hr==S_OK && has_content_handler(This))
+    if (has_content_handler(This))
     {
-        for(index=0; index<nb_namespaces; index++)
+        BSTR uri;
+        int i;
+
+        for (i = 0; i < nb_namespaces; i++)
         {
             if(This->vbInterface)
                 hr = IVBSAXContentHandler_startPrefixMapping(
                         This->saxreader->vbcontentHandler,
-                        &This->nsStack[This->nsStackLast-nb_namespaces+index].prefix,
-                        &This->nsStack[This->nsStackLast-nb_namespaces+index].uri);
+                        &element->ns[i].prefix,
+                        &element->ns[i].uri);
             else
                 hr = ISAXContentHandler_startPrefixMapping(
                         This->saxreader->contentHandler,
-                        This->nsStack[This->nsStackLast-nb_namespaces+index].prefix,
-                        SysStringLen(This->nsStack[This->nsStackLast-nb_namespaces+index].prefix),
-                        This->nsStack[This->nsStackLast-nb_namespaces+index].uri,
-                        SysStringLen(This->nsStack[This->nsStackLast-nb_namespaces+index].uri));
+                        element->ns[i].prefix,
+                        SysStringLen(element->ns[i].prefix),
+                        element->ns[i].uri,
+                        SysStringLen(element->ns[i].uri));
 
-            if(This->saxreader->version>=MSXML6 ? FAILED(hr) : hr!=S_OK)
+            if (sax_callback_failed(This, hr))
             {
                 format_error_message_from_id(This, hr);
                 return;
             }
         }
 
-        NamespaceUri = namespaceFind(This, URI);
-        LocalName = pooled_bstr_from_xmlChar(&This->saxreader->pool, localname);
-        QName = pooled_QName_from_xmlChar(&This->saxreader->pool, prefix, localname);
+        uri = find_element_uri(This, URI);
 
         hr = SAXAttributes_populate(This, nb_namespaces, namespaces, nb_attributes, attributes);
         if(hr == S_OK)
         {
             if(This->vbInterface)
                 hr = IVBSAXContentHandler_startElement(This->saxreader->vbcontentHandler,
-                        &NamespaceUri, &LocalName, &QName, &This->IVBSAXAttributes_iface);
+                        &uri, &element->local, &element->qname, &This->IVBSAXAttributes_iface);
             else
-                hr = ISAXContentHandler_startElement(This->saxreader->contentHandler, NamespaceUri,
-                        SysStringLen(NamespaceUri), LocalName, SysStringLen(LocalName), QName,
-                        SysStringLen(QName), &This->ISAXAttributes_iface);
+                hr = ISAXContentHandler_startElement(This->saxreader->contentHandler,
+                        uri, SysStringLen(uri),
+                        element->local, SysStringLen(element->local),
+                        element->qname, SysStringLen(element->qname),
+                        &This->ISAXAttributes_iface);
         }
     }
 
-    if(This->saxreader->version>=MSXML6 ? FAILED(hr) : hr!=S_OK)
+    if (sax_callback_failed(This, hr))
         format_error_message_from_id(This, hr);
 }
 
@@ -1241,11 +1286,12 @@ static void libxmlEndElementNS(
         const xmlChar *prefix,
         const xmlChar *URI)
 {
-    BSTR NamespaceUri, LocalName, QName;
     saxlocator *This = ctx;
-    HRESULT hr;
+    element_entry *element;
     const xmlChar *p;
-    struct nsstack *elem = &This->nsStack[This->nsStackLast-1];
+    HRESULT hr;
+    BSTR uri;
+    int i;
 
     update_position(This, FALSE);
     p = This->pParserCtxt->input->cur;
@@ -1274,96 +1320,53 @@ static void libxmlEndElementNS(
     for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--)
         This->column++;
 
-    if(has_content_handler(This))
-    {
-        NamespaceUri = namespaceFind(This, URI);
-        LocalName = pooled_bstr_from_xmlChar(&This->saxreader->pool, localname);
-        QName = pooled_QName_from_xmlChar(&This->saxreader->pool, prefix, localname);
-
-        if(This->vbInterface)
-            hr = IVBSAXContentHandler_endElement(
-                    This->saxreader->vbcontentHandler,
-                    &NamespaceUri, &LocalName, &QName);
-        else
-            hr = ISAXContentHandler_endElement(
-                    This->saxreader->contentHandler,
-                    NamespaceUri, SysStringLen(NamespaceUri),
-                    LocalName, SysStringLen(LocalName),
-                    QName, SysStringLen(QName));
+    uri = find_element_uri(This, URI);
+    element = pop_element_ns(This);
 
+    if (!has_content_handler(This))
+    {
         This->nb_attributes = 0;
+        free_element_entry(element);
+        return;
+    }
 
-        if(This->saxreader->version>=MSXML6 ? FAILED(hr) : hr!=S_OK)
-        {
-            format_error_message_from_id(This, hr);
-            return;
-        }
-
-        if(This->saxreader->version >= MSXML6)
-        {
-            while(elem->ptr) {
-                elem--;
-            }
-            elem++;
-
-            while(elem < &This->nsStack[This->nsStackLast]) {
-                if(This->vbInterface)
-                    hr = IVBSAXContentHandler_endPrefixMapping(
-                            This->saxreader->vbcontentHandler, &elem->prefix);
-                else
-                    hr = ISAXContentHandler_endPrefixMapping(
-                            This->saxreader->contentHandler,
-                            elem->prefix, SysStringLen(elem->prefix));
+    if(This->vbInterface)
+        hr = IVBSAXContentHandler_endElement(
+                This->saxreader->vbcontentHandler,
+                &uri, &element->local, &element->qname);
+    else
+        hr = ISAXContentHandler_endElement(
+                This->saxreader->contentHandler,
+                uri, SysStringLen(uri),
+                element->local, SysStringLen(element->local),
+                element->qname, SysStringLen(element->qname));
 
-                if(hr != S_OK)
-                {
-                    format_error_message_from_id(This, hr);
-                    return;
-                }
+    This->nb_attributes = 0;
 
-                elem++;
-            }
+    if (sax_callback_failed(This, hr))
+    {
+        format_error_message_from_id(This, hr);
+        return;
+    }
 
-            elem--;
-            while(elem->ptr) {
-                namespacePop(This);
-                elem--;
-            }
-        }
+    i = -1;
+    while (iterate_endprefix_index(This, element, &i))
+    {
+        if(This->vbInterface)
+            hr = IVBSAXContentHandler_endPrefixMapping(
+                    This->saxreader->vbcontentHandler, &element->ns[i].prefix);
         else
-        {
-            while(1) {
-                if(!elem->ptr)
-                    break;
+            hr = ISAXContentHandler_endPrefixMapping(
+                    This->saxreader->contentHandler,
+                    element->ns[i].prefix, SysStringLen(element->ns[i].prefix));
 
-                if(This->vbInterface)
-                    hr = IVBSAXContentHandler_endPrefixMapping(
-                            This->saxreader->vbcontentHandler, &elem->prefix);
-                else
-                    hr = ISAXContentHandler_endPrefixMapping(
-                            This->saxreader->contentHandler,
-                            elem->prefix, SysStringLen(elem->prefix));
+        if (sax_callback_failed(This, hr)) break;
+    }
 
-                if(FAILED(hr))
-                {
-                    format_error_message_from_id(This, hr);
-                    return;
-                }
+    if (sax_callback_failed(This, hr))
+        format_error_message_from_id(This, hr);
 
-                namespacePop(This);
-                elem--;
-            }
-        }
-    }
-    else
-    {
-        This->nb_attributes = 0;
-        while(elem->ptr) {
-            namespacePop(This);
-            elem--;
-        }
-    }
-    namespacePop(This);
+    free_element_entry(element);
 }
 
 static void libxmlCharacters(
@@ -1438,7 +1441,7 @@ static void libxmlCharacters(
                     This->saxreader->contentHandler,
                     Chars, SysStringLen(Chars));
 
-        if(This->saxreader->version>=MSXML6 ? FAILED(hr) : hr!=S_OK)
+        if (sax_callback_failed(This, hr))
         {
             format_error_message_from_id(This, hr);
             return;
@@ -1820,7 +1823,7 @@ static HRESULT WINAPI ivbsaxlocator_get_systemId(
             (const WCHAR**)systemId);
 }
 
-static const struct IVBSAXLocatorVtbl ivbsaxlocator_vtbl =
+static const struct IVBSAXLocatorVtbl VBSAXLocatorVtbl =
 {
     ivbsaxlocator_QueryInterface,
     ivbsaxlocator_AddRef,
@@ -1868,29 +1871,27 @@ static HRESULT WINAPI isaxlocator_QueryInterface(ISAXLocator* iface, REFIID riid
 static ULONG WINAPI isaxlocator_AddRef(ISAXLocator* iface)
 {
     saxlocator *This = impl_from_ISAXLocator( iface );
-    TRACE("%p\n", This );
-    return InterlockedIncrement( &This->ref );
+    ULONG ref = InterlockedIncrement( &This->ref );
+    TRACE("(%p)->(%d)\n", This, ref);
+    return ref;
 }
 
 static ULONG WINAPI isaxlocator_Release(
         ISAXLocator* iface)
 {
     saxlocator *This = impl_from_ISAXLocator( iface );
-    LONG ref;
+    LONG ref = InterlockedDecrement( &This->ref );
 
-    TRACE("%p\n", This );
+    TRACE("(%p)->(%d)\n", This, ref );
 
-    ref = InterlockedDecrement( &This->ref );
-    if ( ref == 0 )
+    if (ref == 0)
     {
+        element_entry *element, *element2;
         int index;
 
         SysFreeString(This->publicId);
         SysFreeString(This->systemId);
         SysFreeString(This->namespaceUri);
-        while(This->nsStackLast)
-            namespacePop(This);
-        heap_free(This->nsStack);
 
         for(index=0; index<This->nb_attributes; index++)
         {
@@ -1900,6 +1901,13 @@ static ULONG WINAPI isaxlocator_Release(
         }
         heap_free(This->attributes);
 
+        /* element stack */
+        LIST_FOR_EACH_ENTRY_SAFE(element, element2, &This->elements, element_entry, entry)
+        {
+            list_remove(&element->entry);
+            free_element_entry(element);
+        }
+
         ISAXXMLReader_Release(&This->saxreader->ISAXXMLReader_iface);
         heap_free( This );
     }
@@ -1972,7 +1980,7 @@ static HRESULT WINAPI isaxlocator_getSystemId(
     return S_OK;
 }
 
-static const struct ISAXLocatorVtbl isaxlocator_vtbl =
+static const struct ISAXLocatorVtbl SAXLocatorVtbl =
 {
     isaxlocator_QueryInterface,
     isaxlocator_AddRef,
@@ -1994,8 +2002,8 @@ static HRESULT SAXLocator_create(saxreader *reader, saxlocator **ppsaxlocator, B
     if( !locator )
         return E_OUTOFMEMORY;
 
-    locator->IVBSAXLocator_iface.lpVtbl = &ivbsaxlocator_vtbl;
-    locator->ISAXLocator_iface.lpVtbl = &isaxlocator_vtbl;
+    locator->IVBSAXLocator_iface.lpVtbl = &VBSAXLocatorVtbl;
+    locator->ISAXLocator_iface.lpVtbl = &SAXLocatorVtbl;
     locator->IVBSAXAttributes_iface.lpVtbl = &ivbsaxattributes_vtbl;
     locator->ISAXAttributes_iface.lpVtbl = &isaxattributes_vtbl;
     locator->ref = 1;
@@ -2020,16 +2028,6 @@ static HRESULT SAXLocator_create(saxreader *reader, saxlocator **ppsaxlocator, B
         heap_free(locator);
         return E_OUTOFMEMORY;
     }
-    locator->nsStackSize = 8;
-    locator->nsStackLast = 0;
-    locator->nsStack = heap_alloc(sizeof(struct nsstack)*locator->nsStackSize);
-    if(!locator->nsStack)
-    {
-        ISAXXMLReader_Release(&reader->ISAXXMLReader_iface);
-        SysFreeString(locator->namespaceUri);
-        heap_free(locator);
-        return E_OUTOFMEMORY;
-    }
 
     locator->attributesSize = 8;
     locator->nb_attributes = 0;
@@ -2038,11 +2036,12 @@ static HRESULT SAXLocator_create(saxreader *reader, saxlocator **ppsaxlocator, B
     {
         ISAXXMLReader_Release(&reader->ISAXXMLReader_iface);
         SysFreeString(locator->namespaceUri);
-        heap_free(locator->nsStack);
         heap_free(locator);
         return E_OUTOFMEMORY;
     }
 
+    list_init(&locator->elements);
+
     *ppsaxlocator = locator;
 
     TRACE("returning %p\n", *ppsaxlocator);
@@ -2915,7 +2914,7 @@ static HRESULT WINAPI saxxmlreader_parseURL(
     return internal_parseURL(This, url, TRUE);
 }
 
-static const struct IVBSAXXMLReaderVtbl saxreader_vtbl =
+static const struct IVBSAXXMLReaderVtbl VBSAXXMLReaderVtbl =
 {
     saxxmlreader_QueryInterface,
     saxxmlreader_AddRef,
@@ -3113,7 +3112,7 @@ static HRESULT WINAPI isaxxmlreader_parseURL(
     return internal_parseURL(This, url, FALSE);
 }
 
-static const struct ISAXXMLReaderVtbl isaxreader_vtbl =
+static const struct ISAXXMLReaderVtbl SAXXMLReaderVtbl =
 {
     isaxxmlreader_QueryInterface,
     isaxxmlreader_AddRef,
@@ -3149,18 +3148,18 @@ static dispex_static_data_t saxreader_dispex = {
     saxreader_iface_tids
 };
 
-HRESULT SAXXMLReader_create(MSXML_VERSION version, IUnknown *pUnkOuter, LPVOID *ppObj)
+HRESULT SAXXMLReader_create(MSXML_VERSION version, IUnknown *outer, LPVOID *ppObj)
 {
     saxreader *reader;
 
-    TRACE("(%p,%p)\n", pUnkOuter, ppObj);
+    TRACE("(%p, %p)\n", outer, ppObj);
 
     reader = heap_alloc( sizeof (*reader) );
     if( !reader )
         return E_OUTOFMEMORY;
 
-    reader->IVBSAXXMLReader_iface.lpVtbl = &saxreader_vtbl;
-    reader->ISAXXMLReader_iface.lpVtbl = &isaxreader_vtbl;
+    reader->IVBSAXXMLReader_iface.lpVtbl = &VBSAXXMLReaderVtbl;
+    reader->ISAXXMLReader_iface.lpVtbl = &SAXXMLReaderVtbl;
     reader->ref = 1;
     reader->contentHandler = NULL;
     reader->vbcontentHandler = NULL;
diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c
index df504c9..dd17dba 100644
--- a/dlls/msxml3/tests/saxreader.c
+++ b/dlls/msxml3/tests/saxreader.c
@@ -327,8 +327,8 @@ static HRESULT WINAPI contentHandler_putDocumentLocator(
         ISAXContentHandler* iface,
         ISAXLocator *pLocator)
 {
-    ISAXAttributes *attr;
-    HRESULT hres;
+    ISAXAttributes *attr, *attr1;
+    HRESULT hr;
 
     if(!test_expect_call(CH_PUTDOCUMENTLOCATOR))
         return E_FAIL;
@@ -338,9 +338,16 @@ static HRESULT WINAPI contentHandler_putDocumentLocator(
             msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
 
     if(msxml_version >= 6) {
-        hres = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
-        ok(hres == S_OK, "QueryInterface failed: %x\n", hres);
+        EXPECT_REF(pLocator, 1);
+        hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
+        EXPECT_HR(hr, S_OK);
+        EXPECT_REF(pLocator, 2);
+        hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1);
+        EXPECT_HR(hr, S_OK);
+        EXPECT_REF(pLocator, 3);
+        ok(attr == attr1, "got %p, %p\n", attr, attr1);
         ISAXAttributes_Release(attr);
+        ISAXAttributes_Release(attr1);
     }
 
     return (expectCall++)->ret;
-- 
1.5.6.5

