Commit 9d662928 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

msxml3: Implement element stack and use it in related callbacks.

parent 17f0ee46
......@@ -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;
......
......@@ -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;
......
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