From: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> --- dlls/msxml3/saxreader.c | 6783 +++++++++++++++++++++++---------- dlls/msxml3/tests/saxreader.c | 54 +- dlls/msxml3/tests/xmldoc.c | 1 - dlls/msxml6/tests/saxreader.c | 12 +- 4 files changed, 4748 insertions(+), 2102 deletions(-) diff --git a/dlls/msxml3/saxreader.c b/dlls/msxml3/saxreader.c index 75e44ca68a2..7846b512910 100644 --- a/dlls/msxml3/saxreader.c +++ b/dlls/msxml3/saxreader.c @@ -3,6 +3,7 @@ * * Copyright 2008 Alistair Leslie-Hughes * Copyright 2008 Piotr Caban + * Copyright 2025-2026 Nikolay Sivov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,10 +22,6 @@ #define COBJMACROS #include <stdarg.h> -#include <libxml/parser.h> -#include <libxml/xmlerror.h> -#include <libxml/SAX2.h> -#include <libxml/parserInternals.h> #include "windef.h" #include "winbase.h" @@ -36,6 +33,7 @@ #include "urlmon.h" #include "winreg.h" #include "shlwapi.h" +#include "winternl.h" #include "wine/debug.h" @@ -43,29 +41,284 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml); -typedef enum -{ - FeatureUnknown = 0, - ExhaustiveErrors = 1 << 1, - ExternalGeneralEntities = 1 << 2, - ExternalParameterEntities = 1 << 3, - ForcedResync = 1 << 4, - NamespacePrefixes = 1 << 5, - Namespaces = 1 << 6, - ParameterEntities = 1 << 7, - PreserveSystemIndentifiers = 1 << 8, - ProhibitDTD = 1 << 9, - SchemaValidation = 1 << 10, - ServerHttpRequest = 1 << 11, - SuppressValidationfatalError = 1 << 12, - UseInlineSchema = 1 << 13, - UseSchemaLocation = 1 << 14, - LexicalHandlerParEntities = 1 << 15 -} saxreader_feature; +struct stream_wrapper +{ + ISequentialStream ISequentialStream_iface; + LONG refcount; + + const BYTE *buffer; + DWORD size; + DWORD position; +}; + +static struct stream_wrapper *impl_from_ISequentialStream(ISequentialStream *iface) +{ + return CONTAINING_RECORD(iface, struct stream_wrapper, ISequentialStream_iface); +} + +static HRESULT WINAPI stream_wrapper_QueryInterface(ISequentialStream *iface, REFIID riid, void **out) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_ISequentialStream)) + { + *out = iface; + ISequentialStream_AddRef(iface); + return S_OK; + } + + *out = NULL; + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI stream_wrapper_AddRef(ISequentialStream *iface) +{ + struct stream_wrapper *stream = impl_from_ISequentialStream(iface); + ULONG refcount = InterlockedIncrement(&stream->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI stream_wrapper_Release(ISequentialStream *iface) +{ + struct stream_wrapper *stream = impl_from_ISequentialStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + free(stream); + + return refcount; +} + +static HRESULT WINAPI stream_wrapper_Read(ISequentialStream *iface, void *buff, ULONG buff_size, ULONG *read_len) +{ + struct stream_wrapper *stream = impl_from_ISequentialStream(iface); + DWORD size; + + TRACE("%p, %p, %lu, %p.\n", iface, buff, buff_size, read_len); + + if (stream->position >= stream->size) + { + if (read_len) + *read_len = 0; + return S_FALSE; + } + + size = stream->size - stream->position; + if (buff_size < size) + size = buff_size; + + memmove(buff, stream->buffer + stream->position, size); + stream->position += size; + + if (read_len) + *read_len = size; + + return S_OK; +} + +static HRESULT WINAPI stream_wrapper_Write(ISequentialStream *iface, const void *buff, ULONG buff_size, ULONG *written) +{ + TRACE("%p, %p, %lu, %p.\n", iface, buff, buff_size, written); + + return E_NOTIMPL; +} + +static const ISequentialStreamVtbl stream_wrapper_vtbl = +{ + stream_wrapper_QueryInterface, + stream_wrapper_AddRef, + stream_wrapper_Release, + stream_wrapper_Read, + stream_wrapper_Write, +}; + +static HRESULT stream_wrapper_create(const void *buffer, DWORD size, ISequentialStream **ret) +{ + struct stream_wrapper *object; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->ISequentialStream_iface.lpVtbl = &stream_wrapper_vtbl; + object->refcount = 1; + object->buffer = buffer; + object->size = size; + + *ret = &object->ISequentialStream_iface; + + return S_OK; +} + +enum error_codes +{ + E_SAX_UNDEFINEDREF = 0xc00ce002, + E_SAX_INFINITEREFLOOP = 0xc00ce003, + E_SAX_UNPARSEDENTITYREF = 0xc00ce006, + E_SAX_CONTAINSCOLON = 0xc00ce00c, + E_SAX_UNDECLAREDPREFIX = 0xc00ce01d, + + E_SAX_MISSINGEQUALS = 0xc00ce501, + E_SAX_MISSINGQUOTE = 0xc00ce502, + E_SAX_COMMENTSYNTAX = 0xc00ce503, + E_SAX_BADSTARTNAMECHAR = 0xc00ce504, + E_SAX_BADNAMECHAR = 0xc00ce505, + E_SAX_BADCHARINSTRING = 0xc00ce506, + E_SAX_MISSINGWHITESPACE = 0xc00ce509, + E_SAX_EXPECTINGTAGEND = 0xc00ce50a, + E_SAX_BADCHARINDTD = 0xc00ce50b, + E_SAX_MISSINGSEMICOLON = 0xc00ce50d, + E_SAX_BADCHARINENTREF = 0xc00ce50e, + E_SAX_BADCHARINMIXEDMODEL = 0xc00ce515, + E_SAX_MISSING_STAR = 0xc00ce516, + E_SAX_MISSING_PAREN = 0xc00ce518, + E_SAX_BADCHARINENUMERATION = 0xc00ce519, + E_SAX_PIDECLSYNTAX = 0xc00ce51a, + E_SAX_EXPECTINGCLOSEQUOTE = 0xc00ce51b, + E_SAX_MULTIPLE_COLONS = 0xc00ce51c, + E_SAX_INVALID_UNICODE = 0xc00ce51f, + E_SAX_WHITESPACEORQUESTIONMARK = 0xc00ce520, + E_SAX_UNEXPECTEDENDTAG = 0xc00ce552, + E_SAX_DUPLICATEATTRIBUTE = 0xc00ce554, + E_SAX_INVALIDATROOTLEVEL = 0xc00ce556, + E_SAX_BAD_XMLDECL = 0xc00ce557, + E_SAX_MISSINGROOT = 0xc00ce558, + E_SAX_UNEXPECTED_EOF = 0xc00ce559, + E_SAX_INVALID_CDATACLOSINGTAG = 0xc00ce55c, + E_SAX_UNCLOSEDPI = 0xc00ce55d, + E_SAX_UNCLOSEDENDTAG = 0xc00ce55f, + E_SAX_UNCLOSEDCDATA = 0xc00ce564, + E_SAX_BADDECLNAME = 0xc00ce565, + E_SAX_RESERVEDNAMESPACE = 0xc00ce568, + E_SAX_ENDTAGMISMATCH = 0xc00ce56d, + E_SAX_INVALIDENCODING = 0xc00ce56e, + E_SAX_INVALIDSWITCH = 0xc00ce56f, + E_SAX_INVALID_MODEL = 0xc00ce571, + E_SAX_INVALID_TYPE = 0xc00ce572, + E_SAX_BADXMLCASE = 0xc00ce576, + E_SAX_INVALID_STANDALONE = 0xc00ce579, + E_SAX_INVALID_VERSION = 0xc00ce57f, +}; + +enum attdef_type +{ + ATTDEF_TYPE_INVALID = 0, + ATTDEF_TYPE_CDATA, + ATTDEF_TYPE_ID, + ATTDEF_TYPE_IDREF, + ATTDEF_TYPE_IDREFS, + ATTDEF_TYPE_ENTITY, + ATTDEF_TYPE_ENTITIES, + ATTDEF_TYPE_NMTOKEN, + ATTDEF_TYPE_NMTOKENS, + ATTDEF_TYPE_NOTATION, + ATTDEF_TYPE_ENUMERATION, +}; + +enum attdefault_value_type +{ + ATTDEFDECL_NONE = 0, + ATTDEFDECL_REQUIRED, + ATTDEFDECL_IMPLIED, + ATTDEFDECL_FIXED, +}; + +struct attribute +{ + BSTR uri; + BSTR local; + BSTR qname; + BSTR value; + BSTR prefix; + bool nsdef; +}; + +struct name +{ + BSTR prefix; + BSTR local; + BSTR qname; +}; + +struct attlist_attr +{ + struct name name; + BSTR type; + BSTR valuetype; + BSTR value; +}; + +struct attlist_decl +{ + struct list entry; + BSTR name; + struct attlist_attr *attributes; + size_t count; + size_t capacity; +}; + +struct entity_part +{ + BSTR value; + bool reference; +}; + +struct text_position +{ + int line; + int column; +}; + +struct entity_decl +{ + struct list entry; + BSTR name; + BSTR sysid; + BSTR value; + struct + { + struct entity_part *parts; + size_t count; + size_t capacity; + } content; + bool unparsed; + + struct list input_entry; + bool visited; + size_t remaining; + struct text_position position; +}; + +enum saxreader_feature +{ + FeatureUnknown = 0x00000000, + ExhaustiveErrors = 0x00000001, + ExternalGeneralEntities = 0x00000002, + ExternalParameterEntities = 0x00000004, + ForcedResync = 0x00000008, + NamespacePrefixes = 0x00000010, + Namespaces = 0x00000020, + ParameterEntities = 0x00000040, + PreserveSystemIndentifiers = 0x00000080, + ProhibitDTD = 0x00000100, + SchemaValidation = 0x00000200, + ServerHttpRequest = 0x00000400, + SuppressValidationfatalError = 0x00000800, + UseInlineSchema = 0x00001000, + UseSchemaLocation = 0x00002000, + LexicalHandlerParEntities = 0x00004000, + FeatureForceDWord = 0xffffffff, +}; struct saxreader_feature_pair { - saxreader_feature feature; + enum saxreader_feature feature; const WCHAR *name; }; @@ -80,7 +333,7 @@ static const struct saxreader_feature_pair saxreader_feature_map[] = { { SchemaValidation, L"schema-validation" }, }; -static saxreader_feature get_saxreader_feature(const WCHAR *name) +static enum saxreader_feature get_saxreader_feature(const WCHAR *name) { int min, max, n, c; @@ -106,13 +359,6 @@ static saxreader_feature get_saxreader_feature(const WCHAR *name) static const WCHAR empty_str; -struct bstrpool -{ - BSTR *pool; - unsigned int index; - unsigned int len; -}; - typedef struct { BSTR prefix; @@ -164,6 +410,18 @@ struct saxlexicalhandler_iface IVBSAXLexicalHandler *vbhandler; }; +struct saxdtdhandler_iface +{ + ISAXDTDHandler *handler; + IVBSAXDTDHandler *vbhandler; +}; + +struct saxdeclhandler_iface +{ + ISAXDeclHandler *handler; + IVBSAXDeclHandler *vbhandler; +}; + struct saxentityresolver_iface { ISAXEntityResolver *handler; @@ -172,36 +430,39 @@ struct saxentityresolver_iface struct saxhandler_iface { - union { + union + { struct saxcontenthandler_iface content; struct saxentityresolver_iface entityresolver; struct saxerrorhandler_iface error; struct saxlexicalhandler_iface lexical; + struct saxdtdhandler_iface dtd; + struct saxdeclhandler_iface decl; struct saxanyhandler_iface anyhandler; } u; }; -typedef struct +struct saxreader { DispatchEx dispex; IVBSAXXMLReader IVBSAXXMLReader_iface; ISAXXMLReader ISAXXMLReader_iface; - LONG ref; + LONG refcount; struct saxhandler_iface saxhandlers[SAXHandler_Last]; - xmlSAXHandler sax; BOOL isParsing; - struct bstrpool pool; - saxreader_feature features; + enum saxreader_feature features; BSTR xmldecl_version; + BSTR xmldecl_standalone; + BSTR xmldecl_encoding; BSTR empty_bstr; MSXML_VERSION version; -} saxreader; +}; -static HRESULT saxreader_put_handler(saxreader *reader, enum saxhandler_type type, void *ptr, BOOL vb) +static HRESULT saxreader_put_handler(struct saxreader *reader, enum saxhandler_type type, void *ptr, bool vb) { struct saxanyhandler_iface *iface = &reader->saxhandlers[type].u.anyhandler; - IUnknown *unk = (IUnknown*)ptr; + IUnknown *unk = (IUnknown *)ptr; if (unk) IUnknown_AddRef(unk); @@ -217,7 +478,7 @@ static HRESULT saxreader_put_handler(saxreader *reader, enum saxhandler_type typ return S_OK; } -static HRESULT saxreader_get_handler(const saxreader *reader, enum saxhandler_type type, BOOL vb, void **ret) +static HRESULT saxreader_get_handler(const struct saxreader *reader, enum saxhandler_type type, bool vb, void **ret) { const struct saxanyhandler_iface *iface = &reader->saxhandlers[type].u.anyhandler; @@ -236,452 +497,522 @@ static HRESULT saxreader_get_handler(const saxreader *reader, enum saxhandler_ty return S_OK; } -static struct saxcontenthandler_iface *saxreader_get_contenthandler(saxreader *reader) +static struct saxcontenthandler_iface *saxreader_get_contenthandler(struct saxreader *reader) { return &reader->saxhandlers[SAXContentHandler].u.content; } -static struct saxerrorhandler_iface *saxreader_get_errorhandler(saxreader *reader) +static struct saxerrorhandler_iface *saxreader_get_errorhandler(struct saxreader *reader) { return &reader->saxhandlers[SAXErrorHandler].u.error; } -static struct saxlexicalhandler_iface *saxreader_get_lexicalhandler(saxreader *reader) +static struct saxlexicalhandler_iface *saxreader_get_lexicalhandler(struct saxreader *reader) { return &reader->saxhandlers[SAXLexicalHandler].u.lexical; } -typedef struct -{ - IVBSAXLocator IVBSAXLocator_iface; - ISAXLocator ISAXLocator_iface; - IVBSAXAttributes IVBSAXAttributes_iface; - ISAXAttributes ISAXAttributes_iface; - LONG ref; - saxreader *saxreader; - HRESULT ret; - xmlParserCtxtPtr pParserCtxt; - BSTR publicId; - BSTR systemId; - int line; - int column; - BOOL vbInterface; - struct list elements; - - BSTR namespaceUri; - int attr_alloc_count; - int attr_count; - struct _attributes - { - BSTR szLocalname; - BSTR szURI; - BSTR szValue; - BSTR szQName; - } *attributes; -} saxlocator; - -static inline saxreader *impl_from_IVBSAXXMLReader( IVBSAXXMLReader *iface ) +static struct saxdtdhandler_iface *saxreader_get_dtdhandler(struct saxreader *reader) { - return CONTAINING_RECORD(iface, saxreader, IVBSAXXMLReader_iface); + return &reader->saxhandlers[SAXDTDHandler].u.dtd; } -static inline saxreader *impl_from_ISAXXMLReader( ISAXXMLReader *iface ) +static struct saxdeclhandler_iface *saxreader_get_declhandler(struct saxreader *reader) { - return CONTAINING_RECORD(iface, saxreader, ISAXXMLReader_iface); + return &reader->saxhandlers[SAXDeclHandler].u.decl; } -static inline saxlocator *impl_from_IVBSAXLocator( IVBSAXLocator *iface ) +struct encoded_buffer { - return CONTAINING_RECORD(iface, saxlocator, IVBSAXLocator_iface); -} + char *data; + size_t cur; + size_t allocated; + size_t written; +}; -static inline saxlocator *impl_from_ISAXLocator( ISAXLocator *iface ) +static void encoded_buffer_cleanup(struct encoded_buffer *buffer) { - return CONTAINING_RECORD(iface, saxlocator, ISAXLocator_iface); + free(buffer->data); + memset(buffer, 0, sizeof(*buffer)); } -static inline saxlocator *impl_from_IVBSAXAttributes( IVBSAXAttributes *iface ) +enum xmlencoding { - return CONTAINING_RECORD(iface, saxlocator, IVBSAXAttributes_iface); -} + XML_ENCODING_UNKNOWN = 0, + XML_ENCODING_UTF16LE, + XML_ENCODING_UTF16BE, + XML_ENCODING_UCS4BE, + XML_ENCODING_UCS4LE, + XML_ENCODING_UTF8, + XML_ENCODING_LAST = XML_ENCODING_UTF8, + XML_ENCODING_FORCE_DWORD = 0xffffffff, +}; -static inline saxlocator *impl_from_ISAXAttributes( ISAXAttributes *iface ) +static const char *saxreader_get_encoding_name(enum xmlencoding encoding) { - return CONTAINING_RECORD(iface, saxlocator, ISAXAttributes_iface); + static const char *names[] = + { + [XML_ENCODING_UNKNOWN] = "unknown", + [XML_ENCODING_UTF16LE] = "utf16le", + [XML_ENCODING_UTF16BE] = "utf16be", + [XML_ENCODING_UCS4BE] = "ucs4be", + [XML_ENCODING_UCS4LE] = "ucs4le", + [XML_ENCODING_UTF8] = "utf8", + }; + if (encoding > XML_ENCODING_LAST) return "<out-of-bounds>"; + return names[encoding]; } -static inline BOOL saxreader_has_handler(const saxlocator *locator, enum saxhandler_type type) +static bool saxreader_get_encoding_codepage(const WCHAR *name, UINT *codepage) { - struct saxanyhandler_iface *iface = &locator->saxreader->saxhandlers[type].u.anyhandler; - return (locator->vbInterface && iface->vbhandler) || (!locator->vbInterface && iface->handler); + static const struct + { + const WCHAR *name; + UINT codepage; + } + encodings[] = + { + { L"gbk", 936 }, + { L"gb2312", 936 }, + { L"us-ascii", 20127 }, + { L"iso8859-1", 28591 }, + { L"iso-8859-1", 28591 }, + { L"iso-8859-2", 28592 }, + { L"iso-8859-3", 28593 }, + { L"iso-8859-4", 28594 }, + { L"iso-8859-5", 28595 }, + { L"iso-8859-6", 28596 }, + { L"iso-8859-7", 28597 }, + { L"iso-8859-8", 28598 }, + { L"iso-8859-9", 28599 }, + { L"windows-1250", 1250 }, + { L"windows-1251", 1251 }, + { L"windows-1252", 1252 }, + { L"windows-1253", 1253 }, + { L"windows-1254", 1254 }, + { L"windows-1255", 1255 }, + { L"windows-1256", 1256 }, + { L"windows-1257", 1257 }, + { L"windows-1258", 1258 }, + }; + + for (int i = 0; i < ARRAYSIZE(encodings); ++i) + { + if (!wcsicmp(name, encodings[i].name)) + { + *codepage = encodings[i].codepage; + return true; + } + } + + return false; } -static HRESULT saxreader_saxcharacters(saxlocator *locator, BSTR chars) +static bool saxreader_can_ignore_encoding(const WCHAR *encoding) { - struct saxcontenthandler_iface *content = saxreader_get_contenthandler(locator->saxreader); - HRESULT hr; - - if (!saxreader_has_handler(locator, SAXContentHandler)) return S_OK; + static const WCHAR *encodings[] = + { + L"utf-16", L"utf-8" + }; - if (locator->vbInterface) - hr = IVBSAXContentHandler_characters(content->vbhandler, &chars); - else - hr = ISAXContentHandler_characters(content->handler, chars, SysStringLen(chars)); + for (int i = 0; i < ARRAYSIZE(encodings); ++i) + { + if (!wcsicmp(encoding, encodings[i])) + return true; + } - return hr; + return false; } -/* property names */ -static const WCHAR PropertyDeclHandlerW[] = L"http://xml.org/sax/properties/declaration-handler"; -static const WCHAR PropertyDomNodeW[] = L"http://xml.org/sax/properties/dom-node"; -static const WCHAR PropertyLexicalHandlerW[] = L"http://xml.org/sax/properties/lexical-handler"; +typedef int (*p_converter)(UINT cp, const char *src, int src_size, WCHAR *buffer, int buffer_length); -static inline HRESULT set_feature_value(saxreader *reader, saxreader_feature feature, VARIANT_BOOL value) +static int convert_mbtowc(UINT cp, const char *src, int src_size, WCHAR *buffer, int buffer_length) { - /* handling of non-VARIANT_* values is version dependent */ - if ((reader->version < MSXML4) && (value != VARIANT_TRUE)) - value = VARIANT_FALSE; - if ((reader->version >= MSXML4) && (value != VARIANT_FALSE)) - value = VARIANT_TRUE; - - if (value == VARIANT_TRUE) - reader->features |= feature; - else - reader->features &= ~feature; - - return S_OK; + return MultiByteToWideChar(cp, 0, src, src_size, buffer, buffer_length); } -static inline HRESULT get_feature_value(const saxreader *reader, saxreader_feature feature, VARIANT_BOOL *value) +static int convert_utf16be(UINT cp, const char *src, int src_size, WCHAR *buffer, int buffer_length) { - *value = reader->features & feature ? VARIANT_TRUE : VARIANT_FALSE; - return S_OK; -} + size_t size = min(src_size / 2, buffer_length); -static BOOL is_namespaces_enabled(const saxreader *reader) -{ - return (reader->version < MSXML4) || (reader->features & Namespaces); + if (!buffer) return src_size / 2; + + for (int i = 0; i < size; ++i) + buffer[i] = src[i + 1] | src[i]; + + return size; } -static BSTR build_qname(BSTR prefix, BSTR local) +static unsigned int saxreader_convert_u32_to_u16(UINT32 ch, WCHAR *out) { - if (prefix && *prefix) + if (ch < 0x10000) { - BSTR qname = SysAllocStringLen(NULL, SysStringLen(prefix) + SysStringLen(local) + 1); - WCHAR *ptr; - - ptr = qname; - lstrcpyW(ptr, prefix); - ptr += SysStringLen(prefix); - *ptr++ = ':'; - lstrcpyW(ptr, local); - return qname; + out[0] = ch; + out[1] = 0; + out[2] = 0; + return 1; } else - return SysAllocString(local); + { + out[0] = ((ch - 0x10000) >> 10) + 0xd800; + out[1] = ((ch - 0x10000) & 0x3ff) + 0xdc00; + out[2] = 0; + return 2; + } } -static element_entry* alloc_element_entry(const xmlChar *local, const xmlChar *prefix, int nb_ns, - const xmlChar **namespaces) +static int convert_ucs4le(UINT cp, const char *src, int src_size, WCHAR *buffer, int buffer_length) { - element_entry *ret; - int i; + const UINT32 *u = (const UINT32 *)src; + int size = 0, len; + WCHAR *p = buffer; - ret = malloc(sizeof(*ret)); - if (!ret) return ret; + if (src_size % 4) return 0; - ret->local = bstr_from_xmlChar(local); - ret->prefix = bstr_from_xmlChar(prefix); - ret->qname = build_qname(ret->prefix, ret->local); - ret->ns = nb_ns ? malloc(nb_ns * sizeof(ns)) : NULL; - ret->ns_count = nb_ns; - - for (i=0; i < nb_ns; i++) + if (!buffer) { - ret->ns[i].prefix = bstr_from_xmlChar(namespaces[2*i]); - ret->ns[i].uri = bstr_from_xmlChar(namespaces[2*i+1]); - } - - return ret; -} + for (int i = 0; i < src_size / 4; ++i) + { + ++size; + if (u[i] > 0xffff) ++size; + } -static void free_element_entry(element_entry *element) -{ - int i; + return size; + } - for (i=0; i<element->ns_count;i++) + while (buffer_length && src_size) { - SysFreeString(element->ns[i].prefix); - SysFreeString(element->ns[i].uri); + if (*u > 0xffff && buffer_length < 2) break; + len = saxreader_convert_u32_to_u16(*u, buffer); + buffer_length -= len; + buffer += len; + ++u; } - SysFreeString(element->prefix); - SysFreeString(element->local); - SysFreeString(element->qname); - - free(element->ns); - free(element); -} - -static void push_element_ns(saxlocator *locator, element_entry *element) -{ - list_add_head(&locator->elements, &element->entry); + return buffer - p; } -static element_entry * pop_element_ns(saxlocator *locator) +static int convert_ucs4be(UINT cp, const char *src, int src_size, WCHAR *buffer, int buffer_length) { - element_entry *element = LIST_ENTRY(list_head(&locator->elements), element_entry, entry); + const UINT32 *u = (const UINT32 *)src; + int size = 0, len; + WCHAR *p = buffer; + UINT32 _u; - if (element) - list_remove(&element->entry); + if (src_size % 4) return 0; - return element; -} + if (!buffer) + { + for (int i = 0; i < src_size / 4; ++i) + { + ++size; + if (u[i] & 0xffff) ++size; + } -static BSTR find_element_uri(saxlocator *locator, const xmlChar *uri) -{ - element_entry *element; - BSTR uriW; - int i; + return size; + } - if (!uri) return NULL; + while (buffer_length && src_size) + { + _u = RtlUlongByteSwap(*u); + if (_u > 0xffff && buffer_length < 2) break; + len = saxreader_convert_u32_to_u16(_u, buffer); + buffer_length -= len; + buffer += len; + ++u; + } - uriW = bstr_from_xmlChar(uri); + return buffer - p; +} - LIST_FOR_EACH_ENTRY(element, &locator->elements, element_entry, entry) +static p_converter convert_get_converter(enum xmlencoding encoding) +{ + switch (encoding) { - for (i=0; i < element->ns_count; i++) - if (!wcscmp(uriW, element->ns[i].uri)) - { - SysFreeString(uriW); - return element->ns[i].uri; - } + case XML_ENCODING_UCS4BE: + return convert_ucs4be; + case XML_ENCODING_UCS4LE: + return convert_ucs4le; + case XML_ENCODING_UTF16BE: + return convert_utf16be; + case XML_ENCODING_UTF8: + return convert_mbtowc; + case XML_ENCODING_UTF16LE: + default: + ; } - 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) +static UINT convert_get_codepage(enum xmlencoding encoding) { - return This->saxreader->version >= MSXML4 ? FAILED(hr) : hr != S_OK; + switch (encoding) + { + case XML_ENCODING_UTF16LE: + return 1200; + case XML_ENCODING_UTF8: + return CP_UTF8; + default: + ; + } + + return 0; } -/* 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) +/* Get a rough estimate on raw byte size, to produce output of 'size' WCHARs. + Estimate could off in either direction, it should never be an issue if requested + chunk size is always larger than reasonable lookahead window used to detect next markup pattern. */ +static ULONG convert_estimate_raw_size(enum xmlencoding encoding, ULONG size) { - if (This->saxreader->version >= MSXML4) - { - if (*i == -1) *i = 0; else ++*i; - return *i < element->ns_count; - } - else + switch (encoding) { - if (*i == -1) *i = element->ns_count-1; else --*i; - return *i >= 0; + case XML_ENCODING_UTF16LE: + case XML_ENCODING_UTF16BE: + return size * 2; + case XML_ENCODING_UTF8: + return size * 3; + case XML_ENCODING_UCS4BE: + case XML_ENCODING_UCS4LE: + return size * 4; + default: + return 0; } } -static BOOL bstr_pool_insert(struct bstrpool *pool, BSTR pool_entry) +struct input_buffer { - if (!pool->pool) - { - pool->pool = malloc(16 * sizeof(*pool->pool)); - if (!pool->pool) - return FALSE; + struct encoded_buffer utf16; + struct encoded_buffer raw; + enum xmlencoding encoding; + bool switched_encoding; + p_converter converter; + UINT code_page; + struct text_position position; + size_t consumed; + bool last_cr; - pool->index = 0; - pool->len = 16; - } - else if (pool->index == pool->len) - { - BSTR *new_pool = realloc(pool->pool, pool->len * 2 * sizeof(*new_pool)); + unsigned int chunk_size; + struct list entities; +}; - if (!new_pool) - return FALSE; +static size_t convert_get_raw_length(struct input_buffer *buffer) +{ + const struct encoded_buffer *raw = &buffer->raw; + size_t size = raw->written; - pool->pool = new_pool; - pool->len *= 2; + if (buffer->encoding == XML_ENCODING_UTF8 && buffer->code_page == CP_UTF8) + { + /* Incomplete single byte char, look for a start byte of multibyte char. */ + if (raw->data[size-1] & 0x80) + { + while (--size && !(raw->data[size] & 0xc0)) + ; + } } - pool->pool[pool->index++] = pool_entry; - return TRUE; + return size - raw->cur; } -static void free_bstr_pool(struct bstrpool *pool) +enum saxreader_state { - unsigned int i; - - for (i = 0; i < pool->index; i++) - SysFreeString(pool->pool[i]); + SAX_PARSER_START = 0, + SAX_PARSER_MISC, + SAX_PARSER_PI, + SAX_PARSER_COMMENT, + SAX_PARSER_START_TAG, + SAX_PARSER_CONTENT, + SAX_PARSER_CDATA, + SAX_PARSER_END_TAG, + SAX_PARSER_EPILOG, + SAX_PARSER_XML_DECL, + SAX_PARSER_EOF, +}; - free(pool->pool); +struct saxlocator +{ + IVBSAXLocator IVBSAXLocator_iface; + ISAXLocator ISAXLocator_iface; + IVBSAXAttributes IVBSAXAttributes_iface; + ISAXAttributes ISAXAttributes_iface; + LONG refcount; + struct saxreader *saxreader; + HRESULT ret; + int line; + int column; + bool vbInterface; + struct list elements; + enum saxreader_state state; - pool->pool = NULL; - pool->index = pool->len = 0; -} + ISequentialStream *stream; + bool eos; -static BSTR bstr_from_xmlCharN(const xmlChar *buf, int len) -{ - DWORD dLen; - BSTR bstr; + BSTR xmlns_uri; + BSTR xml_uri; + BSTR null_uri; + struct + { + struct attribute *entries; + size_t count; + size_t capacity; + size_t *map; + } attributes; - if (!buf) - return NULL; + struct + { + struct list attr_decls; + struct list entities; + } dtd; - dLen = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, NULL, 0); - if(len != -1) dLen++; - bstr = SysAllocStringLen(NULL, dLen-1); - if (!bstr) - return NULL; - MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, bstr, dLen); - if(len != -1) bstr[dLen-1] = '\0'; + struct input_buffer buffer; + struct text_position start_document_position; + HRESULT status; +}; - return bstr; +static inline struct saxreader *impl_from_IVBSAXXMLReader(IVBSAXXMLReader *iface) +{ + return CONTAINING_RECORD(iface, struct saxreader, IVBSAXXMLReader_iface); } -static BSTR QName_from_xmlChar(const xmlChar *prefix, const xmlChar *name) +static inline struct saxreader *impl_from_ISAXXMLReader(ISAXXMLReader *iface) { - xmlChar *qname; - BSTR bstr; - - if(!name) return NULL; - - if(!prefix || !*prefix) - return bstr_from_xmlChar(name); + return CONTAINING_RECORD(iface, struct saxreader, ISAXXMLReader_iface); +} - qname = xmlBuildQName(name, prefix, NULL, 0); - bstr = bstr_from_xmlChar(qname); - xmlFree(qname); +static inline struct saxlocator *impl_from_IVBSAXLocator(IVBSAXLocator *iface) +{ + return CONTAINING_RECORD(iface, struct saxlocator, IVBSAXLocator_iface); +} - return bstr; +static inline struct saxlocator *impl_from_ISAXLocator(ISAXLocator *iface) +{ + return CONTAINING_RECORD(iface, struct saxlocator, ISAXLocator_iface); } -static BSTR pooled_bstr_from_xmlChar(struct bstrpool *pool, const xmlChar *buf) +static inline struct saxlocator *impl_from_IVBSAXAttributes(IVBSAXAttributes *iface) { - BSTR pool_entry = bstr_from_xmlChar(buf); + return CONTAINING_RECORD(iface, struct saxlocator, IVBSAXAttributes_iface); +} - if (pool_entry && !bstr_pool_insert(pool, pool_entry)) - { - SysFreeString(pool_entry); - return NULL; - } +static inline struct saxlocator *impl_from_ISAXAttributes(ISAXAttributes *iface) +{ + return CONTAINING_RECORD(iface, struct saxlocator, ISAXAttributes_iface); +} - return pool_entry; +static inline bool saxreader_has_handler(const struct saxlocator *locator, enum saxhandler_type type) +{ + struct saxanyhandler_iface *iface = &locator->saxreader->saxhandlers[type].u.anyhandler; + return (locator->vbInterface && iface->vbhandler) || (!locator->vbInterface && iface->handler); } -static BSTR pooled_bstr_from_xmlCharN(struct bstrpool *pool, const xmlChar *buf, int len) +static inline HRESULT set_feature_value(struct saxreader *reader, enum saxreader_feature feature, VARIANT_BOOL value) { - BSTR pool_entry = bstr_from_xmlCharN(buf, len); + /* handling of non-VARIANT_* values is version dependent */ + if ((reader->version < MSXML4) && (value != VARIANT_TRUE)) + value = VARIANT_FALSE; + if ((reader->version >= MSXML4) && (value != VARIANT_FALSE)) + value = VARIANT_TRUE; - if (pool_entry && !bstr_pool_insert(pool, pool_entry)) - { - SysFreeString(pool_entry); - return NULL; - } + if (value == VARIANT_TRUE) + reader->features |= feature; + else + reader->features &= ~feature; - return pool_entry; + return S_OK; } -static void format_error_message_from_id(saxlocator *This, HRESULT hr) +static inline HRESULT get_feature_value(const struct saxreader *reader, enum saxreader_feature feature, VARIANT_BOOL *value) { - struct saxerrorhandler_iface *handler = saxreader_get_errorhandler(This->saxreader); - xmlStopParser(This->pParserCtxt); - This->ret = hr; + *value = reader->features & feature ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; +} - if (saxreader_has_handler(This, SAXErrorHandler)) - { - WCHAR msg[1024]; - if(!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, - NULL, hr, 0, msg, ARRAY_SIZE(msg), NULL)) - { - FIXME("MSXML errors not yet supported.\n"); - msg[0] = '\0'; - } +static void saxreader_set_error(struct saxlocator *locator, HRESULT status) +{ + if (locator->status == S_OK) + locator->status = status; +} - if(This->vbInterface) - { - BSTR bstrMsg = SysAllocString(msg); - IVBSAXErrorHandler_fatalError(handler->vbhandler, - &This->IVBSAXLocator_iface, &bstrMsg, hr); - SysFreeString(bstrMsg); - } - else - ISAXErrorHandler_fatalError(handler->handler, - &This->ISAXLocator_iface, msg, hr); - } +static BSTR saxreader_alloc_string(struct saxlocator *locator, const WCHAR *str) +{ + BSTR ret; + + if (!(ret = SysAllocString(str))) + saxreader_set_error(locator, E_OUTOFMEMORY); + + return ret; } -static void update_position(saxlocator *This, BOOL fix_column) +static BSTR saxreader_alloc_stringlen(struct saxlocator *locator, const WCHAR *str, UINT len) { - const xmlChar *p = This->pParserCtxt->input->cur-1; - const xmlChar *baseP = This->pParserCtxt->input->base; + BSTR ret; - This->line = xmlSAX2GetLineNumber(This->pParserCtxt); - if(fix_column) - { - This->column = 1; - for(;p>=baseP && *p!='\n' && *p!='\r'; p--) - This->column++; - } - else + if (!(ret = SysAllocStringLen(str, len))) + saxreader_set_error(locator, E_OUTOFMEMORY); + + return ret; +} + +static bool is_namespaces_enabled(const struct saxreader *reader) +{ + return (reader->version < MSXML4) || (reader->features & Namespaces); +} + +static void free_element_entry(element_entry *element) +{ + int i; + + for (i=0; i<element->ns_count;i++) { - This->column = xmlSAX2GetColumnNumber(This->pParserCtxt); + SysFreeString(element->ns[i].prefix); + SysFreeString(element->ns[i].uri); } + + SysFreeString(element->prefix); + SysFreeString(element->local); + SysFreeString(element->qname); + + free(element->ns); + free(element); } -/*** IVBSAXAttributes interface ***/ -static HRESULT WINAPI ivbsaxattributes_QueryInterface( - IVBSAXAttributes* iface, - REFIID riid, - void **ppvObject) +static HRESULT WINAPI ivbsaxattributes_QueryInterface(IVBSAXAttributes *iface, REFIID riid, void **obj) { - saxlocator *This = impl_from_IVBSAXAttributes(iface); - TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject); - return IVBSAXLocator_QueryInterface(&This->IVBSAXLocator_iface, riid, ppvObject); + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + return IVBSAXLocator_QueryInterface(&locator->IVBSAXLocator_iface, riid, obj); } static ULONG WINAPI ivbsaxattributes_AddRef(IVBSAXAttributes* iface) { - saxlocator *This = impl_from_IVBSAXAttributes(iface); - return IVBSAXLocator_AddRef(&This->IVBSAXLocator_iface); + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + return IVBSAXLocator_AddRef(&locator->IVBSAXLocator_iface); } static ULONG WINAPI ivbsaxattributes_Release(IVBSAXAttributes* iface) { - saxlocator *This = impl_from_IVBSAXAttributes(iface); - return IVBSAXLocator_Release(&This->IVBSAXLocator_iface); + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + return IVBSAXLocator_Release(&locator->IVBSAXLocator_iface); } -static HRESULT WINAPI ivbsaxattributes_GetTypeInfoCount( IVBSAXAttributes *iface, UINT* pctinfo ) +static HRESULT WINAPI ivbsaxattributes_GetTypeInfoCount(IVBSAXAttributes *iface, UINT *count) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - - TRACE("(%p)->(%p)\n", This, pctinfo); + TRACE("%p, %p.\n", iface, count); - *pctinfo = 1; + *count = 1; return S_OK; } -static HRESULT WINAPI ivbsaxattributes_GetTypeInfo( - IVBSAXAttributes *iface, - UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo ) +static HRESULT WINAPI ivbsaxattributes_GetTypeInfo(IVBSAXAttributes *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) { TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo); return get_typeinfo(IVBSAXAttributes_tid, ppTInfo); } -static HRESULT WINAPI ivbsaxattributes_GetIDsOfNames( - IVBSAXAttributes *iface, - REFIID riid, - LPOLESTR* rgszNames, - UINT cNames, - LCID lcid, - DISPID* rgDispId) +static HRESULT WINAPI ivbsaxattributes_GetIDsOfNames(IVBSAXAttributes *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { ITypeInfo *typeinfo; HRESULT hr; @@ -702,274 +1033,252 @@ static HRESULT WINAPI ivbsaxattributes_GetIDsOfNames( return hr; } -static HRESULT WINAPI ivbsaxattributes_Invoke( - IVBSAXAttributes *iface, - DISPID dispIdMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS* pDispParams, - VARIANT* pVarResult, - EXCEPINFO* pExcepInfo, - UINT* puArgErr) +static HRESULT WINAPI ivbsaxattributes_Invoke(IVBSAXAttributes *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD flags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *ei, UINT *arg_err) { ITypeInfo *typeinfo; HRESULT hr; TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid), - lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + lcid, flags, pDispParams, pVarResult, ei, arg_err); hr = get_typeinfo(IVBSAXAttributes_tid, &typeinfo); - if(SUCCEEDED(hr)) + if (SUCCEEDED(hr)) { - hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, flags, pDispParams, pVarResult, ei, arg_err); ITypeInfo_Release(typeinfo); } return hr; } -/*** IVBSAXAttributes methods ***/ -static HRESULT WINAPI ivbsaxattributes_get_length( - IVBSAXAttributes* iface, - int *nLength) +static HRESULT WINAPI ivbsaxattributes_get_length(IVBSAXAttributes *iface, int *length) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - return ISAXAttributes_getLength(&This->ISAXAttributes_iface, nLength); + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + + TRACE("%p, %p.\n", iface, length); + + *length = locator->attributes.count; + + return S_OK; } -static HRESULT WINAPI ivbsaxattributes_getURI( - IVBSAXAttributes* iface, - int nIndex, - BSTR *uri) +static const struct attribute *saxlocator_get_attribute(const struct saxlocator *locator, int index) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - const WCHAR *uriW; - HRESULT hr; - int len; + if (index >= locator->attributes.count || index < 0) return NULL; + if (locator->attributes.map) + return &locator->attributes.entries[locator->attributes.map[index]]; + return &locator->attributes.entries[index]; +} + +static const struct attribute *saxlocator_get_attribute_by_name(const struct saxlocator *locator, + const WCHAR *uri, int uri_length, const WCHAR *local, int local_length, int *index) +{ + const struct attribute *attr; + + for (int i = 0; i < locator->attributes.count; ++i) + { + attr = saxlocator_get_attribute(locator, i); + + if (uri_length != SysStringLen(attr->uri) || local_length != SysStringLen(attr->local)) + continue; + + if (uri_length && memcmp(uri, attr->uri, sizeof(WCHAR) * uri_length)) + continue; + + if (local_length && memcmp(local, attr->local, sizeof(WCHAR) * local_length)) + continue; + + *index = i; + return attr; + } + + return NULL; +} + +static const struct attribute *saxlocator_get_attribute_by_qname(const struct saxlocator *locator, const WCHAR *name, + int length, int *index) +{ + const struct attribute *attr; + + for (int i = 0; i < locator->attributes.count; ++i) + { + attr = saxlocator_get_attribute(locator, i); + + if (length != SysStringLen(attr->qname)) continue; + if (memcmp(name, attr->qname, sizeof(WCHAR) * length)) continue; + + *index = i; + return attr; + } + + return NULL; +} - TRACE("(%p)->(%d %p)\n", This, nIndex, uri); + +static HRESULT WINAPI ivbsaxattributes_getURI(IVBSAXAttributes *iface, int index, BSTR *uri) +{ + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + const struct attribute *attr; + + TRACE("%p, %d, %p.\n", iface, index, uri); if (!uri) return E_POINTER; *uri = NULL; - hr = ISAXAttributes_getURI(&This->ISAXAttributes_iface, nIndex, &uriW, &len); - if (FAILED(hr)) - return hr; - return return_bstrn(uriW, len, uri); + if (!(attr = saxlocator_get_attribute(locator, index))) + return E_INVALIDARG; + + return return_bstrn(attr->uri, SysStringLen(attr->uri), uri); } -static HRESULT WINAPI ivbsaxattributes_getLocalName( - IVBSAXAttributes* iface, - int nIndex, - BSTR *name) +static HRESULT WINAPI ivbsaxattributes_getLocalName(IVBSAXAttributes *iface, int index, BSTR *name) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - const WCHAR *nameW; - HRESULT hr; - int len; + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + const struct attribute *attr; - TRACE("(%p)->(%d %p)\n", This, nIndex, name); + TRACE("%p, %d, %p.\n", iface, index, name); if (!name) return E_POINTER; *name = NULL; - hr = ISAXAttributes_getLocalName(&This->ISAXAttributes_iface, nIndex, &nameW, &len); - if (FAILED(hr)) - return hr; - return return_bstrn(nameW, len, name); + if (!(attr = saxlocator_get_attribute(locator, index))) + return E_INVALIDARG; + + return return_bstrn(attr->local, SysStringLen(attr->local), name); } -static HRESULT WINAPI ivbsaxattributes_getQName( - IVBSAXAttributes* iface, - int nIndex, - BSTR *QName) +static HRESULT WINAPI ivbsaxattributes_getQName(IVBSAXAttributes *iface, int index, BSTR *name) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - const WCHAR *nameW; - HRESULT hr; - int len; + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + const struct attribute *attr; - TRACE("(%p)->(%d %p)\n", This, nIndex, QName); + TRACE("%p, %d, %p.\n", iface, index, name); - if (!QName) + if (!name) return E_POINTER; - *QName = NULL; - hr = ISAXAttributes_getQName(&This->ISAXAttributes_iface, nIndex, &nameW, &len); - if (FAILED(hr)) - return hr; + *name = NULL; + + if (!(attr = saxlocator_get_attribute(locator, index))) + return E_INVALIDARG; - return return_bstrn(nameW, len, QName); + return return_bstrn(attr->qname, SysStringLen(attr->qname), name); } -static HRESULT WINAPI ivbsaxattributes_getIndexFromName( - IVBSAXAttributes* iface, - BSTR uri, - BSTR localName, - int *index) +static HRESULT WINAPI ivbsaxattributes_getIndexFromName(IVBSAXAttributes *iface, BSTR uri, + BSTR name, int *index) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - return ISAXAttributes_getIndexFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri), - localName, SysStringLen(localName), index); + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + const struct attribute *attr; + + attr = saxlocator_get_attribute_by_name(locator, uri, SysStringLen(uri), name, SysStringLen(name), index); + + return attr ? S_OK : E_INVALIDARG; } -static HRESULT WINAPI ivbsaxattributes_getIndexFromQName( - IVBSAXAttributes* iface, - BSTR QName, - int *index) +static HRESULT WINAPI ivbsaxattributes_getIndexFromQName(IVBSAXAttributes *iface, BSTR name, int *index) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - return ISAXAttributes_getIndexFromQName(&This->ISAXAttributes_iface, QName, - SysStringLen(QName), index); + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + const struct attribute *attr; + + if (!name || !index) return E_POINTER; + + if (!(attr = saxlocator_get_attribute_by_qname(locator, name, SysStringLen(name), index))) + return E_INVALIDARG; + + return S_OK; } -static HRESULT WINAPI ivbsaxattributes_getType( - IVBSAXAttributes* iface, - int nIndex, - BSTR *type) +static HRESULT WINAPI ivbsaxattributes_getType(IVBSAXAttributes *iface, int index, BSTR *type) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - const WCHAR *typeW; - HRESULT hr; - int len; - - TRACE("(%p)->(%d %p)\n", This, nIndex, type); + FIXME("%p, %d, %p stub\n", iface, index, type); if (!type) return E_POINTER; - *type = NULL; - hr = ISAXAttributes_getType(&This->ISAXAttributes_iface, nIndex, &typeW, &len); - if (FAILED(hr)) - return hr; - - return return_bstrn(typeW, len, type); + return E_NOTIMPL; } -static HRESULT WINAPI ivbsaxattributes_getTypeFromName( - IVBSAXAttributes* iface, - BSTR uri, - BSTR localName, - BSTR *type) +static HRESULT WINAPI ivbsaxattributes_getTypeFromName(IVBSAXAttributes *iface, BSTR uri, BSTR name, BSTR *type) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - const WCHAR *typeW; - HRESULT hr; - int len; - - TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(uri), debugstr_w(localName), type); + FIXME("%p, %s, %s, %p stub\n", iface, debugstr_w(uri), debugstr_w(name), type); if (!type) return E_POINTER; - *type = NULL; - hr = ISAXAttributes_getTypeFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri), - localName, SysStringLen(localName), &typeW, &len); - if (FAILED(hr)) - return hr; - - return return_bstrn(typeW, len, type); + return E_NOTIMPL; } -static HRESULT WINAPI ivbsaxattributes_getTypeFromQName( - IVBSAXAttributes* iface, - BSTR QName, - BSTR *type) +static HRESULT WINAPI ivbsaxattributes_getTypeFromQName(IVBSAXAttributes *iface, BSTR name, BSTR *type) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - const WCHAR *typeW; - HRESULT hr; - int len; - - TRACE("(%p)->(%s %p)\n", This, debugstr_w(QName), type); + FIXME("%p, %s, %p stub\n", iface, debugstr_w(name), type); if (!type) return E_POINTER; - *type = NULL; - hr = ISAXAttributes_getTypeFromQName(&This->ISAXAttributes_iface, QName, SysStringLen(QName), - &typeW, &len); - if (FAILED(hr)) - return hr; - - return return_bstrn(typeW, len, type); + return E_NOTIMPL; } -static HRESULT WINAPI ivbsaxattributes_getValue( - IVBSAXAttributes* iface, - int nIndex, - BSTR *value) +static HRESULT WINAPI ivbsaxattributes_getValue(IVBSAXAttributes *iface, int index, BSTR *value) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - const WCHAR *valueW; - HRESULT hr; - int len; + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + const struct attribute *attr; - TRACE("(%p)->(%d %p)\n", This, nIndex, value); + TRACE("%p, %d, %p.\n", iface, index, value); if (!value) return E_POINTER; *value = NULL; - hr = ISAXAttributes_getValue(&This->ISAXAttributes_iface, nIndex, &valueW, &len); - if (FAILED(hr)) - return hr; - return return_bstrn(valueW, len, value); + if (!(attr = saxlocator_get_attribute(locator, index))) + return E_INVALIDARG; + + return return_bstrn(attr->value, SysStringLen(attr->value), value); } -static HRESULT WINAPI ivbsaxattributes_getValueFromName( - IVBSAXAttributes* iface, - BSTR uri, - BSTR localName, - BSTR *value) +static HRESULT WINAPI ivbsaxattributes_getValueFromName(IVBSAXAttributes *iface, BSTR uri, BSTR name, BSTR *value) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - const WCHAR *valueW; - HRESULT hr; - int len; + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + const struct attribute *attr; + int index; - TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(uri), debugstr_w(localName), value); + TRACE("%p, %s, %s, %p.\n", iface, debugstr_w(uri), debugstr_w(name), value); if (!value) return E_POINTER; *value = NULL; - hr = ISAXAttributes_getValueFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri), - localName, SysStringLen(localName), &valueW, &len); - if (FAILED(hr)) - return hr; - return return_bstrn(valueW, len, value); + if (!(attr = saxlocator_get_attribute_by_name(locator, uri, SysStringLen(uri), name, SysStringLen(name), &index))) + return E_INVALIDARG; + + return return_bstrn(attr->value, SysStringLen(attr->value), value); } -static HRESULT WINAPI ivbsaxattributes_getValueFromQName( - IVBSAXAttributes* iface, - BSTR QName, - BSTR *value) +static HRESULT WINAPI ivbsaxattributes_getValueFromQName(IVBSAXAttributes *iface, BSTR name, BSTR *value) { - saxlocator *This = impl_from_IVBSAXAttributes( iface ); - const WCHAR *valueW; - HRESULT hr; - int len; + struct saxlocator *locator = impl_from_IVBSAXAttributes(iface); + const struct attribute *attr; + int index; - TRACE("(%p)->(%s %p)\n", This, debugstr_w(QName), value); + TRACE("%p, %s, %p.\n", iface, debugstr_w(name), value); if (!value) return E_POINTER; *value = NULL; - hr = ISAXAttributes_getValueFromQName(&This->ISAXAttributes_iface, QName, - SysStringLen(QName), &valueW, &len); - if (FAILED(hr)) - return hr; - return return_bstrn(valueW, len, value); + if (!(attr = saxlocator_get_attribute_by_qname(locator, name, SysStringLen(name), &index))) + return E_INVALIDARG; + + return return_bstrn(attr->value, SysStringLen(attr->value), value); } static const struct IVBSAXAttributesVtbl ivbsaxattributes_vtbl = @@ -995,293 +1304,210 @@ static const struct IVBSAXAttributesVtbl ivbsaxattributes_vtbl = ivbsaxattributes_getValueFromQName }; -/*** ISAXAttributes interface ***/ -/*** IUnknown methods ***/ -static HRESULT WINAPI isaxattributes_QueryInterface( - ISAXAttributes* iface, - REFIID riid, - void **ppvObject) +static HRESULT WINAPI isaxattributes_QueryInterface(ISAXAttributes *iface, REFIID riid, void **obj) { - saxlocator *This = impl_from_ISAXAttributes(iface); - TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject); - return ISAXLocator_QueryInterface(&This->ISAXLocator_iface, riid, ppvObject); + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + return ISAXLocator_QueryInterface(&locator->ISAXLocator_iface, riid, obj); } -static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface) +static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes *iface) { - saxlocator *This = impl_from_ISAXAttributes(iface); - TRACE("%p\n", This); - return ISAXLocator_AddRef(&This->ISAXLocator_iface); + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + return ISAXLocator_AddRef(&locator->ISAXLocator_iface); } -static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface) +static ULONG WINAPI isaxattributes_Release(ISAXAttributes *iface) { - saxlocator *This = impl_from_ISAXAttributes(iface); - - TRACE("%p\n", This); - return ISAXLocator_Release(&This->ISAXLocator_iface); + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + return ISAXLocator_Release(&locator->ISAXLocator_iface); } /*** ISAXAttributes methods ***/ -static HRESULT WINAPI isaxattributes_getLength( - ISAXAttributes* iface, - int *length) +static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes *iface, int *length) { - saxlocator *This = impl_from_ISAXAttributes( iface ); + struct saxlocator *locator = impl_from_ISAXAttributes(iface); - *length = This->attr_count; - TRACE("Length set to %d\n", *length); - return S_OK; -} + TRACE("%p, %p.\n", iface, length); -static inline BOOL is_valid_attr_index(const saxlocator *locator, int index) -{ - return index < locator->attr_count && index >= 0; + *length = locator->attributes.count; + + return S_OK; } -static HRESULT WINAPI isaxattributes_getURI( - ISAXAttributes* iface, - int index, - const WCHAR **url, - int *size) +static HRESULT saxlocator_return_string(BSTR str, const WCHAR **p, int *length) { - saxlocator *This = impl_from_ISAXAttributes( iface ); - TRACE("(%p)->(%d)\n", This, index); - - if(!is_valid_attr_index(This, index)) return E_INVALIDARG; - if(!url || !size) return E_POINTER; + if (!p || !length) + return E_POINTER; - *size = SysStringLen(This->attributes[index].szURI); - *url = This->attributes[index].szURI; + *length = SysStringLen(str); + *p = str; - TRACE("(%s:%d)\n", debugstr_w(This->attributes[index].szURI), *size); + TRACE("%s:%d\n", debugstr_w(str), *length); return S_OK; } -static HRESULT WINAPI isaxattributes_getLocalName( - ISAXAttributes* iface, - int index, - const WCHAR **pLocalName, - int *pLocalNameLength) +static HRESULT WINAPI isaxattributes_getURI(ISAXAttributes *iface, int index, + const WCHAR **url, int *length) { - saxlocator *This = impl_from_ISAXAttributes( iface ); - TRACE("(%p)->(%d)\n", This, index); + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + const struct attribute *attr; - if(!is_valid_attr_index(This, index)) return E_INVALIDARG; - if(!pLocalName || !pLocalNameLength) return E_POINTER; + TRACE("%p, %d, %p, %p.\n", iface, index, url, length); - *pLocalNameLength = SysStringLen(This->attributes[index].szLocalname); - *pLocalName = This->attributes[index].szLocalname; - - return S_OK; + if (!(attr = saxlocator_get_attribute(locator, index))) return E_INVALIDARG; + return saxlocator_return_string(attr->uri, url, length); } -static HRESULT WINAPI isaxattributes_getQName( - ISAXAttributes* iface, - int index, - const WCHAR **pQName, - int *pQNameLength) +static HRESULT WINAPI isaxattributes_getLocalName(ISAXAttributes *iface, int index, + const WCHAR **name, int *length) { - saxlocator *This = impl_from_ISAXAttributes( iface ); - TRACE("(%p)->(%d)\n", This, index); + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + const struct attribute *attr; - if(!is_valid_attr_index(This, index)) return E_INVALIDARG; - if(!pQName || !pQNameLength) return E_POINTER; + TRACE("%p, %d, %p, %p.\n", iface, index, name, length); - *pQNameLength = SysStringLen(This->attributes[index].szQName); - *pQName = This->attributes[index].szQName; + if (!(attr = saxlocator_get_attribute(locator, index))) return E_INVALIDARG; + return saxlocator_return_string(attr->local, name, length); +} - return S_OK; +static HRESULT WINAPI isaxattributes_getQName(ISAXAttributes *iface, int index, + const WCHAR **name, int *length) +{ + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + const struct attribute *attr; + + TRACE("%p, %d, %p, %p.\n", iface, index, name, length); + + if (!(attr = saxlocator_get_attribute(locator, index))) return E_INVALIDARG; + return saxlocator_return_string(attr->qname, name, length); } -static HRESULT WINAPI isaxattributes_getName( - ISAXAttributes* iface, - int index, - const WCHAR **uri, - int *pUriLength, - const WCHAR **localName, - int *pLocalNameSize, - const WCHAR **QName, - int *pQNameLength) +static HRESULT WINAPI isaxattributes_getName(ISAXAttributes *iface, int index, + const WCHAR **uri, int *uri_length, const WCHAR **local, int *local_length, + const WCHAR **qname, int *qname_length) { - saxlocator *This = impl_from_ISAXAttributes( iface ); - TRACE("(%p)->(%d)\n", This, index); + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + const struct attribute *attr; - if(!is_valid_attr_index(This, index)) return E_INVALIDARG; - if(!uri || !pUriLength || !localName || !pLocalNameSize - || !QName || !pQNameLength) return E_POINTER; + TRACE("%p, %d, %p, %p, %p, %p, %p, %p.\n", iface, index, uri, uri_length, local, local_length, + qname, qname_length); - *pUriLength = SysStringLen(This->attributes[index].szURI); - *uri = This->attributes[index].szURI; - *pLocalNameSize = SysStringLen(This->attributes[index].szLocalname); - *localName = This->attributes[index].szLocalname; - *pQNameLength = SysStringLen(This->attributes[index].szQName); - *QName = This->attributes[index].szQName; + if (!(attr = saxlocator_get_attribute(locator, index))) return E_INVALIDARG; + if (!uri || !uri_length || !local || !local_length || !qname || !qname_length) return E_POINTER; - TRACE("(%s, %s, %s)\n", debugstr_w(*uri), debugstr_w(*localName), debugstr_w(*QName)); + saxlocator_return_string(attr->uri, uri, uri_length); + saxlocator_return_string(attr->local, local, local_length); + saxlocator_return_string(attr->qname, qname, qname_length); return S_OK; } -static HRESULT WINAPI isaxattributes_getIndexFromName( - ISAXAttributes* iface, - const WCHAR *pUri, - int cUriLength, - const WCHAR *pLocalName, - int cocalNameLength, - int *index) +static HRESULT WINAPI isaxattributes_getIndexFromName(ISAXAttributes *iface, const WCHAR *uri, + int uri_length, const WCHAR *local, int local_length, int *index) { - saxlocator *This = impl_from_ISAXAttributes( iface ); - int i; - TRACE("(%p)->(%s, %d, %s, %d)\n", This, debugstr_w(pUri), cUriLength, - debugstr_w(pLocalName), cocalNameLength); + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + const struct attribute *attr; - if(!pUri || !pLocalName || !index) return E_POINTER; + TRACE("%p, %s, %d, %s, %d, %p.\n", iface, debugstr_w(uri), uri_length, debugstr_w(local), local_length, index); - for(i=0; i<This->attr_count; i++) - { - if(cUriLength!=SysStringLen(This->attributes[i].szURI) - || cocalNameLength!=SysStringLen(This->attributes[i].szLocalname)) - continue; - if(cUriLength && memcmp(pUri, This->attributes[i].szURI, - sizeof(WCHAR)*cUriLength)) - continue; - if(cocalNameLength && memcmp(pLocalName, This->attributes[i].szLocalname, - sizeof(WCHAR)*cocalNameLength)) - continue; + if (!uri || !local || !index) + return E_POINTER; - *index = i; - return S_OK; - } + attr = saxlocator_get_attribute_by_name(locator, uri, uri_length, local, local_length, index); - return E_INVALIDARG; + return attr ? S_OK : E_INVALIDARG; } -static HRESULT WINAPI isaxattributes_getIndexFromQName( - ISAXAttributes* iface, - const WCHAR *pQName, - int nQNameLength, - int *index) +static HRESULT WINAPI isaxattributes_getIndexFromQName(ISAXAttributes *iface, const WCHAR *name, int length, int *index) { - saxlocator *This = impl_from_ISAXAttributes( iface ); - int i; - TRACE("(%p)->(%s, %d)\n", This, debugstr_w(pQName), nQNameLength); + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + const struct attribute *attr; - if(!pQName || !index) return E_POINTER; - if(!nQNameLength) return E_INVALIDARG; + TRACE("%p, %s, %d, %p.\n", iface, debugstr_w(name), length, index); - for(i=0; i<This->attr_count; i++) - { - if(nQNameLength!=SysStringLen(This->attributes[i].szQName)) continue; - if(memcmp(pQName, This->attributes[i].szQName, sizeof(WCHAR)*nQNameLength)) continue; + if (!name || !index) return E_POINTER; + if (!length) return E_INVALIDARG; - *index = i; - return S_OK; - } + attr = saxlocator_get_attribute_by_qname(locator, name, length, index); - return E_INVALIDARG; + return attr ? S_OK : E_INVALIDARG; } -static HRESULT WINAPI isaxattributes_getType( - ISAXAttributes* iface, - int nIndex, - const WCHAR **pType, - int *pTypeLength) +static HRESULT WINAPI isaxattributes_getType(ISAXAttributes *iface, int index, const WCHAR **type, + int *length) { - saxlocator *This = impl_from_ISAXAttributes( iface ); + FIXME("%p, %d, %p, %p stub\n", iface, index, type, length); - FIXME("(%p)->(%d) stub\n", This, nIndex); return E_NOTIMPL; } -static HRESULT WINAPI isaxattributes_getTypeFromName( - ISAXAttributes* iface, - const WCHAR *pUri, - int nUri, - const WCHAR *pLocalName, - int nLocalName, - const WCHAR **pType, - int *nType) +static HRESULT WINAPI isaxattributes_getTypeFromName(ISAXAttributes *iface, const WCHAR *uri, + int uri_length, const WCHAR *name, int name_length, const WCHAR **type, int *type_length) { - saxlocator *This = impl_from_ISAXAttributes( iface ); + FIXME("%p, %s, %d, %s, %d, %p, %p stub\n", iface, debugstr_w(uri), uri_length, debugstr_w(name), + name_length, type, type_length); - FIXME("(%p)->(%s, %d, %s, %d) stub\n", This, debugstr_w(pUri), nUri, - debugstr_w(pLocalName), nLocalName); return E_NOTIMPL; } -static HRESULT WINAPI isaxattributes_getTypeFromQName( - ISAXAttributes* iface, - const WCHAR *pQName, - int nQName, - const WCHAR **pType, - int *nType) +static HRESULT WINAPI isaxattributes_getTypeFromQName(ISAXAttributes *iface, const WCHAR *name, + int name_length, const WCHAR **type, int *type_length) { - saxlocator *This = impl_from_ISAXAttributes( iface ); + FIXME("%p, %s, %d, %p, %p stub\n", iface, debugstr_w(name), name_length, type, type_length); - FIXME("(%p)->(%s, %d) stub\n", This, debugstr_w(pQName), nQName); return E_NOTIMPL; } -static HRESULT WINAPI isaxattributes_getValue( - ISAXAttributes* iface, - int index, - const WCHAR **value, - int *nValue) +static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes *iface, int index, const WCHAR **value, + int *length) { - saxlocator *This = impl_from_ISAXAttributes( iface ); - TRACE("(%p)->(%d)\n", This, index); - - if(!is_valid_attr_index(This, index)) return E_INVALIDARG; - if(!value || !nValue) return E_POINTER; + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + const struct attribute *attr; - *nValue = SysStringLen(This->attributes[index].szValue); - *value = This->attributes[index].szValue; + TRACE("%p, %d, %p, %p.\n", iface, index, value, length); - TRACE("(%s:%d)\n", debugstr_w(*value), *nValue); - - return S_OK; + if (!(attr = saxlocator_get_attribute(locator, index))) return E_INVALIDARG; + return saxlocator_return_string(attr->value, value, length); } -static HRESULT WINAPI isaxattributes_getValueFromName( - ISAXAttributes* iface, - const WCHAR *pUri, - int nUri, - const WCHAR *pLocalName, - int nLocalName, - const WCHAR **pValue, - int *nValue) +static HRESULT WINAPI isaxattributes_getValueFromName(ISAXAttributes *iface, const WCHAR *uri, + int uri_length, const WCHAR *name, int name_length, const WCHAR **value, int *length) { - HRESULT hr; + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + const struct attribute *attr; int index; - saxlocator *This = impl_from_ISAXAttributes( iface ); - TRACE("(%p)->(%s, %d, %s, %d)\n", This, debugstr_w(pUri), nUri, - debugstr_w(pLocalName), nLocalName); - hr = ISAXAttributes_getIndexFromName(iface, - pUri, nUri, pLocalName, nLocalName, &index); - if(hr==S_OK) hr = ISAXAttributes_getValue(iface, index, pValue, nValue); + TRACE("%p, %s, %d, %s, %d, %p, %p.\n", iface, debugstr_w(uri), uri_length, + debugstr_w(name), name_length, value, length); - return hr; + if (!uri || !name) + return E_POINTER; + + attr = saxlocator_get_attribute_by_name(locator, uri, uri_length, name, name_length, &index); + if (attr) + return saxlocator_return_string(attr->value, value, length); + + return E_INVALIDARG; } -static HRESULT WINAPI isaxattributes_getValueFromQName( - ISAXAttributes* iface, - const WCHAR *pQName, - int nQName, - const WCHAR **pValue, - int *nValue) +static HRESULT WINAPI isaxattributes_getValueFromQName(ISAXAttributes *iface, + const WCHAR *name, int name_length, const WCHAR **value, int *length) { - HRESULT hr; + struct saxlocator *locator = impl_from_ISAXAttributes(iface); + const struct attribute *attr; int index; - saxlocator *This = impl_from_ISAXAttributes( iface ); - TRACE("(%p)->(%s, %d)\n", This, debugstr_w(pQName), nQName); - hr = ISAXAttributes_getIndexFromQName(iface, pQName, nQName, &index); - if(hr==S_OK) hr = ISAXAttributes_getValue(iface, index, pValue, nValue); + TRACE("%p, %s, %d, %p, %p.\n", iface, debugstr_w(name), name_length, value, length); - return hr; + if (!name) + return E_POINTER; + + attr = saxlocator_get_attribute_by_qname(locator, name, name_length, &index); + if (attr) + return saxlocator_return_string(attr->value, value, length); + + return E_INVALIDARG; } static const struct ISAXAttributesVtbl isaxattributes_vtbl = @@ -1304,1373 +1530,3921 @@ static const struct ISAXAttributesVtbl isaxattributes_vtbl = isaxattributes_getValueFromQName }; -/* Libxml2 escapes '&' back to char reference '&' in attribute value, - so when document has escaped value with '&' it's parsed to '&' and then - escaped to '&'. This function takes care of ampersands only. */ -static BSTR saxreader_get_unescaped_value(const xmlChar *buf, int len) +static void saxreader_free_bstr(BSTR *str) { - static const WCHAR ampescW[] = L"&"; - WCHAR *dest, *ptrW, *str; - DWORD str_len; - BSTR bstr; - - if (!buf) - return NULL; - - str_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, NULL, 0); - if (len != -1) str_len++; - - str = malloc(str_len * sizeof(WCHAR)); - if (!str) return NULL; - - MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, str, str_len); - if (len != -1) str[str_len-1] = 0; - - ptrW = str; - while ((dest = wcsstr(ptrW, ampescW))) - { - WCHAR *src; - - /* leave first '&' from a reference as a value */ - src = dest + ARRAY_SIZE(ampescW) - 1; - dest++; - - /* move together with null terminator */ - memmove(dest, src, (lstrlenW(src) + 1)*sizeof(WCHAR)); - - ptrW++; - } - - bstr = SysAllocString(str); - free(str); - - return bstr; + SysFreeString(*str); + *str = NULL; } -static void free_attribute_values(saxlocator *locator) +static void saxreader_clear_attributes(struct saxlocator *locator) { - int i; - - for (i = 0; i < locator->attr_count; i++) + for (size_t i = 0; i < locator->attributes.count; ++i) { - SysFreeString(locator->attributes[i].szLocalname); - locator->attributes[i].szLocalname = NULL; + struct attribute *attr = &locator->attributes.entries[i]; - SysFreeString(locator->attributes[i].szValue); - locator->attributes[i].szValue = NULL; - - SysFreeString(locator->attributes[i].szQName); - locator->attributes[i].szQName = NULL; + saxreader_free_bstr(&attr->local); + saxreader_free_bstr(&attr->value); + saxreader_free_bstr(&attr->qname); + saxreader_free_bstr(&attr->prefix); } + + free(locator->attributes.map); + locator->attributes.map = NULL; + locator->attributes.count = 0; } -static HRESULT SAXAttributes_populate(saxlocator *locator, - int nb_namespaces, const xmlChar **xmlNamespaces, - int nb_attributes, const xmlChar **xmlAttributes) +static HRESULT WINAPI ivbsaxlocator_QueryInterface(IVBSAXLocator *iface, REFIID riid, void **obj) { - static const xmlChar xmlns[] = "xmlns"; + struct saxlocator *locator = impl_from_IVBSAXLocator(iface); - struct _attributes *attrs; - int i; + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); - /* skip namespace definitions */ - if ((locator->saxreader->features & NamespacePrefixes) == 0) - nb_namespaces = 0; + *obj = NULL; - locator->attr_count = nb_namespaces + nb_attributes; - if(locator->attr_count > locator->attr_alloc_count) + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IDispatch) || + IsEqualGUID(riid, &IID_IVBSAXLocator)) { - int new_size = locator->attr_count * 2; - attrs = realloc(locator->attributes, new_size * sizeof(*locator->attributes)); - if(!attrs) - { - free_attribute_values(locator); - locator->attr_count = 0; - return E_OUTOFMEMORY; - } - memset(attrs + locator->attr_alloc_count, 0, - (new_size - locator->attr_alloc_count) * sizeof(*locator->attributes)); - locator->attributes = attrs; - locator->attr_alloc_count = new_size; + *obj = iface; } - else + else if (IsEqualGUID(riid, &IID_IVBSAXAttributes)) { - attrs = locator->attributes; + *obj = &locator->IVBSAXAttributes_iface; } - - for (i = 0; i < nb_namespaces; i++) + else { - SysFreeString(attrs[nb_attributes+i].szLocalname); - attrs[nb_attributes+i].szLocalname = SysAllocStringLen(NULL, 0); + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } - attrs[nb_attributes+i].szURI = locator->namespaceUri; + IVBSAXLocator_AddRef(iface); - SysFreeString(attrs[nb_attributes+i].szValue); - attrs[nb_attributes+i].szValue = bstr_from_xmlChar(xmlNamespaces[2*i+1]); + return S_OK; +} - SysFreeString(attrs[nb_attributes+i].szQName); - if(!xmlNamespaces[2*i]) - attrs[nb_attributes+i].szQName = SysAllocString(L"xmlns"); - else - attrs[nb_attributes+i].szQName = QName_from_xmlChar(xmlns, xmlNamespaces[2*i]); - } +static ULONG WINAPI ivbsaxlocator_AddRef(IVBSAXLocator *iface) +{ + struct saxlocator *locator = impl_from_IVBSAXLocator(iface); + return ISAXLocator_AddRef(&locator->ISAXLocator_iface); +} - for (i = 0; i < nb_attributes; i++) - { - static const xmlChar xmlA[] = "xml"; +static ULONG WINAPI ivbsaxlocator_Release(IVBSAXLocator *iface) +{ + struct saxlocator *locator = impl_from_IVBSAXLocator(iface); + return ISAXLocator_Release(&locator->ISAXLocator_iface); +} - if (xmlStrEqual(xmlAttributes[i*5+1], xmlA)) - attrs[i].szURI = bstr_from_xmlChar(xmlAttributes[i*5+2]); - else - /* that's an important feature to keep same uri pointer for every reported attribute */ - attrs[i].szURI = find_element_uri(locator, xmlAttributes[i*5+2]); +static HRESULT WINAPI ivbsaxlocator_GetTypeInfoCount(IVBSAXLocator *iface, UINT *count) +{ + TRACE("%p, %p.\n", iface, count); - SysFreeString(attrs[i].szLocalname); - attrs[i].szLocalname = bstr_from_xmlChar(xmlAttributes[i*5]); + *count = 1; - SysFreeString(attrs[i].szValue); - attrs[i].szValue = saxreader_get_unescaped_value(xmlAttributes[i*5+3], xmlAttributes[i*5+4]-xmlAttributes[i*5+3]); + return S_OK; +} - SysFreeString(attrs[i].szQName); - attrs[i].szQName = QName_from_xmlChar(xmlAttributes[i*5+1], xmlAttributes[i*5]); - } +static HRESULT WINAPI ivbsaxlocator_GetTypeInfo(IVBSAXLocator *iface, UINT index, LCID lcid, ITypeInfo **ti) +{ + TRACE("%p, %u, %lx, %p.\n", iface, index, lcid, ti); - return S_OK; + return get_typeinfo(IVBSAXLocator_tid, ti); } -/*** LibXML callbacks ***/ -static void libxmlStartDocument(void *ctx) +static HRESULT WINAPI ivbsaxlocator_GetIDsOfNames(IVBSAXLocator *iface, REFIID riid, LPOLESTR *names, + UINT count, LCID lcid, DISPID *dispid) { - saxlocator *This = ctx; - struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader); + ITypeInfo *typeinfo; HRESULT hr; - if (This->saxreader->version >= MSXML4) - { - const xmlChar *p = This->pParserCtxt->input->cur-1; - update_position(This, FALSE); - while(p>This->pParserCtxt->input->base && *p!='>') - { - if(*p=='\n' || (*p=='\r' && *(p+1)!='\n')) - This->line--; - p--; + TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), names, count, lcid, dispid); + + if (!names || !count || !dispid) + return E_INVALIDARG; + + hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo); + if (SUCCEEDED(hr)) + { + hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid); + ITypeInfo_Release(typeinfo); + } + + return hr; +} + +static HRESULT WINAPI ivbsaxlocator_Invoke(IVBSAXLocator *iface, DISPID dispid, REFIID riid, + LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *ei, UINT *argerr) +{ + ITypeInfo *typeinfo; + HRESULT hr; + + TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispid, debugstr_guid(riid), + lcid, flags, params, result, ei, argerr); + + hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo); + if (SUCCEEDED(hr)) + { + hr = ITypeInfo_Invoke(typeinfo, iface, dispid, flags, params, result, ei, argerr); + ITypeInfo_Release(typeinfo); + } + + return hr; +} + +static HRESULT WINAPI ivbsaxlocator_get_columnNumber(IVBSAXLocator *iface, int *column) +{ + struct saxlocator *locator = impl_from_IVBSAXLocator(iface); + return ISAXLocator_getColumnNumber(&locator->ISAXLocator_iface, column); +} + +static HRESULT WINAPI ivbsaxlocator_get_lineNumber(IVBSAXLocator *iface, int *line) +{ + struct saxlocator *locator = impl_from_IVBSAXLocator(iface); + return ISAXLocator_getLineNumber(&locator->ISAXLocator_iface, line); +} + +static HRESULT WINAPI ivbsaxlocator_get_publicId(IVBSAXLocator *iface, BSTR *ret) +{ + FIXME("%p, %p stub.\n", iface, ret); + + if (!ret) + return E_POINTER; + + *ret = NULL; + + return S_OK; +} + +static HRESULT WINAPI ivbsaxlocator_get_systemId(IVBSAXLocator *iface, BSTR *ret) +{ + FIXME("%p, %p.\n", iface, ret); + + if (!ret) + return E_POINTER; + + *ret = NULL; + + return S_OK; +} + +static const struct IVBSAXLocatorVtbl VBSAXLocatorVtbl = +{ + ivbsaxlocator_QueryInterface, + ivbsaxlocator_AddRef, + ivbsaxlocator_Release, + ivbsaxlocator_GetTypeInfoCount, + ivbsaxlocator_GetTypeInfo, + ivbsaxlocator_GetIDsOfNames, + ivbsaxlocator_Invoke, + ivbsaxlocator_get_columnNumber, + ivbsaxlocator_get_lineNumber, + ivbsaxlocator_get_publicId, + ivbsaxlocator_get_systemId +}; + +static HRESULT WINAPI isaxlocator_QueryInterface(ISAXLocator *iface, REFIID riid, void **obj) +{ + struct saxlocator *locator = impl_from_ISAXLocator(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + *obj = NULL; + + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_ISAXLocator)) + { + *obj = iface; + } + else if (IsEqualGUID(riid, &IID_ISAXAttributes)) + { + *obj = &locator->ISAXAttributes_iface; + } + else + { + WARN("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + + ISAXLocator_AddRef(iface); + + return S_OK; +} + +static ULONG WINAPI isaxlocator_AddRef(ISAXLocator* iface) +{ + struct saxlocator *locator = impl_from_ISAXLocator(iface); + ULONG refcount = InterlockedIncrement(&locator->refcount); + TRACE("%p, refcount %lu.\n", iface, refcount); + return refcount; +} + +static ULONG WINAPI isaxlocator_Release(ISAXLocator *iface) +{ + struct saxlocator *locator = impl_from_ISAXLocator(iface); + ULONG refcount = InterlockedDecrement(&locator->refcount); + + TRACE("%p, refcount %ld.\n", iface, refcount); + + if (!refcount) + { + element_entry *element, *element2; + + SysFreeString(locator->xmlns_uri); + SysFreeString(locator->xml_uri); + SysFreeString(locator->null_uri); + + saxreader_clear_attributes(locator); + free(locator->attributes.entries); + + /* element stack */ + LIST_FOR_EACH_ENTRY_SAFE(element, element2, &locator->elements, element_entry, entry) + { + list_remove(&element->entry); + free_element_entry(element); + } + + encoded_buffer_cleanup(&locator->buffer.utf16); + encoded_buffer_cleanup(&locator->buffer.raw); + + if (locator->stream) + ISequentialStream_Release(locator->stream); + ISAXXMLReader_Release(&locator->saxreader->ISAXXMLReader_iface); + free(locator); + } + + return refcount; +} + +/*** ISAXLocator methods ***/ +static HRESULT WINAPI isaxlocator_getColumnNumber(ISAXLocator *iface, int *column) +{ + struct saxlocator *locator = impl_from_ISAXLocator(iface); + + *column = locator->column; + return S_OK; +} + +static HRESULT WINAPI isaxlocator_getLineNumber(ISAXLocator *iface, int *line) +{ + struct saxlocator *locator = impl_from_ISAXLocator(iface); + + *line = locator->line; + return S_OK; +} + +static HRESULT WINAPI isaxlocator_getPublicId(ISAXLocator *iface, const WCHAR **value) +{ + FIXME("%p, %p stub\n", iface, value); + + *value = NULL; + return S_OK; +} + +static HRESULT WINAPI isaxlocator_getSystemId(ISAXLocator *iface, const WCHAR **value) +{ + FIXME("%p, %p stub\n", iface, value); + + *value = NULL; + return S_OK; +} + +static const struct ISAXLocatorVtbl SAXLocatorVtbl = +{ + isaxlocator_QueryInterface, + isaxlocator_AddRef, + isaxlocator_Release, + isaxlocator_getColumnNumber, + isaxlocator_getLineNumber, + isaxlocator_getPublicId, + isaxlocator_getSystemId +}; + +static HRESULT saxlocator_create(struct saxreader *reader, ISequentialStream *stream, + bool vbInterface, struct saxlocator **obj) +{ + struct saxlocator *locator; + HRESULT hr; + + *obj = NULL; + + if (!(locator = calloc(1, sizeof(*locator)))) + return E_OUTOFMEMORY; + + locator->IVBSAXLocator_iface.lpVtbl = &VBSAXLocatorVtbl; + locator->ISAXLocator_iface.lpVtbl = &SAXLocatorVtbl; + locator->IVBSAXAttributes_iface.lpVtbl = &ivbsaxattributes_vtbl; + locator->ISAXAttributes_iface.lpVtbl = &isaxattributes_vtbl; + locator->refcount = 1; + locator->vbInterface = vbInterface; + + locator->saxreader = reader; + ISAXXMLReader_AddRef(&reader->ISAXXMLReader_iface); + + locator->stream = stream; + ISequentialStream_AddRef(locator->stream); + + locator->line = reader->version < MSXML4 ? 0 : 1; + locator->column = 0; + locator->buffer.position.line = 1; + locator->buffer.position.column = 1; + locator->buffer.chunk_size = 4096; + list_init(&locator->buffer.entities); + + locator->ret = S_OK; + + locator->xml_uri = saxreader_alloc_string(locator, L"http://www.w3.org/XML/1998/namespace"); + locator->null_uri = saxreader_alloc_stringlen(locator, NULL, 0); + if (locator->saxreader->version >= MSXML6) + locator->xmlns_uri = saxreader_alloc_string(locator, L"http://www.w3.org/2000/xmlns/"); + else + locator->xmlns_uri = saxreader_alloc_stringlen(locator, NULL, 0); + + list_init(&locator->elements); + list_init(&locator->dtd.attr_decls); + list_init(&locator->dtd.entities); + + if (FAILED(locator->status)) + { + hr = locator->status; + ISAXLocator_Release(&locator->ISAXLocator_iface); + return hr; + } + + *obj = locator; + + TRACE("returning %p\n", *obj); + + return S_OK; +} + +static bool saxreader_array_reserve(struct saxlocator *locator, void **elements, size_t *capacity, size_t count, size_t size) +{ + bool ret; + + if (!(ret = array_reserve(elements, capacity, count, size))) + saxreader_set_error(locator, E_OUTOFMEMORY); + + return ret; +} + +static bool saxreader_reserve_buffer(struct saxlocator *locator, struct encoded_buffer *buffer, size_t size) +{ + return saxreader_array_reserve(locator, (void **)&buffer->data, &buffer->allocated, + buffer->written + size, sizeof(*buffer->data)); +} + +static bool saxreader_stream_read(struct saxlocator *locator, void *buffer, ULONG size, ULONG *read) +{ + HRESULT hr; + + if (locator->eos) + return false; + + if (FAILED(hr = ISequentialStream_Read(locator->stream, buffer, size, read))) + { + saxreader_set_error(locator, hr); + locator->eos = true; + return false; + } + + locator->eos = *read == 0; + return true; +} + +static void saxreader_convert_input(struct saxlocator *locator, bool switch_encoding) +{ + struct encoded_buffer *utf16 = &locator->buffer.utf16; + struct encoded_buffer *raw = &locator->buffer.raw; + ULONG read = 0, size; + + /* First conversion attempt with a new codepage. */ + + if (switch_encoding) + { + size = raw->cur; + raw->cur = 0; + } + else + { + size = convert_get_raw_length(&locator->buffer); + } + + read = locator->buffer.converter(locator->buffer.code_page, raw->data + raw->cur, size, NULL, 0); + + if (saxreader_reserve_buffer(locator, utf16, (read + 1) * sizeof(WCHAR))) + { + locator->buffer.converter(locator->buffer.code_page, raw->data + raw->cur, size, + (WCHAR *)(utf16->data + utf16->written), read); + + utf16->written += read * sizeof(WCHAR); + *(WCHAR *)&utf16->data[utf16->written] = 0; + + /* Discard processed raw data */ + if (locator->buffer.switched_encoding) + { + if (size < raw->written) + memmove(raw->data, raw->data + size, raw->written - size); + raw->written -= size; + } + else + { + raw->cur += size; + } + } +} + +static void saxreader_more(struct saxlocator *locator) +{ + struct encoded_buffer *utf16 = &locator->buffer.utf16; + struct encoded_buffer *raw = &locator->buffer.raw; + ULONG read = 0, size; + + if (locator->buffer.encoding == XML_ENCODING_UTF16LE) + { + ULONG needed = locator->buffer.chunk_size * sizeof(WCHAR); + + if (!saxreader_reserve_buffer(locator, utf16, needed + sizeof(WCHAR))) + return; + + if (!saxreader_stream_read(locator, utf16->data + utf16->written, needed, &read)) + return; + utf16->written += read; + *(WCHAR *)&utf16->data[utf16->written] = 0; + + return; + } + + size = convert_estimate_raw_size(locator->buffer.encoding, locator->buffer.chunk_size); + if (!saxreader_reserve_buffer(locator, raw, size)) + return; + + if (!saxreader_stream_read(locator, raw->data + raw->written, size, &read)) + return; + raw->written += read; + + /* Convert complete part of the input */ + saxreader_convert_input(locator, false); +} + +static void saxreader_shrink(struct saxlocator *locator) +{ + struct encoded_buffer *buffer = &locator->buffer.utf16; + size_t size; + + if (buffer->cur > 3 * locator->buffer.chunk_size / 8) + { + size = buffer->written - buffer->cur * sizeof(WCHAR); + if (size) + memmove(buffer->data, (WCHAR *)buffer->data + buffer->cur, size); + + buffer->written = size; + buffer->cur = 0; + } +} + +static WCHAR *saxreader_get_ptr(struct saxlocator *locator) +{ + struct encoded_buffer *buffer = &locator->buffer.utf16; + WCHAR *ptr = (WCHAR *)buffer->data + buffer->cur; + if (!*ptr) saxreader_more(locator); + return (WCHAR *)buffer->data + buffer->cur; +} + +static WCHAR saxreader_get_char(struct saxlocator *locator, int pos) +{ + struct encoded_buffer *buffer = &locator->buffer.utf16; + if (buffer->written - buffer->cur < pos * sizeof(WCHAR)) return 0; + return *(WCHAR *)(buffer->data + buffer->cur + pos * sizeof(WCHAR)); +} + +static WCHAR *saxreader_get_ptr_noread(struct saxlocator *locator) +{ + struct encoded_buffer *buffer = &locator->buffer.utf16; + return (WCHAR *)buffer->data + buffer->cur; +} + +static void saxreader_update_position(struct saxlocator *locator, WCHAR ch) +{ + struct input_buffer *input = &locator->buffer; + + /* Treat \r\n -> \n */ + if (ch == '\r' || (!input->last_cr && ch == '\n')) + { + ++input->position.line; + input->position.column = 1; + } + else if (!(input->last_cr && ch == '\n')) + { + ++input->position.column; + } + input->last_cr = ch == '\r'; +} + +static void saxlocator_end_entity(struct saxlocator *locator, const struct text_position *position, BSTR name); + +static bool saxreader_pop_entity(struct saxlocator *locator) +{ + struct input_buffer *input = &locator->buffer; + struct entity_decl *entity; + + if (list_empty(&input->entities)) return true; + + entity = LIST_ENTRY(list_head(&input->entities), struct entity_decl, input_entry); + + if (entity->remaining) + { + --entity->remaining; + return false; + } + + entity->visited = false; + list_remove(&entity->input_entry); + + saxlocator_end_entity(locator, &entity->position, entity->name); + + return list_empty(&input->entities); +} + +static void saxreader_skip(struct saxlocator *locator, int n) +{ + struct encoded_buffer *buffer = &locator->buffer.utf16; + struct input_buffer *input = &locator->buffer; + WCHAR ch; + + while (locator->status == S_OK && (ch = *saxreader_get_ptr(locator)) && n--) + { + if (saxreader_pop_entity(locator)) + saxreader_update_position(locator, ch); + + ++buffer->cur; + ++input->consumed; + } +} + +static bool saxreader_peek(struct saxlocator *locator, const WCHAR *str, size_t count) +{ + struct encoded_buffer *buffer = &locator->buffer.utf16; + WCHAR *ptr = (WCHAR *)buffer->data + buffer->cur; + + if (FAILED(locator->status)) + return false; + + if ((buffer->written - buffer->cur) < count) + return false; + + return !memcmp(ptr, str, count * sizeof(WCHAR)); +} + +static bool saxreader_cmp(struct saxlocator *locator, const WCHAR *str) +{ + const WCHAR *ptr; + size_t i = 0; + + if (FAILED(locator->status)) + return false; + + ptr = saxreader_get_ptr(locator); + while (str[i]) + { + if (!ptr[i]) + { + saxreader_more(locator); + ptr = saxreader_get_ptr(locator); + } + if (str[i] != ptr[i]) + return false; + i++; + } + saxreader_skip(locator, i); + return true; +} + +static void saxreader_fatal_error(struct saxlocator *locator) +{ + struct saxerrorhandler_iface *handler = saxreader_get_errorhandler(locator->saxreader); + + if (saxreader_has_handler(locator, SAXErrorHandler)) + { + WCHAR msg[1024]; + + if (!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, locator->status, 0, msg, ARRAY_SIZE(msg), NULL)) + { + FIXME("MSXML errors not yet supported.\n"); + msg[0] = '\0'; + } + + if (locator->vbInterface) + { + BSTR s = SysAllocString(msg); + IVBSAXErrorHandler_fatalError(handler->vbhandler, &locator->IVBSAXLocator_iface, &s, locator->status); + SysFreeString(s); + } + else + { + ISAXErrorHandler_fatalError(handler->handler, &locator->ISAXLocator_iface, msg, locator->status); + } + } +} + +struct ns +{ + BSTR prefix; + BSTR uri; +}; + +struct element +{ + struct list entry; + struct name name; + BSTR uri; + + struct + { + struct ns *entries; + size_t count; + size_t capacity; + } ns; +}; + +static HRESULT saxlocator_callback_result(struct saxlocator *locator, HRESULT hr) +{ + if (locator->saxreader->version >= MSXML4) return FAILED(hr) ? hr : S_OK; + return hr; +} + +static void saxlocator_put_document_locator(struct saxlocator *locator) +{ + struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(locator->saxreader); + HRESULT hr = S_OK; + + if (locator->status != S_OK) + return; + + locator->start_document_position = locator->buffer.position; + if (locator->start_document_position.column) + --locator->start_document_position.column; + + if (saxreader_has_handler(locator, SAXContentHandler)) + { + if (locator->vbInterface) + hr = IVBSAXContentHandler_putref_documentLocator(handler->vbhandler, &locator->IVBSAXLocator_iface); + else + hr = ISAXContentHandler_putDocumentLocator(handler->handler, &locator->ISAXLocator_iface); + } + + if (FAILED(hr)) + locator->status = hr; +} + +static void saxlocator_start_document(struct saxlocator *locator) +{ + struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(locator->saxreader); + HRESULT hr = S_OK; + + if (locator->status != S_OK) + return; + + if (locator->saxreader->version >= MSXML4) + { + locator->line = locator->start_document_position.line; + locator->column = locator->start_document_position.column; + } + else + { + locator->line = 0; + locator->column = 0; + } + + if (saxreader_has_handler(locator, SAXContentHandler)) + { + if (locator->vbInterface) + hr = IVBSAXContentHandler_startDocument(handler->vbhandler); + else + hr = ISAXContentHandler_startDocument(handler->handler); + } + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_end_document(struct saxlocator *locator) +{ + struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(locator->saxreader); + HRESULT hr = S_OK; + + if (locator->status != S_OK) + return; + + if (locator->saxreader->version >= MSXML4) + { + locator->line = locator->buffer.position.line; + locator->column = locator->buffer.position.column - 1; + } + else + { + locator->line = 0; + locator->column = 0; + } + + if (saxreader_has_handler(locator, SAXContentHandler)) + { + if (locator->vbInterface) + hr = IVBSAXContentHandler_endDocument(handler->vbhandler); + else + hr = ISAXContentHandler_endDocument(handler->handler); + } + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_start_element(struct saxlocator *locator, const struct text_position *position, + struct element *element) +{ + struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(locator->saxreader); + BSTR uri = NULL, local = NULL; + HRESULT hr; + + if (locator->status != S_OK) + return; + + if (!saxreader_has_handler(locator, SAXContentHandler)) + return; + + locator->line = position->line; + locator->column = position->column; + /* Point to the closing '>' */ + if (locator->saxreader->version >= MSXML4) + --locator->column; + + if (is_namespaces_enabled(locator->saxreader)) + { + for (size_t i = 0; i < element->ns.count && saxreader_has_handler(locator, SAXContentHandler); ++i) + { + struct ns *ns = &element->ns.entries[i]; + + if (locator->vbInterface) + hr = IVBSAXContentHandler_startPrefixMapping( + handler->vbhandler, &ns->prefix, &ns->uri); + else + hr = ISAXContentHandler_startPrefixMapping( + handler->handler, + ns->prefix, + SysStringLen(ns->prefix), + ns->uri, + SysStringLen(ns->uri)); + + if (FAILED((hr = saxlocator_callback_result(locator, hr)))) + { + locator->status = hr; + return; + } + } + + uri = element->uri; + local = element->name.local; + } + + if (locator->vbInterface) + { + if (!uri) uri = locator->saxreader->empty_bstr; + hr = IVBSAXContentHandler_startElement(handler->vbhandler, &uri, &local, &element->name.qname, + &locator->IVBSAXAttributes_iface); + } + else + { + hr = ISAXContentHandler_startElement(handler->handler, uri ? uri : &empty_str, SysStringLen(uri), + local ? local : &empty_str, SysStringLen(local), element->name.qname, SysStringLen(element->name.qname), + &locator->ISAXAttributes_iface); + } + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_end_element(struct saxlocator *locator, const struct text_position *position, struct element *element) +{ + struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(locator->saxreader); + BSTR uri = NULL, local = NULL; + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = position->line; + /* Point to the closing '>' */ + if (locator->saxreader->version >= MSXML4) + locator->column = locator->buffer.position.column - 1; + else + locator->column = position->column; + + if (saxreader_has_handler(locator, SAXContentHandler)) + { + if (is_namespaces_enabled(locator->saxreader)) + { + uri = element->uri; + local = element->name.local; + } + + if (locator->vbInterface) + { + if (!uri) uri = locator->saxreader->empty_bstr; + hr = IVBSAXContentHandler_endElement(handler->vbhandler, &uri, &local, &element->name.qname); + } + else + { + hr = ISAXContentHandler_endElement(handler->handler, uri ? uri : &empty_str, SysStringLen(uri), + local ? local : &empty_str, SysStringLen(local), element->name.qname, SysStringLen(element->name.qname)); + } + + locator->status = saxlocator_callback_result(locator, hr); + } + + if (locator->status != S_OK) + return; + + if (is_namespaces_enabled(locator->saxreader)) + { + for (size_t i = 0; i < element->ns.count && saxreader_has_handler(locator, SAXContentHandler); ++i) + { + size_t index = locator->saxreader->version >= MSXML4 ? i : element->ns.count - 1 - i; + struct ns *ns = &element->ns.entries[index]; + + if (locator->vbInterface) + hr = IVBSAXContentHandler_endPrefixMapping(handler->vbhandler, &ns->prefix); + else + hr = ISAXContentHandler_endPrefixMapping(handler->handler, ns->prefix, SysStringLen(ns->prefix)); + + locator->status = saxlocator_callback_result(locator, hr); + if (locator->status != S_OK) + break; + } + } +} + +static void saxlocator_start_cdata(struct saxlocator *locator, const struct text_position *position) +{ + struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader); + HRESULT hr = S_OK; + + if (locator->status != S_OK) + return; + + locator->line = position->line; + locator->column = position->column; + /* Point to the closing '[' */ + if (locator->saxreader->version >= MSXML4) + --locator->column; + + if (saxreader_has_handler(locator, SAXLexicalHandler)) + { + if (locator->vbInterface) + hr = IVBSAXLexicalHandler_startCDATA(lexical->vbhandler); + else + hr = ISAXLexicalHandler_startCDATA(lexical->handler); + } + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_end_cdata(struct saxlocator *locator, const struct text_position *position) +{ + struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader); + HRESULT hr = S_OK; + + if (locator->status != S_OK) + return; + + if (locator->saxreader->version >= MSXML4) + { + locator->line = locator->buffer.position.line; + locator->column = locator->buffer.position.column - 1; + } + else + { + locator->line = position->line; + locator->column = position->column; + } + + if (saxreader_has_handler(locator, SAXLexicalHandler)) + { + if (locator->vbInterface) + hr = IVBSAXLexicalHandler_endCDATA(lexical->vbhandler); + else + hr = ISAXLexicalHandler_endCDATA(lexical->handler); + } + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_characters(struct saxlocator *locator, const struct text_position *position, BSTR chars) +{ + struct saxcontenthandler_iface *content = saxreader_get_contenthandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK || !*chars) + return; + + locator->line = position->line; + locator->column = position->column; + + if (!saxreader_has_handler(locator, SAXContentHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXContentHandler_characters(content->vbhandler, &chars); + else + hr = ISAXContentHandler_characters(content->handler, chars, SysStringLen(chars)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_comment(struct saxlocator *locator, const struct text_position *position, BSTR chars) +{ + struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = position->line; + locator->column = position->column; + + if (!saxreader_has_handler(locator, SAXLexicalHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXLexicalHandler_comment(lexical->vbhandler, &chars); + else + hr = ISAXLexicalHandler_comment(lexical->handler, chars, SysStringLen(chars)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_pi(struct saxlocator *locator, const struct text_position *position, BSTR target, BSTR data) +{ + struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + /* Point to the closing '>' */ + if (locator->saxreader->version >= MSXML4) + { + locator->line = locator->buffer.position.line; + locator->column = locator->buffer.position.column - 1; + } + else + { + locator->line = position->line; + locator->column = position->column; + } + + if (!saxreader_has_handler(locator, SAXContentHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXContentHandler_processingInstruction(handler->vbhandler, &target, &data); + else + hr = ISAXContentHandler_processingInstruction(handler->handler, target, SysStringLen(target), + data, SysStringLen(data)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_skipped_entity(struct saxlocator *locator, const struct text_position *position, BSTR name) +{ + struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = position->line; + locator->column = position->column; + + if (!saxreader_has_handler(locator, SAXContentHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXContentHandler_skippedEntity(handler->vbhandler, &name); + else + hr = ISAXContentHandler_skippedEntity(handler->handler, name, SysStringLen(name)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_notationdecl(struct saxlocator *locator, const struct text_position *position, + BSTR name, BSTR pubid, BSTR sysid) +{ + struct saxdtdhandler_iface *handler = saxreader_get_dtdhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = position->line; + locator->column = position->column; + + if (!saxreader_has_handler(locator, SAXDTDHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXDTDHandler_notationDecl(handler->vbhandler, &name, &pubid, &sysid); + else + hr = ISAXDTDHandler_notationDecl(handler->handler, name, SysStringLen(name), + pubid, SysStringLen(pubid), sysid, SysStringLen(sysid)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_unparsed_entitydecl(struct saxlocator *locator, BSTR name, BSTR pubid, BSTR sysid, BSTR notation) +{ + struct saxdtdhandler_iface *handler = saxreader_get_dtdhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = locator->buffer.position.line; + locator->column = locator->buffer.position.column; + + if (!saxreader_has_handler(locator, SAXDTDHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXDTDHandler_unparsedEntityDecl(handler->vbhandler, &name, &pubid, &sysid, ¬ation); + else + hr = ISAXDTDHandler_unparsedEntityDecl(handler->handler, name, SysStringLen(name), + pubid, SysStringLen(pubid), sysid, SysStringLen(sysid), notation, SysStringLen(notation)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_external_entitydecl(struct saxlocator *locator, BSTR name, BSTR pubid, BSTR sysid) +{ + struct saxdeclhandler_iface *handler = saxreader_get_declhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = locator->buffer.position.line; + locator->column = locator->buffer.position.column; + + if (!saxreader_has_handler(locator, SAXDeclHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXDeclHandler_externalEntityDecl(handler->vbhandler, &name, &pubid, &sysid); + else + hr = ISAXDeclHandler_externalEntityDecl(handler->handler, name, SysStringLen(name), + pubid, SysStringLen(pubid), sysid, SysStringLen(sysid)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_elementdecl(struct saxlocator *locator, BSTR name, BSTR model) +{ + struct saxdeclhandler_iface *handler = saxreader_get_declhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = locator->buffer.position.line; + locator->column = locator->buffer.position.column; + + if (!saxreader_has_handler(locator, SAXDeclHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXDeclHandler_elementDecl(handler->vbhandler, &name, &model); + else + hr = ISAXDeclHandler_elementDecl(handler->handler, name, SysStringLen(name), model, SysStringLen(model)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_internal_entitydecl(struct saxlocator *locator, BSTR name, BSTR value) +{ + struct saxdeclhandler_iface *handler = saxreader_get_declhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = locator->buffer.position.line; + locator->column = locator->buffer.position.column; + + if (!saxreader_has_handler(locator, SAXDeclHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXDeclHandler_internalEntityDecl(handler->vbhandler, &name, &value); + else + hr = ISAXDeclHandler_internalEntityDecl(handler->handler, name, SysStringLen(name), + value, SysStringLen(value)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_attribute_decl(struct saxlocator *locator, struct attlist_decl *decl) +{ + struct saxdeclhandler_iface *handler = saxreader_get_declhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = locator->buffer.position.line; + locator->column = locator->buffer.position.column; + + if (!saxreader_has_handler(locator, SAXDeclHandler)) + return; + + for (size_t i = 0; i < decl->count && locator->status == S_OK; ++i) + { + if (locator->vbInterface) + hr = IVBSAXDeclHandler_attributeDecl(handler->vbhandler, &decl->name, + &decl->attributes[i].name.qname, &decl->attributes[i].type, + &decl->attributes[i].valuetype, &decl->attributes[i].value); + else + hr = ISAXDeclHandler_attributeDecl(handler->handler, decl->name, SysStringLen(decl->name), + decl->attributes[i].name.qname, SysStringLen(decl->attributes[i].name.qname), + decl->attributes[i].type, SysStringLen(decl->attributes[i].type), + decl->attributes[i].valuetype, SysStringLen(decl->attributes[i].valuetype), + decl->attributes[i].value, SysStringLen(decl->attributes[i].value)); + + locator->status = saxlocator_callback_result(locator, hr); + } +} + +static void saxlocator_startdtd(struct saxlocator *locator, BSTR name, BSTR pubid, BSTR sysid) +{ + struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = locator->buffer.position.line; + locator->column = locator->buffer.position.column; + + if (!saxreader_has_handler(locator, SAXLexicalHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXLexicalHandler_startDTD(lexical->vbhandler, &name, &pubid, &sysid); + else + hr = ISAXLexicalHandler_startDTD(lexical->handler, name, SysStringLen(name), + pubid, SysStringLen(pubid), sysid, SysStringLen(sysid)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_enddtd(struct saxlocator *locator) +{ + struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = locator->buffer.position.line; + locator->column = locator->buffer.position.column; + + if (!saxreader_has_handler(locator, SAXLexicalHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXLexicalHandler_endDTD(lexical->vbhandler); + else + hr = ISAXLexicalHandler_endDTD(lexical->handler); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_start_entity(struct saxlocator *locator, const struct text_position *position, BSTR name) +{ + struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = position->line; + locator->column = position->column; + + if (!saxreader_has_handler(locator, SAXLexicalHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXLexicalHandler_startEntity(lexical->vbhandler, &name); + else + hr = ISAXLexicalHandler_startEntity(lexical->handler, name, SysStringLen(name)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +static void saxlocator_end_entity(struct saxlocator *locator, const struct text_position *position, BSTR name) +{ + struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader); + HRESULT hr; + + if (locator->status != S_OK) + return; + + locator->line = position->line; + locator->column = position->column; + + if (!saxreader_has_handler(locator, SAXLexicalHandler)) + return; + + if (locator->vbInterface) + hr = IVBSAXLexicalHandler_endEntity(lexical->vbhandler, &name); + else + hr = ISAXLexicalHandler_endEntity(lexical->handler, name, SysStringLen(name)); + + locator->status = saxlocator_callback_result(locator, hr); +} + +struct string_buffer +{ + WCHAR *data; + size_t count; + size_t capacity; +}; + +static void saxreader_string_append(struct saxlocator *locator, struct string_buffer *buffer, + const WCHAR *str, UINT len) +{ + if (!saxreader_array_reserve(locator, (void **)&buffer->data, &buffer->capacity, buffer->count + len, sizeof(*str))) + { + saxreader_set_error(locator, E_OUTOFMEMORY); + return; + } + + memcpy(buffer->data + buffer->count, str, len * sizeof(WCHAR)); + buffer->count += len; +} + +static void saxreader_string_append_bstr(struct saxlocator *locator, struct string_buffer *buffer, BSTR *str) +{ + saxreader_string_append(locator, buffer, *str, SysStringLen(*str)); + SysFreeString(*str); + *str = NULL; +} + +static BSTR saxreader_string_to_bstr(struct saxlocator *locator, struct string_buffer *buffer) +{ + BSTR str = saxreader_alloc_stringlen(locator, buffer->data, buffer->count); + free(buffer->data); + memset(buffer, 0, sizeof(*buffer)); + return str; +} + +/* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */ +static bool saxreader_is_space(WCHAR ch) +{ + return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; +} + +/* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */ +static bool saxreader_skipspaces(struct saxlocator *locator) +{ + size_t length = 0; + const WCHAR *ptr; + + if (locator->status != S_OK) + return false; + + ptr = saxreader_get_ptr(locator); + while (saxreader_is_space(*ptr)) + { + saxreader_skip(locator, 1); + ptr = saxreader_get_ptr(locator); + ++length; + } + + return length; +} + +static bool saxreader_skip_required_spaces(struct saxlocator *locator) +{ + bool ret; + + if (!(ret = saxreader_skipspaces(locator))) + saxreader_set_error(locator, E_SAX_MISSINGWHITESPACE); + + return ret; +} + +/* [25] Eq ::= S? '=' S? */ +static void saxreader_parse_eq(struct saxlocator *locator) +{ + saxreader_skipspaces(locator); + if (!saxreader_cmp(locator, L"=")) + return saxreader_set_error(locator, E_SAX_MISSINGEQUALS); + saxreader_skipspaces(locator); +} + +/* [26] VersionNum ::= '1.' [0-9]+ */ +static void saxreader_parse_versionnum(struct saxlocator *locator) +{ + if (saxreader_cmp(locator, L"1.0")) + { + SysFreeString(locator->saxreader->xmldecl_version); + locator->saxreader->xmldecl_version = saxreader_alloc_string(locator, L"1.0"); + } + else + { + saxreader_set_error(locator, E_SAX_INVALID_VERSION); + } +} + +static WCHAR saxreader_is_quote(struct saxlocator *locator) +{ + const WCHAR *ptr; + + if (locator->status != S_OK) + return 0; + + ptr = saxreader_get_ptr(locator); + if (*ptr == '\'' || *ptr == '"') return *ptr; + return 0; +} + +/* [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') */ +static void saxreader_parse_versioninfo(struct saxlocator *locator) +{ + WCHAR q[2] = { 0 }; + + if (!saxreader_cmp(locator, L"version")) + return saxreader_set_error(locator, E_SAX_BAD_XMLDECL); + + saxreader_parse_eq(locator); + if (!(q[0] = saxreader_is_quote(locator))) + saxreader_set_error(locator, E_SAX_MISSINGQUOTE); + saxreader_skip(locator, 1); + + saxreader_parse_versionnum(locator); + + if (!saxreader_cmp(locator, q)) + saxreader_set_error(locator, E_SAX_MISSINGQUOTE); +} + +static void saxreader_switch_encoding(struct saxlocator *locator, UINT codepage) +{ + /* We'll keep mbtowc converter. */ + locator->buffer.code_page = codepage; + + /* Convert entire buffer again, nothing should've been discarded yet. + The utf16 buffer cursor is kept intact. */ + locator->buffer.utf16.written = 0; + locator->buffer.switched_encoding = true; + saxreader_convert_input(locator, true); +} + +/* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */ +static void saxreader_parse_encdecl(struct saxlocator *locator) +{ + struct string_buffer buffer = { 0 }; + WCHAR q[2] = { 0 }, ch; + UINT codepage; + + saxreader_skip_required_spaces(locator); + if (!saxreader_cmp(locator, L"encoding")) + return; + + saxreader_parse_eq(locator); + + if (!(q[0] = saxreader_is_quote(locator))) + saxreader_set_error(locator, E_SAX_MISSINGQUOTE); + saxreader_skip(locator, 1); + + ch = *saxreader_get_ptr(locator); + while (ch != *q) + { + saxreader_string_append(locator, &buffer, &ch, 1); + saxreader_skip(locator, 1); + ch = *saxreader_get_ptr(locator); + } + + if (!saxreader_cmp(locator, q)) + saxreader_set_error(locator, E_SAX_MISSINGQUOTE); + + locator->saxreader->xmldecl_encoding = saxreader_string_to_bstr(locator, &buffer); + TRACE("encoding name %s\n", debugstr_w(locator->saxreader->xmldecl_encoding)); + + /* Switch encoding only in UTF-8 -> mbtowc-able direction. */ + + if (locator->buffer.encoding == XML_ENCODING_UTF8) + { + if (saxreader_get_encoding_codepage(locator->saxreader->xmldecl_encoding, &codepage)) + saxreader_switch_encoding(locator, codepage); + else if (!saxreader_can_ignore_encoding(locator->saxreader->xmldecl_encoding)) + FIXME("Unsupported encoding %s.\n", debugstr_w(locator->saxreader->xmldecl_encoding)); + } +} + +/* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */ +static void saxreader_parse_sddecl(struct saxlocator *locator) +{ + WCHAR q[2] = { 0 }; + + saxreader_skipspaces(locator); + + if (!saxreader_cmp(locator, L"standalone")) + return; + + saxreader_parse_eq(locator); + + if (!(q[0] = saxreader_is_quote(locator))) + saxreader_set_error(locator, E_SAX_MISSINGQUOTE); + saxreader_skip(locator, 1); + + if (saxreader_cmp(locator, L"yes")) + locator->saxreader->xmldecl_standalone = saxreader_alloc_string(locator, L"yes"); + else if (saxreader_cmp(locator, L"no")) + locator->saxreader->xmldecl_standalone = saxreader_alloc_string(locator, L"no"); + else + saxreader_set_error(locator, E_SAX_INVALID_STANDALONE); + + if (!saxreader_cmp(locator, q)) + saxreader_set_error(locator, E_SAX_MISSINGQUOTE); +} + +/* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */ +static void saxreader_parse_xmldecl(struct saxlocator *locator) +{ + WCHAR ch; + + saxreader_more(locator); + + ch = saxreader_get_char(locator, 5); + if (!saxreader_peek(locator, L"<?xml", 5) || !saxreader_is_space(ch)) + return; + saxreader_skip(locator, 5); + saxreader_skipspaces(locator); + + saxreader_parse_versioninfo(locator); + + if (saxreader_cmp(locator, L"?>")) + return; + + saxreader_parse_encdecl(locator); + + if (locator->saxreader->xmldecl_encoding) + { + if (saxreader_cmp(locator, L"?>")) + return; + saxreader_skip_required_spaces(locator); + } + + saxreader_skipspaces(locator); + saxreader_parse_sddecl(locator); + saxreader_skipspaces(locator); + + if (!saxreader_cmp(locator, L"?>")) + saxreader_set_error(locator, E_SAX_BAD_XMLDECL); +} + +/* [85] BaseChar ::= ... */ +static bool saxreader_is_basechar(WCHAR ch) +{ + return (ch >= 0x41 && ch <= 0x5a) + || (ch >= 0x61 && ch <= 0x7a) || (ch >= 0xc0 && ch <= 0xd6) + || (ch >= 0xd8 && ch <= 0xf6) || (ch >= 0xf8 && ch <= 0x131) + || (ch >= 0x134 && ch <= 0x13e) || (ch >= 0x141 && ch <= 0x148) + || (ch >= 0x14a && ch <= 0x17e) || (ch >= 0x180 && ch <= 0x1c3) + || (ch >= 0x1cd && ch <= 0x1f0) || (ch >= 0x1f4 && ch <= 0x1f5) + || (ch >= 0x1fa && ch <= 0x217) || (ch >= 0x250 && ch <= 0x2a8) + || (ch >= 0x2bb && ch <= 0x2c1) || ch == 0x386 || (ch >= 0x388 && ch <= 0x38a) + || ch == 0x38c || (ch >= 0x38e && ch <= 0x3a1) + || (ch >= 0x3a3 && ch <= 0x3ce) || (ch >= 0x3d0 && ch <= 0x3d6) + || ch == 0x3da || ch == 0x3dc || ch == 0x3de || ch == 0x3e0 + || (ch >= 0x3e2 && ch <= 0x3f3) || (ch >= 0x401 && ch <= 0x40c) + || (ch >= 0x40e && ch <= 0x44f) || (ch >= 0x451 && ch <= 0x45c) + || (ch >= 0x45e && ch <= 0x481) || (ch >= 0x490 && ch <= 0x4c4) + || (ch >= 0x4c7 && ch <= 0x4c8) || (ch >= 0x4cb && ch <= 0x4cc) + || (ch >= 0x4d0 && ch <= 0x4eb) || (ch >= 0x4ee && ch <= 0x4f5) + || (ch >= 0x4f8 && ch <= 0x4f9) || (ch >= 0x531 && ch <= 0x556) + || ch == 0x559 || (ch >= 0x561 && ch <= 0x586) + || (ch >= 0x5d0 && ch <= 0x5ea) || (ch >= 0x5f0 && ch <= 0x5f2) + || (ch >= 0x621 && ch <= 0x63a) || (ch >= 0x641 && ch <= 0x64a) + || (ch >= 0x671 && ch <= 0x6b7) || (ch >= 0x6ba && ch <= 0x6be) + || (ch >= 0x6c0 && ch <= 0x6ce) || (ch >= 0x6d0 && ch <= 0x6d3) + || ch == 0x6d5 || (ch >= 0x6e5 && ch <= 0x6e6) + || (ch >= 0x905 && ch <= 0x939) || ch == 0x93d || (ch >= 0x958 && ch <= 0x961) + || (ch >= 0x985 && ch <= 0x98c) || (ch >= 0x98f && ch <= 0x990) + || (ch >= 0x993 && ch <= 0x9a8) || (ch >= 0x9aa && ch <= 0x9b0) + || ch == 0x9b2 || (ch >= 0x9b6 && ch <= 0x9b9) + || (ch >= 0x9dc && ch <= 0x9dd) || (ch >= 0x9df && ch <= 0x9e1) + || (ch >= 0x9f0 && ch <= 0x9f1) || (ch >= 0xa05 && ch <= 0xa0a) + || (ch >= 0xa0f && ch <= 0xa10) || (ch >= 0xa13 && ch <= 0xa28) + || (ch >= 0xa2a && ch <= 0xa30) || (ch >= 0xa32 && ch <= 0xa33) + || (ch >= 0xa35 && ch <= 0xa36) || (ch >= 0xa38 && ch <= 0xa39) + || (ch >= 0xa59 && ch <= 0xa5c) + || ch == 0xa5e || (ch >= 0xa72 && ch <= 0xa74) || (ch >= 0xa85 && ch <= 0xa8b) + || ch == 0xa8d || (ch >= 0xa8f && ch <= 0xa91) + || (ch >= 0xa93 && ch <= 0xaa8) || (ch >= 0xaaa && ch <= 0xab0) + || (ch >= 0xab2 && ch <= 0xab3) || (ch >= 0xab5 && ch <= 0xab9) + || ch == 0xabd || ch == 0xae0 || (ch >= 0xb05 && ch <= 0xb0c) + || (ch >= 0xb0f && ch <= 0xb10) || (ch >= 0xb13 && ch <= 0xb28) + || (ch >= 0xb2a && ch <= 0xb30) || (ch >= 0xb32 && ch <= 0xb33) + || (ch >= 0xb36 && ch <= 0xb39) || ch == 0xb3d || (ch >= 0xb5c && ch <= 0xb5d) + || (ch >= 0xb5f && ch <= 0xb61) || (ch >= 0xb85 && ch <= 0xb8a) + || (ch >= 0xb8e && ch <= 0xb90) || (ch >= 0xb92 && ch <= 0xb95) + || (ch >= 0xb99 && ch <= 0xb9a) || ch == 0xb9c || (ch >= 0xb9e && ch <= 0xb9f) + || (ch >= 0xba3 && ch <= 0xba4) || (ch >= 0xba8 && ch <= 0xbaa) + || (ch >= 0xbae && ch <= 0xbb5) || (ch >= 0xbb7 && ch <= 0xbb9) + || (ch >= 0xc05 && ch <= 0xc0c) || (ch >= 0xc0e && ch <= 0xc10) + || (ch >= 0xc12 && ch <= 0xc28) || (ch >= 0xc2a && ch <= 0xc33) + || (ch >= 0xc35 && ch <= 0xc39) || (ch >= 0xc60 && ch <= 0xc61) + || (ch >= 0xc85 && ch <= 0xc8c) || (ch >= 0xc8e && ch <= 0xc90) + || (ch >= 0xc92 && ch <= 0xca8) || (ch >= 0xcaa && ch <= 0xcb3) + || (ch >= 0xcb5 && ch <= 0xcb9) || ch == 0xcde || (ch >= 0xce0 && ch <= 0xce1) + || (ch >= 0xd05 && ch <= 0xd0c) || (ch >= 0xd0e && ch <= 0xd10) + || (ch >= 0xd12 && ch <= 0xd28) || (ch >= 0xd2a && ch <= 0xd39) + || (ch >= 0xd60 && ch <= 0xd61) || (ch >= 0xe01 && ch <= 0xe2e) + || ch == 0xe30 || (ch >= 0xe32 && ch <= 0xe33) + || (ch >= 0xe40 && ch <= 0xe45) || (ch >= 0xe81 && ch <= 0xe82) + || ch == 0xe84 || (ch >= 0xe87 && ch <= 0xe88) + || ch == 0xe8a || ch == 0xe8d || (ch >= 0xe94 && ch <= 0xe97) + || (ch >= 0xe99 && ch <= 0xe9f) || (ch >= 0xea1 && ch <= 0xea3) + || ch == 0xea5 || ch == 0xea7 || (ch >= 0xeaa && ch <= 0xeab) + || (ch >= 0xead && ch <= 0xeae) || ch == 0xeb0 || (ch >= 0xeb2 && ch <= 0xeb3) + || ch == 0xebd || (ch >= 0xec0 && ch <= 0xec4) + || (ch >= 0xf40 && ch <= 0xf47) || (ch >= 0xf49 && ch <= 0xf69) + || (ch >= 0x10a0 && ch <= 0x10c5) || (ch >= 0x10d0 && ch <= 0x10f6) + || ch == 0x1100 || (ch >= 0x1102 && ch <= 0x1103) + || (ch >= 0x1105 && ch <= 0x1107) || ch == 0x1109 || (ch >= 0x110b && ch <= 0x110c) + || (ch >= 0x110e && ch <= 0x1112) || ch == 0x113c || ch == 0x113e || ch == 0x1140 + || ch == 0x114c || ch == 0x114e || ch == 0x1150 + || (ch >= 0x1154 && ch <= 0x1155) || ch == 0x1159 || (ch >= 0x115f && ch <= 0x1161) + || ch == 0x1163 || ch == 0x1165 || ch == 0x1167 + || ch == 0x1169 || (ch >= 0x116d && ch <= 0x116e) + || (ch >= 0x1172 && ch <= 0x1173) || ch == 0x1175 || ch == 0x119e || ch == 0x11a8 + || ch == 0x11ab || (ch >= 0x11ae && ch <= 0x11af) + || (ch >= 0x11b7 && ch <= 0x11b8) || ch == 0x11ba || (ch >= 0x11bc && ch <= 0x11c2) + || ch == 0x11eb || ch == 0x11f0 || ch == 0x11f9 + || (ch >= 0x1e00 && ch <= 0x1e9b) || (ch >= 0x1ea0 && ch <= 0x1ef9) + || (ch >= 0x1f00 && ch <= 0x1f15) || (ch >= 0x1f18 && ch <= 0x1f1d) + || (ch >= 0x1f20 && ch <= 0x1f45) || (ch >= 0x1f48 && ch <= 0x1f4d) + || (ch >= 0x1f50 && ch <= 0x1f57) || ch == 0x1f59 || ch == 0x1f5b || ch == 0x1f5d + || (ch >= 0x1f5f && ch <= 0x1f7d) || (ch >= 0x1f80 && ch <= 0x1fb4) + || (ch >= 0x1fb6 && ch <= 0x1fbc) || ch == 0x1fbe || (ch >= 0x1fc2 && ch <= 0x1fc4) + || (ch >= 0x1fc6 && ch <= 0x1fcc) || (ch >= 0x1fd0 && ch <= 0x1fd3) + || (ch >= 0x1fd6 && ch <= 0x1fdb) || (ch >= 0x1fe0 && ch <= 0x1fec) + || (ch >= 0x1ff2 && ch <= 0x1ff4) || (ch >= 0x1ff6 && ch <= 0x1ffc) + || ch == 0x2126 || (ch >= 0x212a && ch <= 0x212b) + || ch == 0x212e || (ch >= 0x2180 && ch <= 0x2182) + || (ch >= 0x3041 && ch <= 0x3094) || (ch >= 0x30a1 && ch <= 0x30fa) + || (ch >= 0x3105 && ch <= 0x312c) || (ch >= 0xac00 && ch <= 0xd7a3); +} + +/* [86] Ideographic ::= [#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029] */ +static bool saxreader_is_ideographic(WCHAR ch) +{ + return (ch >= 0x4e00 && ch <= 0x9fa5) || ch == 0x3007 + || (ch >= 0x3021 && ch <= 0x3029); +} + +/* [84] Letter ::= BaseChar | Ideographic */ +static bool saxreader_is_letter(WCHAR ch) +{ + return saxreader_is_basechar(ch) || saxreader_is_ideographic(ch); +} + +/* [87] CombiningChar ::= ... */ +static bool saxreader_is_combiningchar(WCHAR ch) +{ + return (ch >= 0x300 && ch <= 0x345) || (ch >= 0x360 && ch <= 0x361) + || (ch >= 0x483 && ch <= 0x486) || (ch >= 0x591 && ch <= 0x5a1) || ch == 0x670 + || (ch >= 0x6d6 && ch <= 0x6e4) || (ch >= 0x6e7 && ch <= 0x6e8) + || (ch >= 0x6ea && ch <= 0x6ed) || (ch >= 0x901 && ch <= 0x903) || ch == 0x93c + || (ch >= 0x93e && ch <= 0x94d) || (ch >= 0x951 && ch <= 0x954) + || (ch >= 0x962 && ch <= 0x963) || (ch >= 0x981 && ch <= 0x983) || ch == 0x9bc + || (ch >= 0x9be && ch <= 0x9bf) || (ch >= 0x9c0 && ch <= 0x9c4) + || (ch >= 0x9c7 && ch <= 0x9c8) || (ch >= 0x9cb && ch <= 0x9cd) || ch == 0x9d7 + || (ch >= 0x9e2 && ch <= 0x9e3) || ch == 0xa02 + || ch == 0xa3c || (ch >= 0xa3e && ch <= 0xa42) + || (ch >= 0xa47 && ch <= 0xa48) || (ch >= 0xa4b && ch <= 0xa4d) + || (ch >= 0xa70 && ch <= 0xa71) || (ch >= 0xa81 && ch <= 0xa83) + || ch == 0xabc || (ch >= 0xabe && ch <= 0xac5) + || (ch >= 0xac7 && ch <= 0xac9) || (ch >= 0xacb && ch <= 0xacd) + || (ch >= 0xb01 && ch <= 0xb03) || ch == 0xb3c || (ch >= 0xb3e && ch <= 0xb43) + || (ch >= 0xb47 && ch <= 0xb48) || (ch >= 0xb4b && ch <= 0xb4d) + || (ch >= 0xb56 && ch <= 0xb57) || (ch >= 0xb82 && ch <= 0xb83) + || (ch >= 0xbbe && ch <= 0xbc2) || (ch >= 0xbc6 && ch <= 0xbc8) + || (ch >= 0xbca && ch <= 0xbcd) + || ch == 0xbd7 || (ch >= 0xc01 && ch <= 0xc03) + || (ch >= 0xc3e && ch <= 0xc44) || (ch >= 0xc46 && ch <= 0xc48) + || (ch >= 0xc4a && ch <= 0xc4d) || (ch >= 0xc55 && ch <= 0xc56) + || (ch >= 0xc82 && ch <= 0xc83) || (ch >= 0xcbe && ch <= 0xcc4) + || (ch >= 0xcc6 && ch <= 0xcc8) || (ch >= 0xcca && ch <= 0xccd) + || (ch >= 0xcd5 && ch <= 0xcd6) || (ch >= 0xd02 && ch <= 0xd03) + || (ch >= 0xd3e && ch <= 0xd43) || (ch >= 0xd46 && ch <= 0xd48) + || (ch >= 0xd4a && ch <= 0xd4d) || ch == 0xd57 || ch == 0xe31 + || (ch >= 0xe34 && ch <= 0xe3a) || (ch >= 0xe47 && ch <= 0xe4e) + || ch == 0xeb1 || (ch >= 0xeb4 && ch <= 0xeb9) + || (ch >= 0xebb && ch <= 0xebc) || (ch >= 0xec8 && ch <= 0xecd) + || (ch >= 0xf18 && ch <= 0xf19) || ch == 0xf35 || ch == 0xf37 || ch == 0xf39 + || (ch >= 0xf3e && ch <= 0xf3f) || (ch >= 0xf71 && ch <= 0xf84) + || (ch >= 0xf86 && ch <= 0xf8b) || (ch >= 0xf90 && ch <= 0xf95) + || ch == 0xf97 || (ch >= 0xf99 && ch <= 0xfad) + || (ch >= 0xfb1 && ch <= 0xfb7) || ch == 0xfb9 || (ch >= 0x20d0 && ch <= 0x20dc) + || ch == 0x20e1 || (ch >= 0x302a && ch <= 0x302f) + || ch == 0x3099 || ch == 0x309a; +} + +/* [88] Digit ::= [#x0030-#x0039] | [#x0660-#x0669] | [#x06F0-#x06F9] | [#x0966-#x096F] | + [#x09E6-#x09EF] | [#x0A66-#x0A6F] | [#x0AE6-#x0AEF] | [#x0B66-#x0B6F] | + [#x0BE7-#x0BEF] | [#x0C66-#x0C6F] | [#x0CE6-#x0CEF] | [#x0D66-#x0D6F] | + [#x0E50-#x0E59] | [#x0ED0-#x0ED9] | [#x0F20-#x0F29] */ +static bool saxreader_is_digit(WCHAR ch) +{ + return (ch >= 0x30 && ch <= 0x39) || (ch >= 0x660 && ch <= 0x669) + || (ch >= 0x6f0 && ch <= 0x6f9) || (ch >= 0x966 && ch <= 0x96f) + || (ch >= 0x9e6 && ch <= 0x9ef) || (ch >= 0xa66 && ch <= 0xa6f) + || (ch >= 0xae6 && ch <= 0xaef) || (ch >= 0xb66 && ch <= 0xb6f) + || (ch >= 0xbe7 && ch <= 0xbef) || (ch >= 0xc66 && ch <= 0xc6f) + || (ch >= 0xce6 && ch <= 0xcef) || (ch >= 0xd66 && ch <= 0xd6f) + || (ch >= 0xe50 && ch <= 0xe59) || (ch >= 0xed0 && ch <= 0xed9) + || (ch >= 0xf20 && ch <= 0xf29); +} + +/* [89] Extender ::= #x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 | #x0E46 | #x0EC6 | #x3005 | + [#x3031-#x3035] | [#x309D-#x309E] | [#x30FC-#x30FE] */ +static bool saxreader_is_extender(WCHAR ch) +{ + return ch == 0xb7 || ch == 0x2d0 || ch == 0x2d1 || ch == 0x387 || ch == 0x640 || ch == 0xe46 + || ch == 0xec6 || ch == 0x3005 || (ch >= 0x3031 && ch <= 0x3035) + || (ch >= 0x309d && ch <= 0x309e) || (ch >= 0x30fc && ch <= 0x30fe); +} + +/* [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender */ +static bool saxreader_is_namechar(WCHAR ch) +{ + return saxreader_is_letter(ch) + || saxreader_is_digit(ch) + || ch == '.' || ch == '-' || ch == '_' || ch == ':' + || saxreader_is_combiningchar(ch) + || saxreader_is_extender(ch); +} + +/* [5] NCNameChar ::= NameChar - ':' */ +static bool saxreader_is_ncnamechar(WCHAR ch) +{ + return saxreader_is_namechar(ch) && ch != ':'; +} + +/* [6] NCNameStartChar ::= Letter | '_' */ +static bool saxreader_is_ncname_startchar(WCHAR ch) +{ + return saxreader_is_letter(ch) || ch == '_'; +} + +static void *saxreader_calloc(struct saxlocator *locator, size_t count, size_t size) +{ + void *ret; + + if (!(ret = calloc(count, size))) + saxreader_set_error(locator, E_OUTOFMEMORY); + + return ret; +} + +/* [7] Nmtoken ::= (NameChar)+ */ +static void saxreader_parse_nmtoken(struct saxlocator *locator, BSTR *token) +{ + WCHAR ch = *saxreader_get_ptr(locator), *ptr; + UINT len = 0; + + *token = NULL; + + while (saxreader_is_namechar(ch)) + { + saxreader_skip(locator, 1); + ch = *saxreader_get_ptr(locator); + ++len; + } + + if (len) + { + ptr = saxreader_get_ptr(locator); + *token = saxreader_alloc_stringlen(locator, ptr - len, len); + } + else + { + saxreader_set_error(locator, E_SAX_BADNAMECHAR); + } +} + +/* [5] Name ::= (Letter | '_' | ':') (NameChar)* + + Disallow leading ':', and optionally check for it, without stopping. */ +static void saxreader_parse_name_opt(struct saxlocator *locator, bool no_colons, BSTR *name) +{ + WCHAR ch = *saxreader_get_ptr(locator), *ptr; + UINT len, col_count = 0; + + *name = NULL; + + if (!saxreader_is_letter(ch) && ch != '_') + { + saxreader_set_error(locator, E_SAX_BADSTARTNAMECHAR); + return; + } + + len = 0; + while (saxreader_is_namechar(ch)) + { + if (ch == ':') ++col_count; + saxreader_skip(locator, 1); + ch = *saxreader_get_ptr(locator); + ++len; + } + + if (no_colons && col_count) + { + saxreader_set_error(locator, E_SAX_CONTAINSCOLON); + } + else if (col_count > 1) + { + saxreader_set_error(locator, E_SAX_MULTIPLE_COLONS); + } + else if (len) + { + ptr = saxreader_get_ptr(locator); + *name = saxreader_alloc_stringlen(locator, ptr - len, len); + } + else + { + saxreader_set_error(locator, E_SAX_BADNAMECHAR); + } +} + +static void saxreader_parse_name(struct saxlocator *locator, BSTR *name) +{ + saxreader_parse_name_opt(locator, false, name); +} + +/* Parse the name, then abort if it contains a colon. + + Used for entities, PIs, notations and most of attribute values */ +static void saxreader_parse_name_strict(struct saxlocator *locator, BSTR *name) +{ + saxreader_parse_name_opt(locator, true, name); +} + +/* [4 NS] NCName ::= NCNameStartChar NCNameChar* */ +static BSTR saxreader_parse_ncname(struct saxlocator *locator) +{ + struct string_buffer buffer = { 0 }; + WCHAR ch; + + if (locator->status != S_OK) + return NULL; + + ch = *saxreader_get_ptr(locator); + if (!saxreader_is_ncname_startchar(ch)) + { + saxreader_set_error(locator, E_SAX_BADSTARTNAMECHAR); + return NULL; + } + + do + { + saxreader_string_append(locator, &buffer, &ch, 1); + saxreader_skip(locator, 1); + ch = *saxreader_get_ptr(locator); + } + while (saxreader_is_ncnamechar(ch) && locator->status == S_OK); + + saxreader_shrink(locator); + + return saxreader_string_to_bstr(locator, &buffer); +} + +/* [7 NS] QName ::= PrefixedName | UnprefixedName + [8 NS] PrefixedName ::= Prefix ':' LocalPart + [9 NS] UnprefixedName ::= LocalPart + [10 NS] Prefix ::= NCName */ +static void saxreader_parse_qname(struct saxlocator *locator, struct name *name) +{ + struct string_buffer buffer = { 0 }; + BSTR ncname; + + memset(name, 0, sizeof(*name)); + + ncname = saxreader_parse_ncname(locator); + + if (saxreader_cmp(locator, L":")) + { + name->prefix = ncname; + name->local = saxreader_parse_ncname(locator); + if (*saxreader_get_ptr(locator) == ':') + saxreader_set_error(locator, E_SAX_MULTIPLE_COLONS); + } + else + { + name->local = ncname; + } + + if (name->prefix) + { + saxreader_string_append(locator, &buffer, name->prefix, SysStringLen(name->prefix)); + saxreader_string_append(locator, &buffer, L":", 1); + } + saxreader_string_append(locator, &buffer, name->local, SysStringLen(name->local)); + name->qname = saxreader_string_to_bstr(locator, &buffer); +} + +static struct element *saxreader_new_element(struct saxlocator *locator, struct name *name) +{ + struct element *element; + + if (!(element = saxreader_calloc(locator, 1, sizeof(*element)))) + return NULL; + list_add_head(&locator->elements, &element->entry); + + element->name = *name; + saxreader_clear_attributes(locator); + + return element; +} + +static void saxreader_free_name(struct name *name) +{ + SysFreeString(name->prefix); + SysFreeString(name->local); + SysFreeString(name->qname); + memset(name, 0, sizeof(*name)); +} + +static void saxreader_free_element(struct element *element) +{ + saxreader_free_name(&element->name); + free(element); +} + +static bool bstr_equal(BSTR s1, BSTR s2) +{ + if (SysStringLen(s1) != SysStringLen(s2)) return false; + return !memcmp(s1, s2, SysStringLen(s1) * sizeof(WCHAR)); +} + +static bool bstr_startswith(BSTR s, const WCHAR *prefix, UINT length) +{ + if (SysStringLen(s) < length) return false; + return !memcmp(s, prefix, length * sizeof(WCHAR)); +} + +static const struct ns *saxreader_get_namespace(struct saxlocator *locator, BSTR prefix) +{ + struct element *element; + + LIST_FOR_EACH_ENTRY(element, &locator->elements, struct element, entry) + { + for (size_t i = 0; i < element->ns.count; ++i) + { + if (bstr_equal(element->ns.entries[i].prefix, prefix)) + return &element->ns.entries[i]; + } + } + + return NULL; +} + +static void saxreader_add_namespace(struct saxlocator *locator, struct element *element, BSTR prefix, BSTR uri) +{ + struct ns *ns; + + if (bstr_startswith(prefix, L"xml", 3)) + return saxreader_set_error(locator, E_SAX_RESERVEDNAMESPACE); + + if (!saxreader_array_reserve(locator, (void **)&element->ns.entries, &element->ns.capacity, + element->ns.count + 1, sizeof(*element->ns.entries))) + { + return; + } + + ns = &element->ns.entries[element->ns.count++]; + ns->prefix = saxreader_alloc_string(locator, prefix); + ns->uri = saxreader_alloc_string(locator, uri); +} + +static bool saxreader_has_attribute(struct saxlocator *locator, BSTR name) +{ + for (size_t i = 0; i < locator->attributes.count; ++i) + { + if (bstr_equal(locator->attributes.entries[i].qname, name)) + return true; + } + + return false; +} + +static void saxreader_add_attribute(struct saxlocator *locator, const struct name *name, BSTR value, bool nsdef) +{ + struct attribute *attr; + + if (nsdef && !(locator->saxreader->features & NamespacePrefixes)) + return; + + if (saxreader_has_attribute(locator, name->qname)) + return saxreader_set_error(locator, E_SAX_DUPLICATEATTRIBUTE); + + if (!saxreader_array_reserve(locator, (void **)&locator->attributes.entries, &locator->attributes.capacity, + locator->attributes.count + 1, sizeof(*locator->attributes.entries))) + { + return; + } + + attr = &locator->attributes.entries[locator->attributes.count++]; + attr->prefix = name->prefix ? saxreader_alloc_string(locator, name->prefix) : NULL; + attr->local = saxreader_alloc_string(locator, nsdef ? L"" : name->local); + attr->qname = saxreader_alloc_string(locator, name->qname); + attr->value = saxreader_alloc_string(locator, value); + attr->nsdef = nsdef; +} + +static void saxreader_add_default_attributes(struct saxlocator *locator, struct element *element) +{ + struct attlist_decl *decl; + + LIST_FOR_EACH_ENTRY(decl, &locator->dtd.attr_decls, struct attlist_decl, entry) + { + if (bstr_equal(decl->name, element->name.qname)) + { + for (size_t i = 0; i < decl->count; ++i) + { + const struct attlist_attr *attr = &decl->attributes[i]; + + if (!saxreader_has_attribute(locator, attr->name.qname)) + saxreader_add_attribute(locator, &attr->name, attr->value, false); + } + } + } +} + +static void saxreader_set_element_uri(struct saxlocator *locator, struct element *element) +{ + struct attribute *attr; + const struct ns *ns; + + if (element->name.prefix) + { + if (!(ns = saxreader_get_namespace(locator, element->name.prefix))) + return saxreader_set_error(locator, E_SAX_UNDECLAREDPREFIX); + element->uri = ns->uri; + } + else if ((ns = saxreader_get_namespace(locator, locator->saxreader->empty_bstr))) + { + element->uri = ns->uri; + } + + for (size_t i = 0; i < locator->attributes.count; ++i) + { + attr = &locator->attributes.entries[i]; + + if (attr->nsdef) + { + attr->uri = locator->xmlns_uri; + } + else if (!attr->prefix) + { + attr->uri = locator->null_uri; + } + else if (!wcscmp(attr->prefix, L"xml")) + { + attr->uri = locator->xml_uri; + } + else if (!(ns = saxreader_get_namespace(locator, attr->prefix))) + { + return saxreader_set_error(locator, E_SAX_UNDECLAREDPREFIX); + } + else + { + attr->uri = ns->uri; + } + saxreader_free_bstr(&attr->prefix); + } +} + +/* [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] */ +static bool saxreader_is_char(UINT32 ch) +{ + return (ch == 0x9) || (ch == 0xa) || (ch == 0xd) || + (ch >= 0x20 && ch <= 0xd7ff) || + (ch >= 0xe000 && ch <= 0xfffd) || + (ch >= 0x10000 && ch <= 0x10ffff); +} + +/* [66] CharRef ::= '' [0-9]+ ';' | '' [0-9a-fA-F]+ ';' */ +static void saxreader_parse_charref(struct saxlocator *locator, struct string_buffer *buffer, + struct text_position *position) +{ + WCHAR u16[3], *ptr; + unsigned int len; + UINT32 ch = 0; + + /* Skip */ + saxreader_skip(locator, 2); + *position = locator->buffer.position; + + ptr = saxreader_get_ptr(locator); + + /* hex char or decimal */ + if (*ptr == 'x') + { + saxreader_skip(locator, 1); + ptr = saxreader_get_ptr(locator); + + while (*ptr != ';') + { + if ((*ptr >= '0' && *ptr <= '9')) + ch = ch*16 + *ptr - '0'; + else if ((*ptr >= 'a' && *ptr <= 'f')) + ch = ch*16 + *ptr - 'a' + 10; + else if ((*ptr >= 'A' && *ptr <= 'F')) + ch = ch*16 + *ptr - 'A' + 10; + else + return saxreader_set_error(locator, E_SAX_BADCHARINENTREF); + + if (ch > 0x10ffff) + return saxreader_set_error(locator, E_SAX_INVALID_UNICODE); + + saxreader_skip(locator, 1); + ptr = saxreader_get_ptr(locator); + } + } + else + { + while (*ptr != ';') + { + if (!(*ptr >= '0' && *ptr <= '9')) + return saxreader_set_error(locator, E_SAX_BADCHARINENTREF); + + ch = ch*10 + *ptr - '0'; + saxreader_skip(locator, 1); + ptr = saxreader_get_ptr(locator); + + if (ch > 0x10ffff) + return saxreader_set_error(locator, E_SAX_INVALID_UNICODE); } - This->column = 0; - for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--) - This->column++; } + /* For the closing ';' */ + saxreader_skip(locator, 1); + + if (!saxreader_is_char(ch)) + return saxreader_set_error(locator, E_SAX_INVALID_UNICODE); + + len = saxreader_convert_u32_to_u16(ch, u16); + saxreader_string_append(locator, buffer, u16, len); +} + +static struct entity_decl *saxreader_get_entity(struct saxlocator *locator, BSTR name) +{ + struct entity_decl *entity; + + if (!name) + return NULL; - /* store version value, declaration has to contain version attribute */ - if (This->pParserCtxt->standalone != -1) + LIST_FOR_EACH_ENTRY(entity, &locator->dtd.entities, struct entity_decl, entry) { - SysFreeString(This->saxreader->xmldecl_version); - This->saxreader->xmldecl_version = bstr_from_xmlChar(This->pParserCtxt->version); + if (bstr_equal(entity->name, name)) + return entity; } - if (saxreader_has_handler(This, SAXContentHandler)) + return NULL; +} + +static const WCHAR *saxreader_get_predefined_entity(BSTR name) +{ + if (!wcscmp(name, L"amp")) return L"&"; + if (!wcscmp(name, L"lt")) return L"<"; + if (!wcscmp(name, L"gt")) return L">"; + if (!wcscmp(name, L"apos")) return L"'"; + if (!wcscmp(name, L"quot")) return L"\""; + return NULL; +} + +static void saxreader_stringify_entity(struct saxlocator *locator, struct string_buffer *buffer, BSTR name) +{ + struct entity_decl *entity; + const WCHAR *value; + + if ((value = saxreader_get_predefined_entity(name))) + return saxreader_string_append(locator, buffer, value, 1); + + if (!(entity = saxreader_get_entity(locator, name))) + return saxreader_set_error(locator, E_SAX_UNDEFINEDREF); + + if (entity->visited) + return saxreader_set_error(locator, E_SAX_INFINITEREFLOOP); + + for (size_t i = 0; i < entity->content.count && locator->status == S_OK; ++i) { - if(This->vbInterface) - hr = IVBSAXContentHandler_startDocument(handler->vbhandler); - else - hr = ISAXContentHandler_startDocument(handler->handler); + const struct entity_part *part = &entity->content.parts[i]; - if (sax_callback_failed(This, hr)) - format_error_message_from_id(This, hr); + if (part->reference) + { + entity->visited = true; + saxreader_stringify_entity(locator, buffer, part->value); + entity->visited = false; + } + else + { + saxreader_string_append(locator, buffer, part->value, SysStringLen(part->value)); + } } } -static void libxmlEndDocument(void *ctx) +/* [10] AttValue ::= '"' ([^<&"] | Reference)* '"' + | "'" ([^<&'] | Reference)* "'" */ +static BSTR saxreader_parse_attvalue(struct saxlocator *locator) { - saxlocator *This = ctx; - struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader); - HRESULT hr; + struct string_buffer buffer = { 0 }; + struct text_position position; + WCHAR quote[2] = { 0 }, ch; + BSTR name; - if (This->saxreader->version >= MSXML4) { - update_position(This, FALSE); - if(This->column > 1) - This->line++; - This->column = 0; - } else { - This->column = 0; - This->line = 0; + if (!(quote[0] = saxreader_is_quote(locator))) + { + saxreader_set_error(locator, E_SAX_MISSINGQUOTE); + return NULL; } + saxreader_skip(locator, 1); - if(This->ret != S_OK) return; + /* All references are resolved */ - if (saxreader_has_handler(This, SAXContentHandler)) + while (locator->status == S_OK) { - if(This->vbInterface) - hr = IVBSAXContentHandler_endDocument(handler->vbhandler); + if (saxreader_cmp(locator, quote)) + break; + + if (saxreader_cmp(locator, L"<")) + { + saxreader_set_error(locator, E_SAX_BADCHARINSTRING); + break; + } + + if (saxreader_peek(locator, L"", 2)) + { + saxreader_parse_charref(locator, &buffer, &position); + } + else if (saxreader_peek(locator, L"&", 1)) + { + /* Skip '&' */ + saxreader_skip(locator, 1); + + saxreader_parse_name(locator, &name); + if (saxreader_cmp(locator, L";")) + saxreader_stringify_entity(locator, &buffer, name); + else + saxreader_set_error(locator, E_SAX_INVALID_UNICODE); + SysFreeString(name); + } else - hr = ISAXContentHandler_endDocument(handler->handler); + { + ch = *saxreader_get_ptr_noread(locator); + saxreader_string_append(locator, &buffer, &ch, 1); + saxreader_skip(locator, 1); + } + } + + if (locator->status != S_OK) return NULL; + + return saxreader_string_to_bstr(locator, &buffer); +} + +static bool saxreader_add_namespace_attribute(struct saxlocator *locator, struct element *element, + struct name *name, BSTR value) +{ + if (name->prefix && !wcscmp(name->prefix, L"xmlns")) + saxreader_add_namespace(locator, element, name->local, value); + else if (!name->prefix && name->local && !wcscmp(name->local, L"xmlns")) + saxreader_add_namespace(locator, element, locator->saxreader->empty_bstr, value); + else + return false; + + return true; +} + +/* [15 NS] Attribute ::= NSAttName Eq AttValue | QName Eq AttValue */ +static void saxreader_parse_attribute(struct saxlocator *locator, struct element *element) +{ + struct name name; + BSTR value; + bool ns; + + saxreader_parse_qname(locator, &name); + saxreader_skipspaces(locator); + if (!saxreader_cmp(locator, L"=")) + saxreader_set_error(locator, E_SAX_MISSINGEQUALS); + saxreader_skipspaces(locator); + value = saxreader_parse_attvalue(locator); + + ns = saxreader_add_namespace_attribute(locator, element, &name, value); + saxreader_add_attribute(locator, &name, value, !!ns); - if (sax_callback_failed(This, hr)) - format_error_message_from_id(This, hr); + saxreader_free_name(&name); + SysFreeString(value); +} + +static void saxreader_reorder_attributes(struct saxlocator *locator) +{ + size_t count, i, idx; + + if (locator->saxreader->version < MSXML4) + return; + if (!(locator->saxreader->features & Namespaces)) + return; + + count = locator->attributes.count; + if (!(locator->attributes.map = saxreader_calloc(locator, count, sizeof(*locator->attributes.map)))) + return; + + /* Regular attributes first, then namespace definitions. */ + + for (i = 0, idx = 0; i < count; ++i) + { + if (locator->attributes.entries[i].nsdef) continue; + locator->attributes.map[idx++] = i; + } + + for (i = 0; i < count; ++i) + { + if (!locator->attributes.entries[i].nsdef) continue; + locator->attributes.map[idx++] = i; } } -static void libxmlStartElementNS( - void *ctx, - const xmlChar *localname, - const xmlChar *prefix, - const xmlChar *URI, - int nb_namespaces, - const xmlChar **namespaces, - int nb_attributes, - int nb_defaulted, - const xmlChar **attributes) +/* [12 NS] STag ::= '<' QName (S Attribute)* S? '>' + [14 NS] EmptyElemTag ::= '<' QName (S Attribute)* S? '/>' */ +static void saxreader_parse_starttag(struct saxlocator *locator) { - saxlocator *This = ctx; - struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader); - element_entry *element; - HRESULT hr = S_OK; - BSTR uri; + struct text_position position = { 0 }; + bool empty_element = false; + struct element *element; + struct name name; - update_position(This, TRUE); - if(*(This->pParserCtxt->input->cur) == '/') - This->column++; - if(This->saxreader->version < MSXML4) - This->column++; + if (!saxreader_cmp(locator, L"<")) + return saxreader_set_error(locator, E_SAX_INVALIDATROOTLEVEL); - element = alloc_element_entry(localname, prefix, nb_namespaces, namespaces); - push_element_ns(This, element); + saxreader_parse_qname(locator, &name); - if (is_namespaces_enabled(This->saxreader)) + if (bstr_startswith(name.prefix, L"xml", 3)) { - int i; + saxreader_free_name(&name); + return saxreader_set_error(locator, E_SAX_RESERVEDNAMESPACE); + } + + if (!(element = saxreader_new_element(locator, &name))) + { + saxreader_free_name(&name); + return; + } + + while (locator->status == S_OK) + { + saxreader_skipspaces(locator); - for (i = 0; i < nb_namespaces && saxreader_has_handler(This, SAXContentHandler); i++) + if (saxreader_cmp(locator, L"/>")) { - if (This->vbInterface) - hr = IVBSAXContentHandler_startPrefixMapping( - handler->vbhandler, - &element->ns[i].prefix, - &element->ns[i].uri); - else - hr = ISAXContentHandler_startPrefixMapping( - handler->handler, - element->ns[i].prefix, - SysStringLen(element->ns[i].prefix), - element->ns[i].uri, - SysStringLen(element->ns[i].uri)); + empty_element = true; + position = locator->buffer.position; + break; + } - if (sax_callback_failed(This, hr)) - { - format_error_message_from_id(This, hr); - return; - } + if (saxreader_cmp(locator, L">")) + { + position = locator->buffer.position; + break; } + + saxreader_parse_attribute(locator, element); + } + + /* Append default attributes from DTD. */ + saxreader_add_default_attributes(locator, element); + saxreader_reorder_attributes(locator); + + /* The 'uri' string pointers are reused from the namespace stacks. + Namespace definitions can appear after attributes that are using them, + so we have to reiterate after all attributes were parsed. */ + saxreader_set_element_uri(locator, element); + + saxlocator_start_element(locator, &position, element); + if (empty_element) + { + saxlocator_end_element(locator, &position, element); + list_remove(&element->entry); + saxreader_free_element(element); } +} + +/* [13 NS] ETag ::= '</' QName S? '>' */ +static void saxreader_parse_endtag(struct saxlocator *locator) +{ + struct text_position position; + struct element *element; + HRESULT hr = S_OK; + struct name name; + + /* Skip '</' */ + saxreader_skip(locator, 2); + position = locator->buffer.position; + + saxreader_parse_qname(locator, &name); + saxreader_skipspaces(locator); + + if (!saxreader_cmp(locator, L">")) + hr = E_SAX_UNCLOSEDENDTAG; + else if (list_empty(&locator->elements)) + hr = E_SAX_UNEXPECTEDENDTAG; - uri = find_element_uri(This, URI); - hr = SAXAttributes_populate(This, nb_namespaces, namespaces, nb_attributes, attributes); - if (hr == S_OK && saxreader_has_handler(This, SAXContentHandler)) + if (SUCCEEDED(hr)) { - BSTR local; + element = LIST_ENTRY(list_head(&locator->elements), struct element, entry); - if (is_namespaces_enabled(This->saxreader)) - local = element->local; + if (!wcscmp(element->name.qname, name.qname)) + saxlocator_end_element(locator, &position, element); else - uri = local = NULL; + hr = E_SAX_ENDTAGMISMATCH; + + list_remove(&element->entry); + saxreader_free_element(element); + } + + saxreader_free_name(&name); + saxreader_set_error(locator, hr); +} + +static bool saxreader_is_xml_pi(BSTR name) +{ + if (SysStringLen(name) != 3) return false; + return (name[0] == 'x' || name[0] == 'X') + && (name[1] == 'm' || name[1] == 'M') + && (name[2] == 'l' || name[2] == 'L'); +} + +/* [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' + [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) */ +static void saxreader_parse_pi(struct saxlocator *locator) +{ + struct string_buffer buffer = { 0 }; + struct text_position position; + BSTR target, chars; + WCHAR ch; + + /* Skip '<?' */ + saxreader_skip(locator, 2); + saxreader_parse_name_strict(locator, &target); + + if (saxreader_is_xml_pi(target)) + { + SysFreeString(target); + return saxreader_set_error(locator, E_SAX_PIDECLSYNTAX); + } + + saxreader_skipspaces(locator); + position = locator->buffer.position; + + ch = *saxreader_get_ptr_noread(locator); + while (ch && locator->status == S_OK) + { + if (saxreader_cmp(locator, L"?>")) + { + chars = saxreader_string_to_bstr(locator, &buffer); + + saxlocator_pi(locator, &position, target, chars); + + SysFreeString(target); + SysFreeString(chars); + + return; + } + + saxreader_string_append(locator, &buffer, &ch, 1); + saxreader_skip(locator, 1); + ch = *saxreader_get_ptr_noread(locator); + } + + SysFreeString(target); + saxreader_set_error(locator, E_SAX_UNCLOSEDPI); +} + +/* [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' */ +static void saxreader_parse_comment(struct saxlocator *locator) +{ + struct string_buffer buffer = { 0 }; + struct text_position position; + BSTR chars; + WCHAR ch; + + /* Skip <!-- */ + saxreader_skip(locator, 4); + position = locator->buffer.position; - if (This->vbInterface) + ch = *saxreader_get_ptr_noread(locator); + while (ch && locator->status == S_OK) + { + if (saxreader_cmp(locator, L"-->")) + { + chars = saxreader_string_to_bstr(locator, &buffer); + saxlocator_comment(locator, &position, chars); + SysFreeString(chars); + return; + } + else if (saxreader_cmp(locator, L"--")) { - if (!uri) uri = This->saxreader->empty_bstr; - hr = IVBSAXContentHandler_startElement(handler->vbhandler, - &uri, &local, &element->qname, &This->IVBSAXAttributes_iface); + saxreader_set_error(locator, E_SAX_COMMENTSYNTAX); + break; } else { - hr = ISAXContentHandler_startElement(handler->handler, - uri ? uri : &empty_str, SysStringLen(uri), - local ? local : &empty_str, SysStringLen(local), - element->qname, SysStringLen(element->qname), - &This->ISAXAttributes_iface); + saxreader_string_append(locator, &buffer, &ch, 1); } - if (sax_callback_failed(This, hr)) - format_error_message_from_id(This, hr); + saxreader_skip(locator, 1); + ch = *saxreader_get_ptr_noread(locator); } + + free(buffer.data); + saxreader_set_error(locator, E_SAX_UNEXPECTED_EOF); } -static void libxmlEndElementNS( - void *ctx, - const xmlChar *localname, - const xmlChar *prefix, - const xmlChar *URI) +static bool saxreader_predefined_entity(struct saxlocator *locator, const struct text_position *position, BSTR name) { - saxlocator *This = ctx; - struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader); - element_entry *element; - const xmlChar *p; - BSTR uri, local; - HRESULT hr; + const WCHAR *value; + BSTR str; - update_position(This, FALSE); - p = This->pParserCtxt->input->cur; + if (locator->status != S_OK) + return false; - if (This->saxreader->version >= MSXML4) + if (!(value = saxreader_get_predefined_entity(name))) + return false; + + str = SysAllocString(value); + saxlocator_characters(locator, position, str); + SysFreeString(str); + + return true; +} + +static void saxreader_push_entity(struct saxlocator *locator, const struct text_position *position, + struct entity_decl *entity) +{ + struct encoded_buffer *buffer = &locator->buffer.utf16; + ULONG needed = SysStringLen(entity->value); + void *dst, *src; + size_t size; + + if (entity->visited) + return saxreader_set_error(locator, E_SAX_INFINITEREFLOOP); + + /* Squeeze entity value at current input position. Empty entities are valid. */ + if (needed) { - p--; - while(p>This->pParserCtxt->input->base && *p!='>') + if (!saxreader_array_reserve(locator, (void **)&buffer->data, &buffer->allocated, + buffer->written + needed * sizeof(WCHAR), sizeof(*buffer->data))) + { + return saxreader_set_error(locator, E_OUTOFMEMORY); + } + + if (buffer->written > buffer->cur * sizeof(WCHAR)) { - if(*p=='\n' || (*p=='\r' && *(p+1)!='\n')) - This->line--; - p--; + dst = (WCHAR *)buffer->data + buffer->cur + needed; + src = (WCHAR *)buffer->data + buffer->cur; + size = buffer->written - buffer->cur * sizeof(WCHAR); + memmove(dst, src, size); } + + dst = (WCHAR *)buffer->data + buffer->cur; + src = entity->value; + size = needed * sizeof(WCHAR); + memcpy(dst, src, size); + + buffer->written += needed * sizeof(WCHAR); + } + + entity->visited = true; + entity->remaining = needed; + entity->position = *position; + + /* Recursive referencing is explicitly detected, making sure that entities could only be linked once. */ + list_add_head(&locator->buffer.entities, &entity->input_entry); + + saxlocator_start_entity(locator, &entity->position, entity->name); +} + +/* [66] CharRef ::= '' [0-9]+ ';' | '' [0-9a-fA-F]+ ';' + [67] Reference ::= EntityRef | CharRef + [68] EntityRef ::= '&' Name ';' */ +static void saxreader_parse_reference(struct saxlocator *locator) +{ + struct string_buffer buffer = { 0 }; + struct text_position position; + struct entity_decl *entity; + BSTR str; + + if (saxreader_peek(locator, L"", 2)) + { + saxreader_parse_charref(locator, &buffer, &position); + str = saxreader_string_to_bstr(locator, &buffer); + saxlocator_characters(locator, &position, str); } - else if(*(p-1)!='>' || *(p-2)!='/') + else { - p--; - while(p-2>=This->pParserCtxt->input->base - && *(p-2)!='<' && *(p-1)!='/') + /* Skip '&' */ + saxreader_skip(locator, 1); + position = locator->buffer.position; + + saxreader_parse_name(locator, &str); + if (!saxreader_cmp(locator, L";")) + saxreader_set_error(locator, E_SAX_MISSINGSEMICOLON); + + if (!saxreader_predefined_entity(locator, &position, str)) { - if(*p=='\n' || (*p=='\r' && *(p+1)!='\n')) - This->line--; - p--; + if ((entity = saxreader_get_entity(locator, str))) + { + if (entity->unparsed) + saxreader_set_error(locator, E_SAX_UNPARSEDENTITYREF); + else if (*entity->value) + saxreader_push_entity(locator, &position, entity); + else + saxlocator_skipped_entity(locator, &position, entity->name); + } + else + { + saxlocator_skipped_entity(locator, &position, str); + } } } - This->column = 0; - for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--) - This->column++; + SysFreeString(str); +} + +struct chardata_context +{ + struct string_buffer buffer; + struct text_position position; + size_t count; + WCHAR ch; +}; - uri = find_element_uri(This, URI); - element = pop_element_ns(This); +static void saxreader_parse_characters(struct saxlocator *locator, struct chardata_context *ctxt) +{ + BSTR chars; - if (!saxreader_has_handler(This, SAXContentHandler)) + /* Normalize line breaks */ + if (ctxt->ch == '\r') { - free_attribute_values(This); - This->attr_count = 0; - free_element_entry(element); - return; - } + bool move_position = false; + + saxreader_skip(locator, 1); + ctxt->ch = *saxreader_get_ptr_noread(locator); + if (ctxt->ch == '\n') + saxreader_skip(locator, 1); + else if (ctxt->ch != '\r') + move_position = true; + + saxreader_string_append(locator, &ctxt->buffer, L"\n", 1); + chars = saxreader_string_to_bstr(locator, &ctxt->buffer); - if (is_namespaces_enabled(This->saxreader)) - local = element->local; + saxlocator_characters(locator, &ctxt->position, chars); + SysFreeString(chars); + + saxreader_shrink(locator); + + if (move_position) + ctxt->position = locator->buffer.position; + else + ctxt->position.column += (locator->buffer.consumed - ctxt->count); + + ctxt->count = locator->buffer.consumed; + } else - uri = local = NULL; + { + saxreader_string_append(locator, &ctxt->buffer, &ctxt->ch, 1); + saxreader_skip(locator, 1); + } - if (This->vbInterface) + ctxt->ch = *saxreader_get_ptr(locator); +} + +static void saxreader_parse_characters_newparser(struct saxlocator *locator, struct chardata_context *ctxt) +{ + BSTR chars; + + /* Normalize line breaks */ + if (ctxt->ch == '\r') { - if (!uri) uri = This->saxreader->empty_bstr; - hr = IVBSAXContentHandler_endElement( - handler->vbhandler, - &uri, &local, &element->qname); + bool move_position = false; + + saxreader_skip(locator, 1); + ctxt->ch = *saxreader_get_ptr_noread(locator); + if (ctxt->ch == '\n') + saxreader_skip(locator, 1); + else if (ctxt->ch != '\r') + move_position = true; + + /* Flush current block first, then new line separately */ + chars = saxreader_string_to_bstr(locator, &ctxt->buffer); + saxlocator_characters(locator, &ctxt->position, chars); + SysFreeString(chars); + + saxreader_shrink(locator); + + ctxt->position = locator->buffer.position; + ctxt->position.column = 0; + saxreader_string_append(locator, &ctxt->buffer, L"\n", 1); + chars = saxreader_string_to_bstr(locator, &ctxt->buffer); + saxlocator_characters(locator, &ctxt->position, chars); + SysFreeString(chars); + + if (move_position) + ctxt->position = locator->buffer.position; + else + ctxt->position.column += (locator->buffer.consumed - ctxt->count); + + ctxt->count = locator->buffer.consumed; } else { - hr = ISAXContentHandler_endElement( - handler->handler, - uri ? uri : &empty_str, SysStringLen(uri), - local ? local : &empty_str, SysStringLen(local), - element->qname, SysStringLen(element->qname)); + saxreader_string_append(locator, &ctxt->buffer, &ctxt->ch, 1); + saxreader_skip(locator, 1); + } + + ctxt->ch = *saxreader_get_ptr(locator); +} + +/* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */ +static void saxreader_parse_chardata(struct saxlocator *locator) +{ + struct chardata_context context = { 0 }; + BSTR chars; + + context.position = locator->buffer.position; + context.count = locator->buffer.consumed; + context.ch = *saxreader_get_ptr(locator); + + while (context.ch) + { + if (saxreader_cmp(locator, L"]]>")) + { + saxreader_set_error(locator, E_SAX_INVALID_CDATACLOSINGTAG); + break; + } + + if (context.ch == '&' || context.ch == '<') + { + if (context.buffer.count) + { + if (locator->saxreader->version >= MSXML4) + { + context.position.line = locator->buffer.position.line; + context.position.column = locator->buffer.position.column; + } + + chars = saxreader_string_to_bstr(locator, &context.buffer); + saxlocator_characters(locator, &context.position, chars); + SysFreeString(chars); + } + else + { + free(context.buffer.data); + } + return; + } + + if (locator->saxreader->version >= MSXML4) + saxreader_parse_characters_newparser(locator, &context); + else + saxreader_parse_characters(locator, &context); + } + + free(context.buffer.data); + saxreader_set_error(locator, E_SAX_UNEXPECTED_EOF); +} + +/* [18] CDSect ::= CDStart CData CDEnd + [19] CDStart ::= '<![CDATA[' + [20] CData ::= (Char* - (Char* ']]>' Char*)) + [21] CDEnd ::= ']]>' */ +static void saxreader_parse_cdata(struct saxlocator *locator) +{ + struct chardata_context context = { 0 }; + BSTR chars; + + /* Skip <![CDATA[ */ + saxreader_skip(locator, 9); + + context.position = locator->buffer.position; + context.count = locator->buffer.consumed; + context.ch = *saxreader_get_ptr(locator); + + saxlocator_start_cdata(locator, &context.position); + + while (context.ch && locator->status == S_OK) + { + if (saxreader_cmp(locator, L"]]>")) + { + /* Point to closing '>' */ + if (locator->saxreader->version >= MSXML4) + { + context.position.line = locator->buffer.position.line; + context.position.column = locator->buffer.position.column - 1; + } + + chars = saxreader_string_to_bstr(locator, &context.buffer); + saxlocator_characters(locator, &context.position, chars); + SysFreeString(chars); + + return saxlocator_end_cdata(locator, &context.position); + } + + if (locator->saxreader->version >= MSXML4) + saxreader_parse_characters_newparser(locator, &context); + else + saxreader_parse_characters(locator, &context); } - free_attribute_values(This); - This->attr_count = 0; + free(context.buffer.data); + saxreader_set_error(locator, E_SAX_UNCLOSEDCDATA); +} + +/* [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')' */ +static void saxreader_parse_mixed_contentspec(struct saxlocator *locator, struct string_buffer *buffer) +{ + BSTR name; + WCHAR ch; - if (sax_callback_failed(This, hr)) + saxreader_string_append(locator, buffer, L"#PCDATA", 7); + saxreader_skipspaces(locator); + if (saxreader_cmp(locator, L")")) { - format_error_message_from_id(This, hr); - free_element_entry(element); + saxreader_string_append(locator, buffer, L")", 1); + if (saxreader_cmp(locator, L"*")) + saxreader_string_append(locator, buffer, L"*", 1); return; } - if (is_namespaces_enabled(This->saxreader)) + ch = *saxreader_get_ptr_noread(locator); + while (ch == '|' && locator->status == S_OK) { - int i = -1; - while (iterate_endprefix_index(This, element, &i) && saxreader_has_handler(This, SAXContentHandler)) - { - if (This->vbInterface) - hr = IVBSAXContentHandler_endPrefixMapping( - handler->vbhandler, &element->ns[i].prefix); - else - hr = ISAXContentHandler_endPrefixMapping( - handler->handler, element->ns[i].prefix, SysStringLen(element->ns[i].prefix)); - - if (sax_callback_failed(This, hr)) break; - } - - if (sax_callback_failed(This, hr)) - format_error_message_from_id(This, hr); + saxreader_skip(locator, 1); + saxreader_string_append(locator, buffer, L"|", 1); + saxreader_skipspaces(locator); + saxreader_parse_name(locator, &name); + saxreader_string_append_bstr(locator, buffer, &name); + saxreader_skipspaces(locator); + ch = *saxreader_get_ptr_noread(locator); } - free_element_entry(element); + if (!saxreader_cmp(locator, L")")) + saxreader_set_error(locator, E_SAX_BADCHARINMIXEDMODEL); + else if (!saxreader_cmp(locator, L"*")) + saxreader_set_error(locator, E_SAX_MISSING_STAR); + saxreader_string_append(locator, buffer, L")*", 2); } -static void libxmlCharacters( - void *ctx, - const xmlChar *ch, - int len) -{ - saxlocator *This = ctx; - BSTR Chars; - HRESULT hr; - xmlChar *cur, *end; - BOOL lastEvent = FALSE; +static void saxreader_parse_children_contentspec(struct saxlocator *locator, struct string_buffer *buffer); - if (!saxreader_has_handler(This, SAXContentHandler)) return; +static void saxreader_parse_occurence_spec(struct saxlocator *locator, struct string_buffer *buffer) +{ + WCHAR ch; - update_position(This, FALSE); - cur = (xmlChar*)This->pParserCtxt->input->cur; - while(cur>=This->pParserCtxt->input->base && *cur!='>') + ch = *saxreader_get_ptr(locator); + if (ch == '?' || ch == '*' || ch == '+') { - if(*cur=='\n' || (*cur=='\r' && *(cur+1)!='\n')) - This->line--; - cur--; + saxreader_string_append(locator, buffer, &ch, 1); + saxreader_skip(locator, 1); } - This->column = 1; - for(; cur>=This->pParserCtxt->input->base && *cur!='\n' && *cur!='\r'; cur--) - This->column++; +} - cur = (xmlChar*)ch; - if(*(ch-1)=='\r') cur--; - end = cur; +static void saxreader_parse_child_contentspec(struct saxlocator *locator, struct string_buffer *buffer) +{ + BSTR name; - while(1) + saxreader_skipspaces(locator); + if (saxreader_cmp(locator, L"(")) { - while(end-ch<len && *end!='\r') end++; - if(end-ch==len) - { - lastEvent = TRUE; - } - else - { - *end = '\n'; - end++; - } + saxreader_string_append(locator, buffer, L"(", 1); + saxreader_skipspaces(locator); + saxreader_parse_children_contentspec(locator, buffer); + saxreader_skipspaces(locator); + } + else + { + saxreader_parse_name(locator, &name); + saxreader_string_append_bstr(locator, buffer, &name); + saxreader_parse_occurence_spec(locator, buffer); + } + saxreader_skipspaces(locator); +} - if (This->saxreader->version >= MSXML4) - { - xmlChar *p; +static void saxreader_parse_children_contentspec(struct saxlocator *locator, struct string_buffer *buffer) +{ + WCHAR ch, sep = 0; - for(p=cur; p!=end; p++) - { - if(*p=='\n') - { - This->line++; - This->column = 1; - } - else - { - This->column++; - } - } + /* TODO: limit recursion depth */ - if(!lastEvent) - This->column = 0; - } + if (locator->status != S_OK) + return; - Chars = pooled_bstr_from_xmlCharN(&This->saxreader->pool, cur, end-cur); - hr = saxreader_saxcharacters(This, Chars); + saxreader_parse_child_contentspec(locator, buffer); - if (sax_callback_failed(This, hr)) + ch = *saxreader_get_ptr(locator); + while (ch != ')' && locator->status == S_OK) + { + if (ch == ',') { - format_error_message_from_id(This, hr); - return; - } + /* Check for "Name | Name , Name" */ + if (sep == 0) sep = ch; + else if (sep != ch) + return saxreader_set_error(locator, E_SAX_INVALID_MODEL); - if (This->saxreader->version < MSXML4) - This->column += end-cur; - - if(lastEvent) - break; + saxreader_skip(locator, 1); + saxreader_string_append(locator, buffer, &ch, 1); + } + else if (ch == '|') + { + /* Check for "Name , Name | Name" */ + if (sep == 0) sep = ch; + else if (sep != ch) + return saxreader_set_error(locator, E_SAX_INVALID_MODEL); - *(end-1) = '\r'; - if(*end == '\n') + saxreader_skip(locator, 1); + saxreader_string_append(locator, buffer, &ch, 1); + } + else { - end++; - This->column++; + return saxreader_set_error(locator, E_SAX_INVALID_MODEL); } - cur = end; - if(end-ch == len) break; + saxreader_parse_child_contentspec(locator, buffer); + ch = *saxreader_get_ptr(locator); } + + saxreader_skip(locator, 1); + saxreader_string_append(locator, buffer, L")", 1); + saxreader_parse_occurence_spec(locator, buffer); } -static void libxmlSetDocumentLocator( - void *ctx, - xmlSAXLocatorPtr loc) +/* [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children + [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')' */ +static void saxreader_parse_contentspec(struct saxlocator *locator, BSTR *model) { - saxlocator *This = ctx; - struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader); - HRESULT hr = S_OK; + struct string_buffer buffer = { 0 }; - if (saxreader_has_handler(This, SAXContentHandler)) + *model = NULL; + + if (saxreader_cmp(locator, L"EMPTY")) { - if(This->vbInterface) - hr = IVBSAXContentHandler_putref_documentLocator(handler->vbhandler, - &This->IVBSAXLocator_iface); - else - hr = ISAXContentHandler_putDocumentLocator(handler->handler, &This->ISAXLocator_iface); + *model = saxreader_alloc_string(locator, L"EMPTY"); } - - if(FAILED(hr)) - format_error_message_from_id(This, hr); -} - -static void libxmlComment(void *ctx, const xmlChar *value) -{ - saxlocator *This = ctx; - struct saxlexicalhandler_iface *handler = saxreader_get_lexicalhandler(This->saxreader); - BSTR bValue; - HRESULT hr; - const xmlChar *p = This->pParserCtxt->input->cur; - - update_position(This, FALSE); - while(p-4>=This->pParserCtxt->input->base - && memcmp(p-4, "<!--", sizeof(char[4]))) + else if (saxreader_cmp(locator, L"ANY")) { - if(*p=='\n' || (*p=='\r' && *(p+1)!='\n')) - This->line--; - p--; + *model = saxreader_alloc_string(locator, L"ANY"); } + else if (saxreader_cmp(locator, L"(")) + { + saxreader_skipspaces(locator); - This->column = 0; - for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--) - This->column++; + saxreader_string_append(locator, &buffer, L"(", 1); + if (saxreader_cmp(locator, L"#PCDATA")) + saxreader_parse_mixed_contentspec(locator, &buffer); + else + saxreader_parse_children_contentspec(locator, &buffer); - if (!saxreader_has_handler(This, SAXLexicalHandler)) return; + *model = saxreader_string_to_bstr(locator, &buffer); + } + else + { + saxreader_set_error(locator, E_SAX_INVALID_MODEL); + } +} - bValue = pooled_bstr_from_xmlChar(&This->saxreader->pool, value); +/* [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>' */ +static void saxreader_parse_elementdecl(struct saxlocator *locator) +{ + BSTR name, model; - if (This->vbInterface) - hr = IVBSAXLexicalHandler_comment(handler->vbhandler, &bValue); + /* Skip <!ELEMENT */ + saxreader_skip(locator, 9); + saxreader_skip_required_spaces(locator); + saxreader_parse_name(locator, &name); + saxreader_skip_required_spaces(locator); + saxreader_parse_contentspec(locator, &model); + saxreader_skipspaces(locator); + if (saxreader_cmp(locator, L">")) + saxlocator_elementdecl(locator, name, model); else - hr = ISAXLexicalHandler_comment(handler->handler, bValue, SysStringLen(bValue)); + saxreader_set_error(locator, E_SAX_EXPECTINGTAGEND); - if(FAILED(hr)) - format_error_message_from_id(This, hr); + SysFreeString(name); + SysFreeString(model); } -static void WINAPIV libxmlFatalError(void *ctx, const char *msg, ...) +/* [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */ +static bool saxreader_is_pubidchar(WCHAR ch) { - saxlocator *This = ctx; - struct saxerrorhandler_iface *handler = saxreader_get_errorhandler(This->saxreader); - char message[1024]; - WCHAR *error; - DWORD len; - va_list args; - - if(This->ret != S_OK) { - xmlStopParser(This->pParserCtxt); - return; - } + return (ch == 0x20) || (ch == 0xd) || (ch == 0xa) || + (ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + (ch >= '-' && ch <= ';') || /* '()*+,-./:; */ + (ch == '=') || (ch == '?') || + (ch == '@') || (ch == '!') || + (ch == '#') || (ch == '$') || (ch == '%') || + (ch == '_'); +} - va_start(args, msg); - vsprintf(message, msg, args); - va_end(args); +/* [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" + [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */ +static BSTR saxreader_parse_pubidliteral(struct saxlocator *locator) +{ + struct string_buffer buffer = { 0 }; + WCHAR quote, ch; + BSTR str; - len = MultiByteToWideChar(CP_UNIXCP, 0, message, -1, NULL, 0); - error = malloc(sizeof(WCHAR) * len); - if(error) + if (!(quote = saxreader_is_quote(locator))) { - MultiByteToWideChar(CP_UNIXCP, 0, message, -1, error, len); - TRACE("fatal error for %p: %s\n", This, debugstr_w(error)); + saxreader_set_error(locator, E_SAX_MISSINGQUOTE); + return NULL; } - if (!saxreader_has_handler(This, SAXErrorHandler)) + saxreader_skip(locator, 1); + saxreader_more(locator); + + ch = *saxreader_get_ptr_noread(locator); + while (saxreader_is_pubidchar(ch) && ch != quote) { - xmlStopParser(This->pParserCtxt); - This->ret = E_FAIL; - free(error); - return; + saxreader_string_append(locator, &buffer, &ch, 1); + saxreader_skip(locator, 1); + ch = *saxreader_get_ptr_noread(locator); } - FIXME("Error handling is not compatible.\n"); - - if(This->vbInterface) + if (ch == quote) { - BSTR bstrError = SysAllocString(error); - IVBSAXErrorHandler_fatalError(handler->vbhandler, &This->IVBSAXLocator_iface, - &bstrError, E_FAIL); - SysFreeString(bstrError); + str = saxreader_string_to_bstr(locator, &buffer); + /* Skip closing quote */ + saxreader_skip(locator, 1); + return str; } - else - ISAXErrorHandler_fatalError(handler->handler, &This->ISAXLocator_iface, error, E_FAIL); - free(error); - - xmlStopParser(This->pParserCtxt); - This->ret = E_FAIL; + free(buffer.data); + saxreader_set_error(locator, E_SAX_EXPECTINGCLOSEQUOTE); + return NULL; } -/* The only reason this helper exists is that CDATA section are reported by chunks, - newlines are used as delimiter. More than that, reader even alters input data before reporting. - - This helper should be called for substring with trailing newlines. -*/ -static BSTR saxreader_get_cdata_chunk(const xmlChar *str, int len) +/* [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") */ +static BSTR saxreader_parse_systemliteral(struct saxlocator *locator) { - BSTR bstr = bstr_from_xmlCharN(str, len), ret; - WCHAR *ptr; + struct string_buffer buffer = { 0 }; + WCHAR quote, ch; - len = SysStringLen(bstr); - ptr = bstr + len - 1; - while ((*ptr == '\r' || *ptr == '\n') && ptr >= bstr) - ptr--; - - while (*++ptr) + if (!(quote = saxreader_is_quote(locator))) { - /* replace returns as: + saxreader_set_error(locator, E_SAX_MISSINGQUOTE); + return NULL; + } + + saxreader_skip(locator, 1); + saxreader_more(locator); - - "\r<char>" -> "\n<char>" - - "\r\r" -> "\r" - - "\r\n" -> "\n" - */ - if (*ptr == '\r') + ch = *saxreader_get_ptr_noread(locator); + while (ch) + { + if (ch == quote) { - if (*(ptr+1) == '\r' || *(ptr+1) == '\n') - { - /* shift tail */ - memmove(ptr, ptr+1, len-- - (ptr-bstr)); - } - else - *ptr = '\n'; + saxreader_skip(locator, 1); + return saxreader_string_to_bstr(locator, &buffer); } + saxreader_string_append(locator, &buffer, &ch, 1); + saxreader_skip(locator, 1); + ch = *saxreader_get_ptr_noread(locator); } - ret = SysAllocStringLen(bstr, len); - SysFreeString(bstr); - return ret; + free(buffer.data); + saxreader_set_error(locator, E_SAX_EXPECTINGCLOSEQUOTE); + return NULL; } -static void libxml_cdatablock(void *ctx, const xmlChar *value, int len) +/* [75] ExternalID ::= 'SYSTEM' S SystemLiteral + | 'PUBLIC' S PubidLiteral S SystemLiteral + [83] PublicID ::= 'PUBLIC' S PubidLiteral */ +static void saxreader_parse_externalid(struct saxlocator *locator, BSTR *systemid, BSTR *publicid, bool is_notation) { - const xmlChar *start, *end; - saxlocator *locator = ctx; - struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader); - HRESULT hr = S_OK; - BSTR chars; - int i; + *systemid = *publicid = NULL; - update_position(locator, FALSE); - if (saxreader_has_handler(locator, SAXLexicalHandler)) + if (saxreader_cmp(locator, L"SYSTEM")) { - if (locator->vbInterface) - hr = IVBSAXLexicalHandler_startCDATA(lexical->vbhandler); - else - hr = ISAXLexicalHandler_startCDATA(lexical->handler); - } + if (!saxreader_skip_required_spaces(locator)) + return; - if(FAILED(hr)) - { - format_error_message_from_id(locator, hr); - return; + *systemid = saxreader_parse_systemliteral(locator); } + else if (saxreader_cmp(locator, L"PUBLIC")) + { + if (!saxreader_skip_required_spaces(locator)) + return; - start = value; - end = NULL; - i = 0; + *publicid = saxreader_parse_pubidliteral(locator); - while (i < len) - { - /* scan for newlines */ - if (value[i] == '\r' || value[i] == '\n') + if (is_notation) + { + if (!saxreader_skipspaces(locator)) + return; + if (!saxreader_is_quote(locator)) + return; + } + else { - /* skip newlines/linefeeds */ - while (i < len) + if (!saxreader_skip_required_spaces(locator)) { - if (value[i] != '\r' && value[i] != '\n') break; - i++; + SysFreeString(*publicid); + *publicid = NULL; + return; } - end = &value[i]; - - /* report */ - chars = saxreader_get_cdata_chunk(start, end-start); - TRACE("(chunk %s)\n", debugstr_w(chars)); - hr = saxreader_saxcharacters(locator, chars); - SysFreeString(chars); - - start = &value[i]; - end = NULL; } - i++; - locator->column++; - } - - /* no newline chars (or last chunk) report as a whole */ - if (!end && start == value) - { - /* report */ - chars = bstr_from_xmlCharN(start, len-(start-value)); - TRACE("(%s)\n", debugstr_w(chars)); - hr = saxreader_saxcharacters(locator, chars); - SysFreeString(chars); - } - if (saxreader_has_handler(locator, SAXLexicalHandler)) - { - if (locator->vbInterface) - hr = IVBSAXLexicalHandler_endCDATA(lexical->vbhandler); - else - hr = ISAXLexicalHandler_endCDATA(lexical->handler); + *systemid = saxreader_parse_systemliteral(locator); } - - if(FAILED(hr)) - format_error_message_from_id(locator, hr); } -static void libxml_pi(void *ctx, const xmlChar *_target, const xmlChar *_data) +/* Read EntityRef without much validation */ +static void saxreader_parse_entityvalue_entityref(struct saxlocator *locator, struct string_buffer *buffer) { - saxlocator *locator = ctx; - struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(locator->saxreader); - BSTR target, data; - HRESULT hr = S_OK; - - update_position(locator, FALSE); - if (!saxreader_has_handler(locator, SAXContentHandler)) return; - - target = pooled_bstr_from_xmlChar(&locator->saxreader->pool, _target); - data = pooled_bstr_from_xmlChar(&locator->saxreader->pool, _data); - - if (locator->vbInterface) - hr = IVBSAXContentHandler_processingInstruction(handler->vbhandler, &target, &data); - else - hr = ISAXContentHandler_processingInstruction(handler->handler, target, SysStringLen(target), - data, SysStringLen(data)); + WCHAR ch; - if (FAILED(hr)) - format_error_message_from_id(locator, hr); -} - -static void libxml_internalsubset(void *ctx, const xmlChar *_name, const xmlChar *external_id, const xmlChar *system_id) -{ - saxlocator *locator = ctx; - struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader); - BSTR name, pubid, sysid; - HRESULT hr; + saxreader_string_append(locator, buffer, L"&", 1); + saxreader_skip(locator, 1); - update_position(locator, FALSE); - if (!saxreader_has_handler(locator, SAXLexicalHandler)) return; + /* Check for empty name */ + ch = *saxreader_get_ptr_noread(locator); + if (!saxreader_is_namechar(ch)) + saxreader_set_error(locator, E_SAX_BADCHARINENTREF); - name = pooled_bstr_from_xmlChar(&locator->saxreader->pool, _name); - pubid = pooled_bstr_from_xmlChar(&locator->saxreader->pool, external_id); - sysid = pooled_bstr_from_xmlChar(&locator->saxreader->pool, system_id); + while (saxreader_is_namechar(ch)) + { + saxreader_string_append(locator, buffer, &ch, 1); + saxreader_skip(locator, 1); + ch = *saxreader_get_ptr_noread(locator); + } - if (locator->vbInterface) - hr = IVBSAXLexicalHandler_startDTD(lexical->vbhandler, &name, &pubid, &sysid); + if (saxreader_cmp(locator, L";")) + saxreader_string_append(locator, buffer, L";", 1); else - hr = ISAXLexicalHandler_startDTD(lexical->handler, name, SysStringLen(name), - pubid, SysStringLen(pubid), sysid, SysStringLen(sysid)); - - if (FAILED(hr)) - format_error_message_from_id(locator, hr); + saxreader_set_error(locator, E_SAX_BADCHARINENTREF); } -static void libxml_externalsubset(void *ctx, const xmlChar *name, const xmlChar *external_id, const xmlChar *system_id) +static void saxreader_entity_add_part(struct saxlocator *locator, struct entity_decl *decl, + struct string_buffer *buffer, bool reference) { - saxlocator *locator = ctx; - struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader); - HRESULT hr = S_OK; + struct entity_part *part; - update_position(locator, FALSE); - if (!saxreader_has_handler(locator, SAXLexicalHandler)) return; - - if (locator->vbInterface) - hr = IVBSAXLexicalHandler_endDTD(lexical->vbhandler); - else - hr = ISAXLexicalHandler_endDTD(lexical->handler); + if (!buffer->count) + return; - if (FAILED(hr)) - format_error_message_from_id(locator, hr); -} + if (!saxreader_array_reserve(locator, (void **)&decl->content.parts, &decl->content.capacity, + decl->content.count + 1, sizeof(*decl->content.parts))) + { + return; + } + part = &decl->content.parts[decl->content.count++]; -static xmlParserInputPtr libxmlresolveentity(void *ctx, const xmlChar *publicid, const xmlChar *systemid) -{ - FIXME("entity resolving not implemented, %s, %s\n", publicid, systemid); - return xmlSAX2ResolveEntity(ctx, publicid, systemid); + part->value = saxreader_string_to_bstr(locator, buffer); + part->reference = reference; } -/*** IVBSAXLocator interface ***/ -/*** IUnknown methods ***/ -static HRESULT WINAPI ivbsaxlocator_QueryInterface(IVBSAXLocator* iface, REFIID riid, void **ppvObject) +/* [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' + | "'" ([^%&'] | PEReference | Reference)* "'" */ +static void saxreader_parse_entityvalue(struct saxlocator *locator, struct entity_decl *decl) { - saxlocator *This = impl_from_IVBSAXLocator( iface ); + struct string_buffer buffer = { 0 }, part = { 0 }; + struct text_position position; + WCHAR quote, ch; + size_t count; - TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject); - - *ppvObject = NULL; - - if ( IsEqualGUID( riid, &IID_IUnknown ) || - IsEqualGUID( riid, &IID_IDispatch) || - IsEqualGUID( riid, &IID_IVBSAXLocator )) - { - *ppvObject = iface; - } - else if ( IsEqualGUID( riid, &IID_IVBSAXAttributes )) + if (!(quote = saxreader_is_quote(locator))) { - *ppvObject = &This->IVBSAXAttributes_iface; - } - else - { - FIXME("interface %s not implemented\n", debugstr_guid(riid)); - return E_NOINTERFACE; + saxreader_set_error(locator, E_SAX_MISSINGQUOTE); + return; } - IVBSAXLocator_AddRef( iface ); + saxreader_skip(locator, 1); - return S_OK; -} + /* Only character references are resolved. Entity references are parsed + lazily, checking for valid name characters but not for a valid name. + Referenced entities do not have to be already declared, and are not expanded + if they are declared. */ -static ULONG WINAPI ivbsaxlocator_AddRef(IVBSAXLocator* iface) -{ - saxlocator *This = impl_from_IVBSAXLocator( iface ); - TRACE("%p\n", This ); - return ISAXLocator_AddRef(&This->ISAXLocator_iface); -} + saxreader_more(locator); + ch = *saxreader_get_ptr_noread(locator); + while (ch != quote) + { + if (saxreader_peek(locator, L"", 2)) + { + count = buffer.count; + saxreader_parse_charref(locator, &buffer, &position); + saxreader_string_append(locator, &part, buffer.data + count, buffer.count - count); + } + else if (saxreader_peek(locator, L"&", 1)) + { + saxreader_entity_add_part(locator, decl, &part, false); -static ULONG WINAPI ivbsaxlocator_Release(IVBSAXLocator* iface) -{ - saxlocator *This = impl_from_IVBSAXLocator( iface ); - return ISAXLocator_Release(&This->ISAXLocator_iface); -} + count = buffer.count; + saxreader_parse_entityvalue_entityref(locator, &buffer); + /* Skip markup in &name; */ + if (buffer.count - count > 2) + saxreader_string_append(locator, &part, buffer.data + count + 1, buffer.count - count - 2); -/*** IDispatch methods ***/ -static HRESULT WINAPI ivbsaxlocator_GetTypeInfoCount( IVBSAXLocator *iface, UINT* pctinfo ) -{ - saxlocator *This = impl_from_IVBSAXLocator( iface ); + saxreader_entity_add_part(locator, decl, &part, true); + } + else + { + saxreader_string_append(locator, &buffer, &ch, 1); + saxreader_string_append(locator, &part, &ch, 1); + saxreader_skip(locator, 1); + } + ch = *saxreader_get_ptr_noread(locator); + } - TRACE("(%p)->(%p)\n", This, pctinfo); + if (ch == quote) + { + saxreader_entity_add_part(locator, decl, &part, false); + decl->value = saxreader_string_to_bstr(locator, &buffer); - *pctinfo = 1; + /* Skip closing quote */ + saxreader_skip(locator, 1); + return; + } - return S_OK; + free(part.data); + free(buffer.data); + saxreader_set_error(locator, E_SAX_EXPECTINGCLOSEQUOTE); } -static HRESULT WINAPI ivbsaxlocator_GetTypeInfo( - IVBSAXLocator *iface, - UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo ) +static void saxreader_release_entity(struct entity_decl *entity) { - TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo); - - return get_typeinfo(IVBSAXLocator_tid, ppTInfo); + SysFreeString(entity->name); + SysFreeString(entity->sysid); + SysFreeString(entity->value); + free(entity); } -static HRESULT WINAPI ivbsaxlocator_GetIDsOfNames( - IVBSAXLocator *iface, - REFIID riid, - LPOLESTR* rgszNames, - UINT cNames, - LCID lcid, - DISPID* rgDispId) +/* [70] EntityDecl ::= GEDecl | PEDecl + [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>' + [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>' + [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?) + [74] PEDef ::= EntityValue | ExternalID + [76] NDataDecl ::= S 'NDATA' S Name */ +static void saxreader_parse_entitydecl(struct saxlocator *locator) { - ITypeInfo *typeinfo; - HRESULT hr; + BSTR notation = NULL, pubid = NULL; + struct string_buffer buffer = { 0 }; + struct entity_decl *decl; + bool pe, undeclared; - TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, - lcid, rgDispId); + /* Skip <!ENTITY */ + saxreader_skip(locator, 8); + saxreader_skip_required_spaces(locator); - if(!rgszNames || cNames == 0 || !rgDispId) - return E_INVALIDARG; + if ((pe = saxreader_cmp(locator, L"%"))) + saxreader_skip_required_spaces(locator); - hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo); - if(SUCCEEDED(hr)) + if (!(decl = saxreader_calloc(locator, 1, sizeof(*decl)))) + return; + + saxreader_parse_name_strict(locator, &decl->name); + saxreader_skip_required_spaces(locator); + + if (pe) { - hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); - ITypeInfo_Release(typeinfo); - } + saxreader_string_append(locator, &buffer, L"%", 1); + saxreader_string_append_bstr(locator, &buffer, &decl->name); + decl->name = saxreader_string_to_bstr(locator, &buffer); + undeclared = saxreader_get_entity(locator, decl->name) == NULL; - return hr; -} + if (saxreader_is_quote(locator)) + { + saxreader_parse_entityvalue(locator, decl); + saxreader_skipspaces(locator); + if (saxreader_cmp(locator, L">")) + { + if (undeclared) + saxlocator_internal_entitydecl(locator, decl->name, decl->value); + } + else + { + saxreader_set_error(locator, E_SAX_EXPECTINGTAGEND); + } + } + else + { + saxreader_parse_externalid(locator, &decl->sysid, &pubid, false); + saxreader_skipspaces(locator); + if (saxreader_cmp(locator, L">")) + { + if (undeclared) + saxlocator_external_entitydecl(locator, decl->name, pubid, decl->sysid); + } + else + { + saxreader_set_error(locator, E_SAX_EXPECTINGTAGEND); + } + } + } + else + { + undeclared = saxreader_get_entity(locator, decl->name) == NULL; -static HRESULT WINAPI ivbsaxlocator_Invoke( - IVBSAXLocator *iface, - DISPID dispIdMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS* pDispParams, - VARIANT* pVarResult, - EXCEPINFO* pExcepInfo, - UINT* puArgErr) -{ - ITypeInfo *typeinfo; - HRESULT hr; + if (saxreader_is_quote(locator)) + { + saxreader_parse_entityvalue(locator, decl); + saxreader_skipspaces(locator); + if (saxreader_cmp(locator, L">")) + { + if (undeclared) + saxlocator_internal_entitydecl(locator, decl->name, decl->value); + } + else + { + saxreader_set_error(locator, E_SAX_EXPECTINGTAGEND); + } + } + else + { + saxreader_parse_externalid(locator, &decl->sysid, &pubid, false); - TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid), - lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + saxreader_more(locator); + if (!saxreader_peek(locator, L">", 1)) + saxreader_skip_required_spaces(locator); - hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo); - if(SUCCEEDED(hr)) - { - hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); - ITypeInfo_Release(typeinfo); + if (saxreader_cmp(locator, L"NDATA")) + { + decl->unparsed = true; + saxreader_skip_required_spaces(locator); + saxreader_parse_name(locator, ¬ation); + saxreader_skipspaces(locator); + if (saxreader_cmp(locator, L">")) + { + if (undeclared) + saxlocator_unparsed_entitydecl(locator, decl->name, pubid, decl->sysid, notation); + } + else + { + saxreader_set_error(locator, E_SAX_EXPECTINGTAGEND); + } + } + else + { + saxreader_skipspaces(locator); + if (saxreader_cmp(locator, L">")) + { + if (undeclared) + saxlocator_external_entitydecl(locator, decl->name, pubid, decl->sysid); + } + else + { + saxreader_set_error(locator, E_SAX_EXPECTINGTAGEND); + } + } + } } - return hr; -} - -/*** IVBSAXLocator methods ***/ -static HRESULT WINAPI ivbsaxlocator_get_columnNumber( - IVBSAXLocator* iface, - int *pnColumn) -{ - saxlocator *This = impl_from_IVBSAXLocator( iface ); - return ISAXLocator_getColumnNumber(&This->ISAXLocator_iface, pnColumn); -} + if (undeclared) + list_add_tail(&locator->dtd.entities, &decl->entry); + else + saxreader_release_entity(decl); -static HRESULT WINAPI ivbsaxlocator_get_lineNumber( - IVBSAXLocator* iface, - int *pnLine) -{ - saxlocator *This = impl_from_IVBSAXLocator( iface ); - return ISAXLocator_getLineNumber(&This->ISAXLocator_iface, pnLine); + SysFreeString(pubid); + SysFreeString(notation); } -static HRESULT WINAPI ivbsaxlocator_get_publicId(IVBSAXLocator* iface, BSTR *ret) +/* [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' */ +static BSTR saxreader_parse_notation_type(struct saxlocator *locator) { - saxlocator *This = impl_from_IVBSAXLocator( iface ); - const WCHAR *publicidW; - HRESULT hr; + struct string_buffer buffer = { 0 }; + BSTR name, value = NULL; - TRACE("(%p)->(%p)\n", This, ret); + /* Skip NOTATION */ + saxreader_skip(locator, 8); + saxreader_skip_required_spaces(locator); + if (!saxreader_cmp(locator, L"(")) + { + saxreader_set_error(locator, E_SAX_MISSING_PAREN); + return NULL; + } - if (!ret) - return E_POINTER; + saxreader_string_append(locator, &buffer, L"NOTATION (", 10); + while (locator->status == S_OK && !value) + { + saxreader_skipspaces(locator); + saxreader_parse_name_strict(locator, &name); + saxreader_string_append_bstr(locator, &buffer, &name); + saxreader_skipspaces(locator); - *ret = NULL; - hr = ISAXLocator_getPublicId(&This->ISAXLocator_iface, &publicidW); - if (FAILED(hr)) - return hr; + if (saxreader_cmp(locator, L")")) + { + saxreader_string_append(locator, &buffer, L")", 1); + value = saxreader_string_to_bstr(locator, &buffer); + } + else if (saxreader_cmp(locator, L"|")) + saxreader_string_append(locator, &buffer, L"|", 1); + else + saxreader_set_error(locator, E_SAX_BADCHARINENUMERATION); + } - return return_bstr(publicidW, ret); + return value; } -static HRESULT WINAPI ivbsaxlocator_get_systemId(IVBSAXLocator* iface, BSTR *ret) +/* [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' */ +static BSTR saxreader_parse_enumeration_type(struct saxlocator *locator) { - saxlocator *This = impl_from_IVBSAXLocator( iface ); - const WCHAR *systemidW; - HRESULT hr; + struct string_buffer buffer = { 0 }; + BSTR token, value = NULL; - TRACE("(%p)->(%p)\n", This, ret); + /* Skip '(' */ + saxreader_skip(locator, 1); + saxreader_string_append(locator, &buffer, L"(", 1); - if (!ret) - return E_POINTER; + while (locator->status == S_OK && !value) + { + saxreader_skipspaces(locator); + saxreader_parse_nmtoken(locator, &token); + saxreader_string_append_bstr(locator, &buffer, &token); + saxreader_skipspaces(locator); - *ret = NULL; - hr = ISAXLocator_getSystemId(&This->ISAXLocator_iface, &systemidW); - if (FAILED(hr)) - return hr; + if (saxreader_cmp(locator, L")")) + { + saxreader_string_append(locator, &buffer, L")", 1); + value = saxreader_string_to_bstr(locator, &buffer); + } + else if (saxreader_cmp(locator, L"|")) + saxreader_string_append(locator, &buffer, L"|", 1); + else + saxreader_set_error(locator, E_SAX_BADCHARINENUMERATION); + } - return return_bstr(systemidW, ret); + return value; +} + +/* [54] AttType ::= StringType | TokenizedType | EnumeratedType + [55] StringType ::= 'CDATA' + [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' + | 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS' + [57] EnumeratedType ::= NotationType | Enumeration */ +static BSTR saxreader_parse_atttype(struct saxlocator *locator) +{ + /* TODO: this could reuse strings */ + + if (saxreader_cmp(locator, L"CDATA")) + return saxreader_alloc_string(locator, L"CDATA"); + if (saxreader_cmp(locator, L"IDREFS")) + return saxreader_alloc_string(locator, L"IDREFS"); + if (saxreader_cmp(locator, L"IDREF")) + return saxreader_alloc_string(locator, L"IDREF"); + if (saxreader_cmp(locator, L"ID")) + return saxreader_alloc_string(locator, L"ID"); + if (saxreader_cmp(locator, L"ENTITY")) + return saxreader_alloc_string(locator, L"ENTITY"); + if (saxreader_cmp(locator, L"ENTITIES")) + return saxreader_alloc_string(locator, L"ENTITIES"); + if (saxreader_cmp(locator, L"NMTOKENS")) + return saxreader_alloc_string(locator, L"NMTOKENS"); + if (saxreader_cmp(locator, L"NMTOKEN")) + return saxreader_alloc_string(locator, L"NMTOKEN"); + + if (saxreader_peek(locator, L"NOTATION", 8)) + return saxreader_parse_notation_type(locator); + else if (saxreader_peek(locator, L"(", 1)) + return saxreader_parse_enumeration_type(locator); + + saxreader_set_error(locator, E_SAX_INVALID_TYPE); + return NULL; } -static const struct IVBSAXLocatorVtbl VBSAXLocatorVtbl = -{ - ivbsaxlocator_QueryInterface, - ivbsaxlocator_AddRef, - ivbsaxlocator_Release, - ivbsaxlocator_GetTypeInfoCount, - ivbsaxlocator_GetTypeInfo, - ivbsaxlocator_GetIDsOfNames, - ivbsaxlocator_Invoke, - ivbsaxlocator_get_columnNumber, - ivbsaxlocator_get_lineNumber, - ivbsaxlocator_get_publicId, - ivbsaxlocator_get_systemId -}; - -/*** ISAXLocator interface ***/ -/*** IUnknown methods ***/ -static HRESULT WINAPI isaxlocator_QueryInterface(ISAXLocator* iface, REFIID riid, void **ppvObject) +/* [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue) */ +static BSTR saxreader_parse_defaultdecl(struct saxlocator *locator, BSTR *value) { - saxlocator *This = impl_from_ISAXLocator( iface ); + BSTR ret = NULL; - TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject ); + *value = NULL; - *ppvObject = NULL; + if (saxreader_cmp(locator, L"#REQUIRED")) + return saxreader_alloc_string(locator, L"#REQUIRED"); + if (saxreader_cmp(locator, L"#IMPLIED")) + return saxreader_alloc_string(locator, L"#IMPLIED"); - if ( IsEqualGUID( riid, &IID_IUnknown ) || - IsEqualGUID( riid, &IID_ISAXLocator )) - { - *ppvObject = iface; - } - else if ( IsEqualGUID( riid, &IID_ISAXAttributes )) - { - *ppvObject = &This->ISAXAttributes_iface; - } - else + if (saxreader_cmp(locator, L"#FIXED")) { - WARN("interface %s not implemented\n", debugstr_guid(riid)); - return E_NOINTERFACE; + ret = saxreader_alloc_string(locator, L"#FIXED"); + saxreader_skip_required_spaces(locator); } + *value = saxreader_parse_attvalue(locator); - ISAXLocator_AddRef( iface ); - - return S_OK; + return ret; } -static ULONG WINAPI isaxlocator_AddRef(ISAXLocator* iface) +/* [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>' + [53] AttDef ::= S Name S AttType S DefaultDecl */ +static void saxreader_parse_attlistdecl(struct saxlocator *locator) { - saxlocator *This = impl_from_ISAXLocator( iface ); - ULONG ref = InterlockedIncrement( &This->ref ); - TRACE("%p, refcount %lu.\n", iface, ref); - return ref; -} + struct attlist_decl *decl; -static ULONG WINAPI isaxlocator_Release( - ISAXLocator* iface) -{ - saxlocator *This = impl_from_ISAXLocator( iface ); - ULONG ref = InterlockedDecrement( &This->ref ); + if (!(decl = saxreader_calloc(locator, 1, sizeof(*decl)))) + return; + list_add_tail(&locator->dtd.attr_decls, &decl->entry); - TRACE("%p, refcount %ld.\n", iface, ref ); + /* Skip <!ATTLIST */ + saxreader_skip(locator, 9); + saxreader_skip_required_spaces(locator); + saxreader_parse_name(locator, &decl->name); + saxreader_skipspaces(locator); - if (!ref) + while (locator->status == S_OK) { - element_entry *element, *element2; - int index; + struct attlist_attr *attr; - SysFreeString(This->publicId); - SysFreeString(This->systemId); - SysFreeString(This->namespaceUri); + if (saxreader_cmp(locator, L">")) + break; - for(index = 0; index < This->attr_alloc_count; index++) + if (!saxreader_array_reserve(locator, (void **)&decl->attributes, &decl->capacity, + decl->count + 1, sizeof(*decl->attributes))) { - SysFreeString(This->attributes[index].szLocalname); - SysFreeString(This->attributes[index].szValue); - SysFreeString(This->attributes[index].szQName); + break; } - free(This->attributes); + attr = &decl->attributes[decl->count++]; - /* element stack */ - LIST_FOR_EACH_ENTRY_SAFE(element, element2, &This->elements, element_entry, entry) - { - list_remove(&element->entry); - free_element_entry(element); - } + saxreader_parse_qname(locator, &attr->name); + saxreader_skip_required_spaces(locator); + attr->type = saxreader_parse_atttype(locator); + saxreader_skip_required_spaces(locator); + attr->valuetype = saxreader_parse_defaultdecl(locator, &attr->value); + + if (saxreader_cmp(locator, L">")) + break; - ISAXXMLReader_Release(&This->saxreader->ISAXXMLReader_iface); - free(This); + saxreader_skip_required_spaces(locator); } - return ref; + saxlocator_attribute_decl(locator, decl); } -/*** ISAXLocator methods ***/ -static HRESULT WINAPI isaxlocator_getColumnNumber( - ISAXLocator* iface, - int *pnColumn) +/* [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>' */ +static void saxreader_parse_notationdecl(struct saxlocator *locator) { - saxlocator *This = impl_from_ISAXLocator( iface ); + BSTR name = NULL, sysid = NULL, pubid = NULL; - *pnColumn = This->column; - return S_OK; + /* Skip <!NOTATION */ + saxreader_skip(locator, 10); + saxreader_skip_required_spaces(locator); + saxreader_parse_name_strict(locator, &name); + saxreader_shrink(locator); + + saxreader_skip_required_spaces(locator); + saxreader_parse_externalid(locator, &sysid, &pubid, true); + saxreader_skipspaces(locator); + + if (!saxreader_cmp(locator, L">")) + saxreader_set_error(locator, E_SAX_EXPECTINGTAGEND); + + saxlocator_notationdecl(locator, &locator->buffer.position, name, pubid, sysid); + + SysFreeString(name); + SysFreeString(sysid); + SysFreeString(pubid); } -static HRESULT WINAPI isaxlocator_getLineNumber( - ISAXLocator* iface, - int *pnLine) +/* [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment */ +static void saxreader_parse_markupdecl(struct saxlocator *locator) { - saxlocator *This = impl_from_ISAXLocator( iface ); - - *pnLine = This->line; - return S_OK; + saxreader_more(locator); + if (saxreader_peek(locator, L"<!--", 4)) + saxreader_parse_comment(locator); + else if (saxreader_peek(locator, L"<!", 2)) + { + if (saxreader_peek(locator, L"<!ELEMENT", 9)) + saxreader_parse_elementdecl(locator); + else if (saxreader_peek(locator, L"<!ENTITY", 8)) + saxreader_parse_entitydecl(locator); + else if (saxreader_peek(locator, L"<!ATTLIST", 9)) + saxreader_parse_attlistdecl(locator); + else if (saxreader_peek(locator, L"<!NOTATION", 10)) + saxreader_parse_notationdecl(locator); + else + saxreader_set_error(locator, E_SAX_BADDECLNAME); + } + else if (saxreader_peek(locator, L"<?", 2)) + saxreader_parse_pi(locator); + else + saxreader_set_error(locator, E_SAX_BADCHARINDTD); } -static HRESULT WINAPI isaxlocator_getPublicId( - ISAXLocator* iface, - const WCHAR ** ppwchPublicId) +/* [69] PEReference ::= '%' Name ';' */ +static void saxreader_parse_pe_reference(struct saxlocator *locator) { - BSTR publicId; - saxlocator *This = impl_from_ISAXLocator( iface ); + struct string_buffer buffer = { 0 }; + struct text_position position; + struct entity_decl *entity; + BSTR name; - SysFreeString(This->publicId); + /* Skip '%' */ + saxreader_skip(locator, 1); + position = locator->buffer.position; - publicId = bstr_from_xmlChar(xmlSAX2GetPublicId(This->pParserCtxt)); - if(SysStringLen(publicId)) - This->publicId = publicId; - else - { - SysFreeString(publicId); - This->publicId = NULL; - } + saxreader_parse_name(locator, &name); + if (!saxreader_cmp(locator, L";")) + saxreader_set_error(locator, E_SAX_MISSINGSEMICOLON); - *ppwchPublicId = This->publicId; - return S_OK; + saxreader_string_append(locator, &buffer, L"%", 1); + saxreader_string_append_bstr(locator, &buffer, &name); + name = saxreader_string_to_bstr(locator, &buffer); + + if ((entity = saxreader_get_entity(locator, name))) + saxreader_push_entity(locator, &locator->buffer.position, entity); + else + saxlocator_skipped_entity(locator, &position, name); } -static HRESULT WINAPI isaxlocator_getSystemId( - ISAXLocator* iface, - const WCHAR ** ppwchSystemId) +/* [28a] DeclSep ::= PEReference | S + [28b] intSubset ::= (markupdecl | DeclSep)* + [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment */ +static void saxreader_parse_intsubset(struct saxlocator *locator) { - BSTR systemId; - saxlocator *This = impl_from_ISAXLocator( iface ); + WCHAR *ptr; - SysFreeString(This->systemId); + /* Opening '[' bracket already skipped */ + saxreader_skipspaces(locator); - systemId = bstr_from_xmlChar(xmlSAX2GetSystemId(This->pParserCtxt)); - if(SysStringLen(systemId)) - This->systemId = systemId; - else + while (locator->status == S_OK) { - SysFreeString(systemId); - This->systemId = NULL; - } + if (saxreader_cmp(locator, L"]")) + return; - *ppwchSystemId = This->systemId; - return S_OK; + // TODO: conditional blocks should be supported too + + if (saxreader_peek(locator, L"<!", 2) || saxreader_peek(locator, L"<?", 2)) + saxreader_parse_markupdecl(locator); + else if (saxreader_peek(locator, L"%", 1)) + saxreader_parse_pe_reference(locator); + else + saxreader_set_error(locator, E_SAX_BADCHARINDTD); + + saxreader_skipspaces(locator); + saxreader_shrink(locator); + ptr = saxreader_get_ptr(locator); + if (!*ptr) + saxreader_set_error(locator, E_SAX_UNEXPECTED_EOF); + } } -static const struct ISAXLocatorVtbl SAXLocatorVtbl = +/* [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' */ +static void saxreader_parse_doctype(struct saxlocator *locator) { - isaxlocator_QueryInterface, - isaxlocator_AddRef, - isaxlocator_Release, - isaxlocator_getColumnNumber, - isaxlocator_getLineNumber, - isaxlocator_getPublicId, - isaxlocator_getSystemId -}; + BSTR name, sysid, pubid; -static HRESULT SAXLocator_create(saxreader *reader, saxlocator **ppsaxlocator, BOOL vbInterface) -{ - saxlocator *locator; + if (locator->saxreader->features & ProhibitDTD) + return saxreader_set_error(locator, E_SAX_INVALIDATROOTLEVEL); - locator = malloc(sizeof(*locator)); - if( !locator ) - return E_OUTOFMEMORY; + /* Skip <!DOCTYPE */ + saxreader_skip(locator, 9); + saxreader_skip_required_spaces(locator); + saxreader_parse_name(locator, &name); - 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; - locator->vbInterface = vbInterface; + saxreader_skipspaces(locator); + saxreader_parse_externalid(locator, &sysid, &pubid, false); - locator->saxreader = reader; - ISAXXMLReader_AddRef(&reader->ISAXXMLReader_iface); + saxreader_skipspaces(locator); + saxreader_shrink(locator); - locator->pParserCtxt = NULL; - locator->publicId = NULL; - locator->systemId = NULL; - locator->line = reader->version < MSXML4 ? 0 : 1; - locator->column = 0; - locator->ret = S_OK; - if (locator->saxreader->version >= MSXML6) - locator->namespaceUri = SysAllocString(L"http://www.w3.org/2000/xmlns/"); - else - locator->namespaceUri = SysAllocStringLen(NULL, 0); - if(!locator->namespaceUri) + if (saxreader_cmp(locator, L"[")) { - ISAXXMLReader_Release(&reader->ISAXXMLReader_iface); - free(locator); - return E_OUTOFMEMORY; + saxlocator_startdtd(locator, name, pubid, sysid); + saxreader_parse_intsubset(locator); + saxreader_skipspaces(locator); + if (!saxreader_cmp(locator, L">")) + saxreader_set_error(locator, E_SAX_EXPECTINGTAGEND); } - - locator->attr_alloc_count = 8; - locator->attr_count = 0; - locator->attributes = calloc(locator->attr_alloc_count, sizeof(*locator->attributes)); - if(!locator->attributes) + else if (saxreader_cmp(locator, L">")) { - ISAXXMLReader_Release(&reader->ISAXXMLReader_iface); - SysFreeString(locator->namespaceUri); - free(locator); - return E_OUTOFMEMORY; + saxlocator_startdtd(locator, name, pubid, sysid); } - list_init(&locator->elements); - - *ppsaxlocator = locator; + if (sysid) + FIXME("External subset is not supported.\n"); - TRACE("returning %p\n", *ppsaxlocator); + saxlocator_enddtd(locator); - return S_OK; + SysFreeString(sysid); + SysFreeString(pubid); } -/*** SAXXMLReader internal functions ***/ -static HRESULT internal_parseBuffer(saxreader *This, const char *buffer, int size, BOOL vbInterface) +static enum xmlencoding saxreader_match_encoding(const char *data, size_t size, size_t *bom) { - xmlCharEncoding encoding = XML_CHAR_ENCODING_NONE; - xmlChar *enc_name = NULL; - saxlocator *locator; - HRESULT hr; + const BYTE *b = (const BYTE *)data; - TRACE("(%p)->(%p %d)\n", This, buffer, size); + *bom = 0; - hr = SAXLocator_create(This, &locator, vbInterface); - if (FAILED(hr)) - return hr; + if (size < 4) + return XML_ENCODING_UNKNOWN; - if (size >= 4) + if (b[0] == 0 && b[1] == 0 && b[2] == 0 && b[3] == '<') + return XML_ENCODING_UCS4BE; + if (b[0] == '<' && b[1] == 0 && b[2] == 0 && b[3] == 0) + return XML_ENCODING_UCS4LE; + if (b[0] == '<' && b[1] == 0 && b[2] == '?' && b[3] == 0) + return XML_ENCODING_UTF16LE; + if (b[0] == '<' && b[1] == 0 && b[2] && b[2] != '?') + return XML_ENCODING_UTF16LE; + if (b[0] == 0 && b[1] == '<' && b[2] == 0 && b[3] == '?') + return XML_ENCODING_UTF16BE; + if (b[0] == '<' && b[1] == '?' && b[2] == 'x' && b[3] == 'm') + return XML_ENCODING_UTF8; + if (b[0] == '<' && b[1] && b[1] != '?') + return XML_ENCODING_UTF8; + + if (b[0] == 0xef && b[1] == 0xbb && b[2] == 0xbf) { - encoding = xmlDetectCharEncoding((xmlChar*)buffer, 4); - enc_name = (xmlChar*)xmlGetCharEncodingName(encoding); - TRACE("detected encoding: %s\n", enc_name); + *bom = 3; + return XML_ENCODING_UTF8; } - /* if libxml2 detection failed try to guess */ - if (encoding == XML_CHAR_ENCODING_NONE) + if (b[0] == 0xfe && b[1] == 0xff) { - const WCHAR *ptr = (WCHAR*)buffer; - /* an xml declaration with optional encoding will still be handled by the parser */ - if ((size >= 2) && *ptr == '<' && ptr[1] != '?') - { - enc_name = (xmlChar*)xmlGetCharEncodingName(XML_CHAR_ENCODING_UTF16LE); - encoding = XML_CHAR_ENCODING_UTF16LE; - } + *bom = 2; + return XML_ENCODING_UTF16BE; } - else if (encoding == XML_CHAR_ENCODING_UTF8) - enc_name = (xmlChar*)xmlGetCharEncodingName(encoding); - else - enc_name = NULL; - locator->pParserCtxt = xmlCreateMemoryParserCtxt(buffer, size); - if (!locator->pParserCtxt) + if (b[0] == 0xff && b[1] == 0xfe) { - ISAXLocator_Release(&locator->ISAXLocator_iface); - return E_FAIL; + *bom = 2; + return XML_ENCODING_UTF16LE; } - if (enc_name) + return XML_ENCODING_UNKNOWN; +} + +static void saxreader_detect_encoding(struct saxlocator *locator) +{ + struct encoded_buffer *utf16 = &locator->buffer.utf16; + struct encoded_buffer *raw = &locator->buffer.raw; + enum xmlencoding encoding; + size_t bom = 0, size; + ULONG read = 0; + HRESULT hr; + + /* In principle there is no need to read as much to detect encoding, + but experiments show that application never gets smaller input buffer. */ + + if (!saxreader_reserve_buffer(locator, raw, locator->buffer.chunk_size)) + return; + + if (FAILED(hr = ISequentialStream_Read(locator->stream, raw->data, locator->buffer.chunk_size, &read))) + return saxreader_set_error(locator, hr); + if (!read) + return saxreader_set_error(locator, E_SAX_MISSINGROOT); + + raw->written = read; + + encoding = saxreader_match_encoding(raw->data, read, &bom); + + if (encoding == XML_ENCODING_UNKNOWN) { - locator->pParserCtxt->encoding = xmlStrdup(enc_name); - if (encoding == XML_CHAR_ENCODING_UTF16LE) { - TRACE("switching to %s\n", enc_name); - xmlSwitchEncoding(locator->pParserCtxt, encoding); - } + WARN("Failed to detect document encoding.\n"); + return saxreader_set_error(locator, E_SAX_INVALIDENCODING); } - xmlFree(locator->pParserCtxt->sax); - locator->pParserCtxt->sax = &locator->saxreader->sax; - locator->pParserCtxt->userData = locator; + locator->buffer.encoding = encoding; + locator->buffer.converter = convert_get_converter(encoding); + locator->buffer.code_page = convert_get_codepage(encoding); - This->isParsing = TRUE; - if(xmlParseDocument(locator->pParserCtxt) == -1 && locator->ret == S_OK) - hr = E_FAIL; - else - hr = locator->ret; - This->isParsing = FALSE; + TRACE("detected encoding %s\n", saxreader_get_encoding_name(encoding)); + + size = read - bom; - if(locator->pParserCtxt) + if (encoding == XML_ENCODING_UTF16LE) { - locator->pParserCtxt->sax = NULL; - xmlFreeParserCtxt(locator->pParserCtxt); - locator->pParserCtxt = NULL; - } + if (!saxreader_reserve_buffer(locator, utf16, size)) + return; - ISAXLocator_Release(&locator->ISAXLocator_iface); - return hr; + memcpy(utf16->data + utf16->written, raw->data + bom, size); + utf16->written += size; + + encoded_buffer_cleanup(raw); + } + else if (bom) + { + memmove(raw->data, raw->data + bom, size); + raw->written -= bom; + } } -static HRESULT internal_parseStream(saxreader *This, ISequentialStream *stream, BOOL vbInterface) +static HRESULT saxreader_parse_stream(struct saxreader *reader, ISequentialStream *stream, bool vbInterface) { - saxlocator *locator; + struct saxlocator *locator; HRESULT hr; - ULONG dataRead; - char data[2048]; - int ret; - dataRead = 0; - hr = ISequentialStream_Read(stream, data, sizeof(data), &dataRead); - if(FAILED(hr)) return hr; - - hr = SAXLocator_create(This, &locator, vbInterface); - if(FAILED(hr)) return hr; + if (FAILED(hr = saxlocator_create(reader, stream, vbInterface, &locator))) + return hr; - locator->pParserCtxt = xmlCreatePushParserCtxt( - &locator->saxreader->sax, locator, - data, dataRead, NULL); - if(!locator->pParserCtxt) + while (locator->state != SAX_PARSER_EOF) { - ISAXLocator_Release(&locator->ISAXLocator_iface); - return E_FAIL; - } + if (locator->status != S_OK) + { + saxreader_fatal_error(locator); + break; + } - This->isParsing = TRUE; + switch (locator->state) + { + case SAX_PARSER_START: + saxreader_detect_encoding(locator); + locator->state = SAX_PARSER_XML_DECL; + break; + case SAX_PARSER_XML_DECL: + saxreader_parse_xmldecl(locator); + locator->buffer.switched_encoding = true; + saxlocator_put_document_locator(locator); + saxlocator_start_document(locator); + locator->state = SAX_PARSER_MISC; + break; + case SAX_PARSER_MISC: + case SAX_PARSER_EPILOG: + saxreader_skipspaces(locator); + saxreader_more(locator); - do { - dataRead = 0; - hr = ISequentialStream_Read(stream, data, sizeof(data), &dataRead); - if (FAILED(hr) || !dataRead) break; + if (saxreader_peek(locator, L"<", 1)) + { + if (saxreader_peek(locator, L"<?", 2)) + { + saxreader_parse_pi(locator); + break; + } + else if (saxreader_peek(locator, L"<!--", 4)) + { + saxreader_parse_comment(locator); + break; + } + else if (locator->state == SAX_PARSER_MISC) + { + if (saxreader_peek(locator, L"<!DOCTYPE", 9)) + { + saxreader_parse_doctype(locator); + break; + } + } + } - ret = xmlParseChunk(locator->pParserCtxt, data, dataRead, 0); - hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret; - }while(hr == S_OK); + if (locator->state == SAX_PARSER_EPILOG) + { + locator->state = SAX_PARSER_EOF; + saxlocator_end_document(locator); + } + else + { + locator->state = SAX_PARSER_START_TAG; + } + break; + case SAX_PARSER_START_TAG: + saxreader_parse_starttag(locator); + if (list_empty(&locator->elements)) + locator->state = SAX_PARSER_EPILOG; + else + locator->state = SAX_PARSER_CONTENT; + break; + case SAX_PARSER_END_TAG: + saxreader_parse_endtag(locator); + if (list_empty(&locator->elements)) + locator->state = SAX_PARSER_EPILOG; + else + locator->state = SAX_PARSER_CONTENT; + break; + case SAX_PARSER_CONTENT: + saxreader_more(locator); - if(SUCCEEDED(hr)) - { - ret = xmlParseChunk(locator->pParserCtxt, data, 0, 1); - hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret; + if (saxreader_peek(locator, L"<", 1)) + { + if (saxreader_peek(locator, L"</", 2)) + { + locator->state = SAX_PARSER_END_TAG; + } + else if (saxreader_peek(locator, L"<?", 2)) + { + saxreader_parse_pi(locator); + locator->state = SAX_PARSER_CONTENT; + } + else if (saxreader_peek(locator, L"<!--", 4)) + { + saxreader_parse_comment(locator); + locator->state = SAX_PARSER_CONTENT; + } + else if (saxreader_peek(locator, L"<![CDATA[", 9)) + { + locator->state = SAX_PARSER_CDATA; + } + else + { + locator->state = SAX_PARSER_START_TAG; + } + } + else if (saxreader_peek(locator, L"&", 1)) + { + saxreader_parse_reference(locator); + } + else + { + saxreader_parse_chardata(locator); + } + break; + case SAX_PARSER_CDATA: + saxreader_parse_cdata(locator); + locator->state = SAX_PARSER_CONTENT; + break; + default: + locator->state = SAX_PARSER_EOF; + } } - - This->isParsing = FALSE; - - xmlFreeParserCtxt(locator->pParserCtxt); - locator->pParserCtxt = NULL; + hr = locator->status; ISAXLocator_Release(&locator->ISAXLocator_iface); + return hr; } -static HRESULT internal_parse( - saxreader* This, - VARIANT varInput, - BOOL vbInterface) +static HRESULT saxreader_parse(struct saxreader *reader, VARIANT input, bool vbInterface) { + ISequentialStream *stream; HRESULT hr; - TRACE("(%p)->(%s)\n", This, debugstr_variant(&varInput)); + TRACE("%p, %s.\n", reader, debugstr_variant(&input)); - /* Dispose of the BSTRs in the pool from a prior run, if any. */ - free_bstr_pool(&This->pool); - - switch(V_VT(&varInput)) + switch (V_VT(&input)) { case VT_BSTR: case VT_BSTR|VT_BYREF: { - BSTR str = V_ISBYREF(&varInput) ? *V_BSTRREF(&varInput) : V_BSTR(&varInput); - hr = internal_parseBuffer(This, (const char*)str, lstrlenW(str)*sizeof(WCHAR), vbInterface); + BSTR str = V_ISBYREF(&input) ? *V_BSTRREF(&input) : V_BSTR(&input); + + if (FAILED(hr = stream_wrapper_create((const void *)str, SysStringByteLen(str), &stream))) + return hr; + hr = saxreader_parse_stream(reader, stream, vbInterface); + ISequentialStream_Release(stream); break; } - case VT_ARRAY|VT_UI1: { - void *pSAData; + case VT_ARRAY|VT_UI1: + { LONG lBound, uBound; - ULONG dataRead; - - hr = SafeArrayGetLBound(V_ARRAY(&varInput), 1, &lBound); - if(hr != S_OK) break; - hr = SafeArrayGetUBound(V_ARRAY(&varInput), 1, &uBound); - if(hr != S_OK) break; - dataRead = (uBound-lBound)*SafeArrayGetElemsize(V_ARRAY(&varInput)); - hr = SafeArrayAccessData(V_ARRAY(&varInput), &pSAData); - if(hr != S_OK) break; - hr = internal_parseBuffer(This, pSAData, dataRead, vbInterface); - SafeArrayUnaccessData(V_ARRAY(&varInput)); + ULONG size; + void *data; + + if (FAILED(hr = SafeArrayGetLBound(V_ARRAY(&input), 1, &lBound))) return hr; + if (FAILED(hr = SafeArrayGetUBound(V_ARRAY(&input), 1, &uBound))) return hr; + if (FAILED(hr = SafeArrayAccessData(V_ARRAY(&input), &data))) return hr; + + size = (uBound - lBound + 1) * SafeArrayGetElemsize(V_ARRAY(&input)); + if (SUCCEEDED(hr = stream_wrapper_create(data, size, &stream))) + { + hr = saxreader_parse_stream(reader, stream, vbInterface); + ISequentialStream_Release(stream); + } + SafeArrayUnaccessData(V_ARRAY(&input)); break; } case VT_UNKNOWN: - case VT_DISPATCH: { + case VT_DISPATCH: + { ISequentialStream *stream = NULL; IXMLDOMDocument *xmlDoc; - if (!V_UNKNOWN(&varInput)) + if (!V_UNKNOWN(&input)) return E_INVALIDARG; - if(IUnknown_QueryInterface(V_UNKNOWN(&varInput), - &IID_IXMLDOMDocument, (void**)&xmlDoc) == S_OK) + if (IUnknown_QueryInterface(V_UNKNOWN(&input), &IID_IXMLDOMDocument, (void**)&xmlDoc) == S_OK) { BSTR bstrData; IXMLDOMDocument_get_xml(xmlDoc, &bstrData); - hr = internal_parseBuffer(This, (const char*)bstrData, - SysStringByteLen(bstrData), vbInterface); + stream_wrapper_create(bstrData, SysStringByteLen(bstrData), &stream); + hr = saxreader_parse_stream(reader, stream, vbInterface); + ISequentialStream_Release(stream); IXMLDOMDocument_Release(xmlDoc); SysFreeString(bstrData); break; } /* try base interface first */ - IUnknown_QueryInterface(V_UNKNOWN(&varInput), &IID_ISequentialStream, (void**)&stream); + IUnknown_QueryInterface(V_UNKNOWN(&input), &IID_ISequentialStream, (void **)&stream); if (!stream) /* this should never happen if IStream is implemented properly, but just in case */ - IUnknown_QueryInterface(V_UNKNOWN(&varInput), &IID_IStream, (void**)&stream); + IUnknown_QueryInterface(V_UNKNOWN(&input), &IID_IStream, (void **)&stream); - if(stream) + if (stream) { - hr = internal_parseStream(This, stream, vbInterface); + hr = saxreader_parse_stream(reader, stream, vbInterface); ISequentialStream_Release(stream); } else @@ -2682,7 +5456,7 @@ static HRESULT internal_parse( break; } default: - WARN("vt %d not implemented\n", V_VT(&varInput)); + WARN("input type %d is not supported\n", V_VT(&input)); hr = E_INVALIDARG; } @@ -2691,19 +5465,33 @@ static HRESULT internal_parse( static HRESULT internal_vbonDataAvailable(void *obj, char *ptr, DWORD len) { - saxreader *This = obj; + struct saxreader *reader = obj; + ISequentialStream *stream; + HRESULT hr; - return internal_parseBuffer(This, ptr, len, TRUE); + if (SUCCEEDED(hr = stream_wrapper_create(ptr, len, &stream))) + { + hr = saxreader_parse_stream(reader, stream, true); + ISequentialStream_Release(stream); + } + return hr; } static HRESULT internal_onDataAvailable(void *obj, char *ptr, DWORD len) { - saxreader *This = obj; + struct saxreader *reader = obj; + ISequentialStream *stream; + HRESULT hr; - return internal_parseBuffer(This, ptr, len, FALSE); + if (SUCCEEDED(hr = stream_wrapper_create(ptr, len, &stream))) + { + hr = saxreader_parse_stream(reader, stream, false); + ISequentialStream_Release(stream); + } + return hr; } -static HRESULT internal_parseURL(saxreader *reader, const WCHAR *url, BOOL vbInterface) +static HRESULT saxreader_parse_url(struct saxreader *reader, const WCHAR *url, bool vbInterface) { IMoniker *mon; bsc_t *bsc; @@ -2715,25 +5503,26 @@ static HRESULT internal_parseURL(saxreader *reader, const WCHAR *url, BOOL vbInt return E_INVALIDARG; hr = create_moniker_from_url(url, &mon); - if(FAILED(hr)) + if (FAILED(hr)) return hr; - if(vbInterface) hr = bind_url(mon, internal_vbonDataAvailable, reader, &bsc); + if (vbInterface) hr = bind_url(mon, internal_vbonDataAvailable, reader, &bsc); else hr = bind_url(mon, internal_onDataAvailable, reader, &bsc); IMoniker_Release(mon); - if(FAILED(hr)) + if (FAILED(hr)) return hr; return detach_bsc(bsc); } -static HRESULT saxreader_put_handler_from_variant(saxreader *This, enum saxhandler_type type, const VARIANT *v, BOOL vb) +static HRESULT saxreader_put_handler_from_variant(struct saxreader *reader, enum saxhandler_type type, + const VARIANT *v, bool vb) { const IID *riid; if (V_VT(v) == VT_EMPTY) - return saxreader_put_handler(This, type, NULL, vb); + return saxreader_put_handler(reader, type, NULL, vb); switch (type) { @@ -2761,7 +5550,7 @@ static HRESULT saxreader_put_handler_from_variant(saxreader *This, enum saxhandl if (FAILED(hr)) return hr; } - saxreader_put_handler(This, type, handler, vb); + saxreader_put_handler(reader, type, handler, vb); if (handler) IUnknown_Release(handler); break; } @@ -2773,120 +5562,112 @@ static HRESULT saxreader_put_handler_from_variant(saxreader *This, enum saxhandl return S_OK; } -static HRESULT internal_putProperty( - saxreader* This, - const WCHAR *prop, - VARIANT value, - BOOL vbInterface) +static HRESULT saxreader_put_property(struct saxreader *reader, const WCHAR *prop, VARIANT value, bool vbInterface) { VARIANT *v; - TRACE("(%p)->(%s %s)\n", This, debugstr_w(prop), debugstr_variant(&value)); + TRACE("%p, %s, %s.\n", reader, debugstr_w(prop), debugstr_variant(&value)); - if (This->isParsing) return E_FAIL; + if (reader->isParsing) return E_FAIL; v = V_VT(&value) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(&value) : &value; - if(!memcmp(prop, PropertyDeclHandlerW, sizeof(PropertyDeclHandlerW))) - return saxreader_put_handler_from_variant(This, SAXDeclHandler, v, vbInterface); - if(!memcmp(prop, PropertyLexicalHandlerW, sizeof(PropertyLexicalHandlerW))) - return saxreader_put_handler_from_variant(This, SAXLexicalHandler, v, vbInterface); + if (!wcscmp(prop, L"http://xml.org/sax/properties/declaration-handler")) + return saxreader_put_handler_from_variant(reader, SAXDeclHandler, v, vbInterface); - if(!memcmp(prop, L"max-xml-size", sizeof(L"max-xml-size"))) + if (!wcscmp(prop, L"http://xml.org/sax/properties/lexical-handler")) + return saxreader_put_handler_from_variant(reader, SAXLexicalHandler, v, vbInterface); + + if (!wcscmp(prop, L"max-xml-size")) { if (V_VT(v) == VT_I4 && V_I4(v) == 0) return S_OK; - FIXME("(%p)->(%s): max-xml-size unsupported\n", This, debugstr_variant(v)); + FIXME("(%p)->(%s): max-xml-size unsupported\n", reader, debugstr_variant(v)); return E_NOTIMPL; } - if(!memcmp(prop, L"max-element-depth", sizeof(L"max-element-depth"))) + if (!wcscmp(prop, L"max-element-depth")) { if (V_VT(v) == VT_I4 && V_I4(v) == 0) return S_OK; - FIXME("(%p)->(%s): max-element-depth unsupported\n", This, debugstr_variant(v)); + FIXME("(%p)->(%s): max-element-depth unsupported\n", reader, debugstr_variant(v)); return E_NOTIMPL; } - FIXME("(%p)->(%s:%s): unsupported property\n", This, debugstr_w(prop), debugstr_variant(v)); + FIXME("(%p)->(%s:%s): unsupported property\n", reader, debugstr_w(prop), debugstr_variant(v)); - if(!memcmp(prop, L"charset", sizeof(L"charset"))) + if (!wcscmp(prop, L"charset")) return E_NOTIMPL; - if(!memcmp(prop, PropertyDomNodeW, sizeof(PropertyDomNodeW))) + if (!wcscmp(prop, L"http://xml.org/sax/properties/dom-node")) return E_FAIL; - if(!memcmp(prop, L"input-source", sizeof(L"input-source"))) + if (!wcscmp(prop, L"input-source")) return E_NOTIMPL; - if(!memcmp(prop, L"schema-declaration-handler", sizeof(L"schema-declaration-handler"))) + if (!wcscmp(prop, L"schema-declaration-handler")) return E_NOTIMPL; - if(!memcmp(prop, L"xmldecl-encoding", sizeof(L"xmldecl-encoding"))) + if (!wcscmp(prop, L"xmldecl-encoding")) return E_FAIL; - if(!memcmp(prop, L"xmldecl-standalone", sizeof(L"xmldecl-standalone"))) + if (!wcscmp(prop, L"xmldecl-standalone")) return E_FAIL; - if(!memcmp(prop, L"xmldecl-version", sizeof(L"xmldecl-version"))) + if (!wcscmp(L"xmldecl-version", prop)) return E_FAIL; return E_INVALIDARG; } -static HRESULT internal_getProperty(const saxreader* This, const WCHAR *prop, VARIANT *value, BOOL vb) +static HRESULT saxreader_get_property(const struct saxreader *reader, const WCHAR *prop, VARIANT *value, bool vb) { - TRACE("(%p)->(%s)\n", This, debugstr_w(prop)); - if (!value) return E_POINTER; - if (!memcmp(PropertyLexicalHandlerW, prop, sizeof(PropertyLexicalHandlerW))) + if (!wcscmp(prop, L"http://xml.org/sax/properties/lexical-handler")) { - V_VT(value) = VT_UNKNOWN; - saxreader_get_handler(This, SAXLexicalHandler, vb, (void**)&V_UNKNOWN(value)); + V_VT(value) = vb ? VT_DISPATCH : VT_UNKNOWN; + saxreader_get_handler(reader, SAXLexicalHandler, vb, (void**)&V_UNKNOWN(value)); return S_OK; } - if (!memcmp(PropertyDeclHandlerW, prop, sizeof(PropertyDeclHandlerW))) + if (!wcscmp(prop, L"http://xml.org/sax/properties/declaration-handler")) { - V_VT(value) = VT_UNKNOWN; - saxreader_get_handler(This, SAXDeclHandler, vb, (void**)&V_UNKNOWN(value)); + V_VT(value) = vb ? VT_DISPATCH : VT_UNKNOWN; + saxreader_get_handler(reader, SAXDeclHandler, vb, (void**)&V_UNKNOWN(value)); return S_OK; } - if (!memcmp(L"xmldecl-version", prop, sizeof(L"xmldecl-version"))) + if (!wcscmp(prop, L"xmldecl-version")) { V_VT(value) = VT_BSTR; - V_BSTR(value) = SysAllocString(This->xmldecl_version); - return S_OK; + return return_bstr(reader->xmldecl_version, &V_BSTR(value)); } - FIXME("(%p)->(%s) unsupported property\n", This, debugstr_w(prop)); + FIXME("(%p)->(%s) unsupported property\n", reader, debugstr_w(prop)); return E_NOTIMPL; } -/*** IVBSAXXMLReader interface ***/ -/*** IUnknown methods ***/ -static HRESULT WINAPI saxxmlreader_QueryInterface(IVBSAXXMLReader* iface, REFIID riid, void **ppvObject) +static HRESULT WINAPI saxxmlreader_QueryInterface(IVBSAXXMLReader *iface, REFIID riid, void **obj) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); - TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject ); + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); - *ppvObject = NULL; + *obj = NULL; - if ( IsEqualGUID( riid, &IID_IUnknown ) || - IsEqualGUID( riid, &IID_IDispatch ) || - IsEqualGUID( riid, &IID_IVBSAXXMLReader )) + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IDispatch) || + IsEqualGUID(riid, &IID_IVBSAXXMLReader)) { - *ppvObject = iface; + *obj = iface; } - else if( IsEqualGUID( riid, &IID_ISAXXMLReader )) + else if (IsEqualGUID(riid, &IID_ISAXXMLReader)) { - *ppvObject = &This->ISAXXMLReader_iface; + *obj = &reader->ISAXXMLReader_iface; } - else if (dispex_query_interface(&This->dispex, riid, ppvObject)) + else if (dispex_query_interface(&reader->dispex, riid, obj)) { - return *ppvObject ? S_OK : E_NOINTERFACE; + return *obj ? S_OK : E_NOINTERFACE; } else { @@ -2894,34 +5675,31 @@ static HRESULT WINAPI saxxmlreader_QueryInterface(IVBSAXXMLReader* iface, REFIID return E_NOINTERFACE; } - IVBSAXXMLReader_AddRef( iface ); + IVBSAXXMLReader_AddRef(iface); return S_OK; } -static ULONG WINAPI saxxmlreader_AddRef(IVBSAXXMLReader* iface) +static ULONG WINAPI saxxmlreader_AddRef(IVBSAXXMLReader *iface) { - saxreader *reader = impl_from_IVBSAXXMLReader(iface); - LONG refcount = InterlockedIncrement(&reader->ref); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + LONG refcount = InterlockedIncrement(&reader->refcount); - TRACE("%p refcount %lu.\n", iface, refcount); + TRACE("%p, refcount %lu.\n", iface, refcount); return refcount; } -static ULONG WINAPI saxxmlreader_Release( - IVBSAXXMLReader* iface) +static ULONG WINAPI saxxmlreader_Release(IVBSAXXMLReader *iface) { - saxreader *reader = impl_from_IVBSAXXMLReader(iface); - LONG refcount = InterlockedDecrement(&reader->ref); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + LONG refcount = InterlockedDecrement(&reader->refcount); - TRACE("%p refcount %lu.\n", iface, refcount); + TRACE("%p, refcount %lu.\n", iface, refcount); if (!refcount) { - int i; - - for (i = 0; i < SAXHandler_Last; i++) + for (int i = 0; i < ARRAYSIZE(reader->saxhandlers); ++i) { struct saxanyhandler_iface *saxiface = &reader->saxhandlers[i].u.anyhandler; @@ -2934,7 +5712,6 @@ static ULONG WINAPI saxxmlreader_Release( SysFreeString(reader->xmldecl_version); SysFreeString(reader->empty_bstr); - free_bstr_pool(&reader->pool); free(reader); } @@ -2942,209 +5719,150 @@ static ULONG WINAPI saxxmlreader_Release( return refcount; } -/*** IDispatch ***/ -static HRESULT WINAPI saxxmlreader_GetTypeInfoCount( IVBSAXXMLReader *iface, UINT* pctinfo ) +static HRESULT WINAPI saxxmlreader_GetTypeInfoCount(IVBSAXXMLReader *iface, UINT *count) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return IDispatchEx_GetTypeInfoCount(&reader->dispex.IDispatchEx_iface, count); } -static HRESULT WINAPI saxxmlreader_GetTypeInfo( - IVBSAXXMLReader *iface, - UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo ) +static HRESULT WINAPI saxxmlreader_GetTypeInfo(IVBSAXXMLReader *iface, UINT index, LCID lcid, ITypeInfo **ti) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, - iTInfo, lcid, ppTInfo); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return IDispatchEx_GetTypeInfo(&reader->dispex.IDispatchEx_iface, index, lcid, ti); } -static HRESULT WINAPI saxxmlreader_GetIDsOfNames( - IVBSAXXMLReader *iface, - REFIID riid, - LPOLESTR* rgszNames, - UINT cNames, - LCID lcid, - DISPID* rgDispId) +static HRESULT WINAPI saxxmlreader_GetIDsOfNames(IVBSAXXMLReader *iface, REFIID riid, LPOLESTR *names, + UINT count, LCID lcid, DISPID *dispid) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, - riid, rgszNames, cNames, lcid, rgDispId); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return IDispatchEx_GetIDsOfNames(&reader->dispex.IDispatchEx_iface, riid, names, count, lcid, dispid); } -static HRESULT WINAPI saxxmlreader_Invoke( - IVBSAXXMLReader *iface, - DISPID dispIdMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS* pDispParams, - VARIANT* pVarResult, - EXCEPINFO* pExcepInfo, - UINT* puArgErr) +static HRESULT WINAPI saxxmlreader_Invoke(IVBSAXXMLReader *iface, DISPID dispid, REFIID riid, + LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *ei, + UINT *argerr) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, - dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return IDispatchEx_Invoke(&reader->dispex.IDispatchEx_iface, dispid, riid, lcid, flags, params, result, ei, argerr); } -/*** IVBSAXXMLReader methods ***/ -static HRESULT WINAPI saxxmlreader_getFeature( - IVBSAXXMLReader* iface, - BSTR feature_name, - VARIANT_BOOL *value) +static HRESULT WINAPI saxxmlreader_getFeature(IVBSAXXMLReader *iface, BSTR name, VARIANT_BOOL *value) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return ISAXXMLReader_getFeature(&This->ISAXXMLReader_iface, feature_name, value); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return ISAXXMLReader_getFeature(&reader->ISAXXMLReader_iface, name, value); } -static HRESULT WINAPI saxxmlreader_putFeature( - IVBSAXXMLReader* iface, - BSTR feature_name, - VARIANT_BOOL value) +static HRESULT WINAPI saxxmlreader_putFeature(IVBSAXXMLReader *iface, BSTR name, VARIANT_BOOL value) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return ISAXXMLReader_putFeature(&This->ISAXXMLReader_iface, feature_name, value); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return ISAXXMLReader_putFeature(&reader->ISAXXMLReader_iface, name, value); } -static HRESULT WINAPI saxxmlreader_getProperty( - IVBSAXXMLReader* iface, - BSTR prop, - VARIANT *value) +static HRESULT WINAPI saxxmlreader_getProperty(IVBSAXXMLReader *iface, BSTR name, VARIANT *value) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return internal_getProperty(This, prop, value, TRUE); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_w(name), value); + + return saxreader_get_property(reader, name, value, true); } -static HRESULT WINAPI saxxmlreader_putProperty( - IVBSAXXMLReader* iface, - BSTR pProp, - VARIANT value) +static HRESULT WINAPI saxxmlreader_putProperty(IVBSAXXMLReader *iface, BSTR name, VARIANT value) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return internal_putProperty(This, pProp, value, TRUE); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + + TRACE("%p, %s, %s.\n", iface, debugstr_w(name), debugstr_variant(&value)); + + return saxreader_put_property(reader, name, value, true); } -static HRESULT WINAPI saxxmlreader_get_entityResolver( - IVBSAXXMLReader* iface, - IVBSAXEntityResolver **resolver) +static HRESULT WINAPI saxxmlreader_get_entityResolver(IVBSAXXMLReader *iface, IVBSAXEntityResolver **resolver) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return saxreader_get_handler(This, SAXEntityResolver, TRUE, (void**)resolver); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return saxreader_get_handler(reader, SAXEntityResolver, true, (void **)resolver); } static HRESULT WINAPI saxxmlreader_putref_entityResolver(IVBSAXXMLReader *iface, IVBSAXEntityResolver *resolver) { - saxreader *reader = impl_from_IVBSAXXMLReader(iface); - - TRACE("%p, %p.\n", iface, resolver); - - return saxreader_put_handler(reader, SAXEntityResolver, resolver, TRUE); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return saxreader_put_handler(reader, SAXEntityResolver, resolver, true); } -static HRESULT WINAPI saxxmlreader_get_contentHandler( - IVBSAXXMLReader* iface, - IVBSAXContentHandler **handler) +static HRESULT WINAPI saxxmlreader_get_contentHandler(IVBSAXXMLReader *iface, IVBSAXContentHandler **handler) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return saxreader_get_handler(This, SAXContentHandler, TRUE, (void**)handler); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return saxreader_get_handler(reader, SAXContentHandler, true, (void **)handler); } static HRESULT WINAPI saxxmlreader_putref_contentHandler(IVBSAXXMLReader *iface, IVBSAXContentHandler *handler) { - saxreader *reader = impl_from_IVBSAXXMLReader(iface); - - TRACE("%p, %p.\n", iface, handler); - - return saxreader_put_handler(reader, SAXContentHandler, handler, TRUE); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return saxreader_put_handler(reader, SAXContentHandler, handler, true); } -static HRESULT WINAPI saxxmlreader_get_dtdHandler( - IVBSAXXMLReader* iface, - IVBSAXDTDHandler **handler) +static HRESULT WINAPI saxxmlreader_get_dtdHandler(IVBSAXXMLReader *iface, IVBSAXDTDHandler **handler) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return saxreader_get_handler(This, SAXDTDHandler, TRUE, (void**)handler); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return saxreader_get_handler(reader, SAXDTDHandler, true, (void **)handler); } static HRESULT WINAPI saxxmlreader_putref_dtdHandler(IVBSAXXMLReader *iface, IVBSAXDTDHandler *handler) { - saxreader *reader = impl_from_IVBSAXXMLReader(iface); - - TRACE("%p, %p.\n", iface, handler); - - return saxreader_put_handler(reader, SAXDTDHandler, handler, TRUE); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return saxreader_put_handler(reader, SAXDTDHandler, handler, true); } -static HRESULT WINAPI saxxmlreader_get_errorHandler( - IVBSAXXMLReader* iface, - IVBSAXErrorHandler **handler) +static HRESULT WINAPI saxxmlreader_get_errorHandler(IVBSAXXMLReader *iface, IVBSAXErrorHandler **handler) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return saxreader_get_handler(This, SAXErrorHandler, TRUE, (void**)handler); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return saxreader_get_handler(reader, SAXErrorHandler, true, (void **)handler); } static HRESULT WINAPI saxxmlreader_putref_errorHandler(IVBSAXXMLReader *iface, IVBSAXErrorHandler *handler) { - saxreader *reader = impl_from_IVBSAXXMLReader(iface); - - TRACE("%p, %p.\n", iface, handler); - - return saxreader_put_handler(reader, SAXErrorHandler, handler, TRUE); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return saxreader_put_handler(reader, SAXErrorHandler, handler, true); } -static HRESULT WINAPI saxxmlreader_get_baseURL( - IVBSAXXMLReader* iface, - BSTR *pBaseUrl) +static HRESULT WINAPI saxxmlreader_get_baseURL(IVBSAXXMLReader *iface, BSTR *url) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); + FIXME("%p, %p stub\n", iface, url); - FIXME("(%p)->(%p) stub\n", This, pBaseUrl); return E_NOTIMPL; } -static HRESULT WINAPI saxxmlreader_put_baseURL( - IVBSAXXMLReader* iface, - BSTR pBaseUrl) +static HRESULT WINAPI saxxmlreader_put_baseURL(IVBSAXXMLReader *iface, BSTR url) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return ISAXXMLReader_putBaseURL(&This->ISAXXMLReader_iface, pBaseUrl); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return ISAXXMLReader_putBaseURL(&reader->ISAXXMLReader_iface, url); } -static HRESULT WINAPI saxxmlreader_get_secureBaseURL( - IVBSAXXMLReader* iface, - BSTR *pSecureBaseUrl) +static HRESULT WINAPI saxxmlreader_get_secureBaseURL(IVBSAXXMLReader *iface, BSTR *url) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); + FIXME("%p, %p stub\n", iface, url); - FIXME("(%p)->(%p) stub\n", This, pSecureBaseUrl); return E_NOTIMPL; } -static HRESULT WINAPI saxxmlreader_put_secureBaseURL( - IVBSAXXMLReader* iface, - BSTR secureBaseUrl) +static HRESULT WINAPI saxxmlreader_put_secureBaseURL(IVBSAXXMLReader *iface, BSTR url) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return ISAXXMLReader_putSecureBaseURL(&This->ISAXXMLReader_iface, secureBaseUrl); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return ISAXXMLReader_putSecureBaseURL(&reader->ISAXXMLReader_iface, url); } -static HRESULT WINAPI saxxmlreader_parse( - IVBSAXXMLReader* iface, - VARIANT varInput) +static HRESULT WINAPI saxxmlreader_parse(IVBSAXXMLReader *iface, VARIANT input) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return internal_parse(This, varInput, TRUE); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return saxreader_parse(reader, input, true); } -static HRESULT WINAPI saxxmlreader_parseURL( - IVBSAXXMLReader* iface, - BSTR url) +static HRESULT WINAPI saxxmlreader_parseURL(IVBSAXXMLReader *iface, BSTR url) { - saxreader *This = impl_from_IVBSAXXMLReader( iface ); - return internal_parseURL(This, url, TRUE); + struct saxreader *reader = impl_from_IVBSAXXMLReader(iface); + return saxreader_parse_url(reader, url, true); } -static const struct IVBSAXXMLReaderVtbl VBSAXXMLReaderVtbl = +static const struct IVBSAXXMLReaderVtbl vbsaxxmlreadervtbl = { saxxmlreader_QueryInterface, saxxmlreader_AddRef, @@ -3173,63 +5891,54 @@ static const struct IVBSAXXMLReaderVtbl VBSAXXMLReaderVtbl = saxxmlreader_parseURL }; -/*** ISAXXMLReader interface ***/ -/*** IUnknown methods ***/ -static HRESULT WINAPI isaxxmlreader_QueryInterface(ISAXXMLReader* iface, REFIID riid, void **ppvObject) +static HRESULT WINAPI isaxxmlreader_QueryInterface(ISAXXMLReader *iface, REFIID riid, void **obj) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return IVBSAXXMLReader_QueryInterface(&This->IVBSAXXMLReader_iface, riid, ppvObject); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return IVBSAXXMLReader_QueryInterface(&reader->IVBSAXXMLReader_iface, riid, obj); } -static ULONG WINAPI isaxxmlreader_AddRef(ISAXXMLReader* iface) +static ULONG WINAPI isaxxmlreader_AddRef(ISAXXMLReader *iface) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return IVBSAXXMLReader_AddRef(&This->IVBSAXXMLReader_iface); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return IVBSAXXMLReader_AddRef(&reader->IVBSAXXMLReader_iface); } -static ULONG WINAPI isaxxmlreader_Release(ISAXXMLReader* iface) +static ULONG WINAPI isaxxmlreader_Release(ISAXXMLReader *iface) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return IVBSAXXMLReader_Release(&This->IVBSAXXMLReader_iface); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return IVBSAXXMLReader_Release(&reader->IVBSAXXMLReader_iface); } -/*** ISAXXMLReader methods ***/ -static HRESULT WINAPI isaxxmlreader_getFeature( - ISAXXMLReader* iface, - const WCHAR *feature_name, - VARIANT_BOOL *value) +static HRESULT WINAPI isaxxmlreader_getFeature(ISAXXMLReader *iface, const WCHAR *name, VARIANT_BOOL *value) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - saxreader_feature feature; + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + enum saxreader_feature feature; - TRACE("(%p)->(%s %p)\n", This, debugstr_w(feature_name), value); + TRACE("%p, %s, %p.\n", iface, debugstr_w(name), value); - feature = get_saxreader_feature(feature_name); + feature = get_saxreader_feature(name); - if (This->version < MSXML4 && (feature == ExhaustiveErrors || feature == SchemaValidation)) + if (reader->version < MSXML4 && (feature == ExhaustiveErrors || feature == SchemaValidation)) return E_INVALIDARG; if (feature == Namespaces || feature == NamespacePrefixes || feature == ExhaustiveErrors || feature == SchemaValidation) - return get_feature_value(This, feature, value); + return get_feature_value(reader, feature, value); - FIXME("(%p)->(%s %p) stub\n", This, debugstr_w(feature_name), value); + FIXME("%p, %s, %p stub\n", iface, debugstr_w(name), value); return E_NOTIMPL; } -static HRESULT WINAPI isaxxmlreader_putFeature( - ISAXXMLReader* iface, - const WCHAR *feature_name, - VARIANT_BOOL value) +static HRESULT WINAPI isaxxmlreader_putFeature(ISAXXMLReader *iface, const WCHAR *name, VARIANT_BOOL value) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - saxreader_feature feature; + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + enum saxreader_feature feature; - TRACE("(%p)->(%s %x)\n", This, debugstr_w(feature_name), value); + TRACE("%p, %s, %#x.\n", iface, debugstr_w(name), value); - feature = get_saxreader_feature(feature_name); + feature = get_saxreader_feature(name); /* accepted cases */ if ((feature == ExhaustiveErrors && value == VARIANT_FALSE) || @@ -3237,7 +5946,7 @@ static HRESULT WINAPI isaxxmlreader_putFeature( feature == Namespaces || feature == NamespacePrefixes) { - return set_feature_value(This, feature, value); + return set_feature_value(reader, feature, value); } if (feature == LexicalHandlerParEntities || @@ -3245,156 +5954,121 @@ static HRESULT WINAPI isaxxmlreader_putFeature( feature == ExternalGeneralEntities || feature == ExternalParameterEntities) { - FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature_name), value); - return set_feature_value(This, feature, value); + FIXME("%p, %s, %#x stub\n", iface, debugstr_w(name), value); + return set_feature_value(reader, feature, value); } - FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature_name), value); + FIXME("%p, %s, %#x stub\n", iface, debugstr_w(name), value); return E_NOTIMPL; } -static HRESULT WINAPI isaxxmlreader_getProperty( - ISAXXMLReader* iface, - const WCHAR *prop, - VARIANT *value) +static HRESULT WINAPI isaxxmlreader_getProperty(ISAXXMLReader *iface, const WCHAR *name, VARIANT *value) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return internal_getProperty(This, prop, value, FALSE); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_w(name), value); + + return saxreader_get_property(reader, name, value, false); } -static HRESULT WINAPI isaxxmlreader_putProperty( - ISAXXMLReader* iface, - const WCHAR *pProp, - VARIANT value) +static HRESULT WINAPI isaxxmlreader_putProperty(ISAXXMLReader *iface, const WCHAR *name, VARIANT value) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return internal_putProperty(This, pProp, value, FALSE); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + + TRACE("%p, %s, %s.\n", iface, debugstr_w(name), debugstr_variant(&value)); + + return saxreader_put_property(reader, name, value, false); } -static HRESULT WINAPI isaxxmlreader_getEntityResolver( - ISAXXMLReader* iface, - ISAXEntityResolver **resolver) +static HRESULT WINAPI isaxxmlreader_getEntityResolver(ISAXXMLReader *iface, ISAXEntityResolver **resolver) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return saxreader_get_handler(This, SAXEntityResolver, FALSE, (void**)resolver); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return saxreader_get_handler(reader, SAXEntityResolver, false, (void **)resolver); } static HRESULT WINAPI isaxxmlreader_putEntityResolver(ISAXXMLReader *iface, ISAXEntityResolver *resolver) { - saxreader *reader = impl_from_ISAXXMLReader(iface); - - TRACE("%p, %p.\n", iface, resolver); - - return saxreader_put_handler(reader, SAXEntityResolver, resolver, FALSE); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return saxreader_put_handler(reader, SAXEntityResolver, resolver, false); } -static HRESULT WINAPI isaxxmlreader_getContentHandler( - ISAXXMLReader* iface, - ISAXContentHandler **handler) +static HRESULT WINAPI isaxxmlreader_getContentHandler(ISAXXMLReader *iface, ISAXContentHandler **handler) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return saxreader_get_handler(This, SAXContentHandler, FALSE, (void**)handler); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return saxreader_get_handler(reader, SAXContentHandler, false, (void **)handler); } static HRESULT WINAPI isaxxmlreader_putContentHandler(ISAXXMLReader *iface, ISAXContentHandler *handler) { - saxreader *reader = impl_from_ISAXXMLReader(iface); - - TRACE("%p, %p.\n", iface, handler); - - return saxreader_put_handler(reader, SAXContentHandler, handler, FALSE); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return saxreader_put_handler(reader, SAXContentHandler, handler, false); } -static HRESULT WINAPI isaxxmlreader_getDTDHandler( - ISAXXMLReader* iface, - ISAXDTDHandler **handler) +static HRESULT WINAPI isaxxmlreader_getDTDHandler(ISAXXMLReader *iface, ISAXDTDHandler **handler) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return saxreader_get_handler(This, SAXDTDHandler, FALSE, (void**)handler); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return saxreader_get_handler(reader, SAXDTDHandler, false, (void **)handler); } static HRESULT WINAPI isaxxmlreader_putDTDHandler(ISAXXMLReader *iface, ISAXDTDHandler *handler) { - saxreader *reader = impl_from_ISAXXMLReader(iface); - - TRACE("%p, %p.\n", iface, handler); - - return saxreader_put_handler(reader, SAXDTDHandler, handler, FALSE); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return saxreader_put_handler(reader, SAXDTDHandler, handler, false); } -static HRESULT WINAPI isaxxmlreader_getErrorHandler( - ISAXXMLReader* iface, - ISAXErrorHandler **handler) +static HRESULT WINAPI isaxxmlreader_getErrorHandler(ISAXXMLReader *iface, ISAXErrorHandler **handler) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return saxreader_get_handler(This, SAXErrorHandler, FALSE, (void**)handler); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return saxreader_get_handler(reader, SAXErrorHandler, false, (void **)handler); } static HRESULT WINAPI isaxxmlreader_putErrorHandler(ISAXXMLReader *iface, ISAXErrorHandler *handler) { - saxreader *reader = impl_from_ISAXXMLReader(iface); - - TRACE("%p, %p.\n", iface, handler); - - return saxreader_put_handler(reader, SAXErrorHandler, handler, FALSE); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return saxreader_put_handler(reader, SAXErrorHandler, handler, false); } -static HRESULT WINAPI isaxxmlreader_getBaseURL( - ISAXXMLReader* iface, - const WCHAR **base_url) +static HRESULT WINAPI isaxxmlreader_getBaseURL(ISAXXMLReader *iface, const WCHAR **url) { - saxreader *This = impl_from_ISAXXMLReader( iface ); + FIXME("%p, %p stub\n", iface, url); - FIXME("(%p)->(%p) stub\n", This, base_url); return E_NOTIMPL; } -static HRESULT WINAPI isaxxmlreader_putBaseURL( - ISAXXMLReader* iface, - const WCHAR *pBaseUrl) +static HRESULT WINAPI isaxxmlreader_putBaseURL(ISAXXMLReader *iface, const WCHAR *url) { - saxreader *This = impl_from_ISAXXMLReader( iface ); + FIXME("%p, %s stub\n", iface, debugstr_w(url)); - FIXME("(%p)->(%s) stub\n", This, debugstr_w(pBaseUrl)); return E_NOTIMPL; } -static HRESULT WINAPI isaxxmlreader_getSecureBaseURL( - ISAXXMLReader* iface, - const WCHAR **pSecureBaseUrl) +static HRESULT WINAPI isaxxmlreader_getSecureBaseURL(ISAXXMLReader *iface, const WCHAR **url) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - FIXME("(%p)->(%p) stub\n", This, pSecureBaseUrl); + FIXME("%p, %p stub\n", iface, url); + return E_NOTIMPL; } -static HRESULT WINAPI isaxxmlreader_putSecureBaseURL( - ISAXXMLReader* iface, - const WCHAR *secureBaseUrl) +static HRESULT WINAPI isaxxmlreader_putSecureBaseURL(ISAXXMLReader *iface, const WCHAR *url) { - saxreader *This = impl_from_ISAXXMLReader( iface ); + FIXME("%p, %s stub\n", iface, debugstr_w(url)); - FIXME("(%p)->(%s) stub\n", This, debugstr_w(secureBaseUrl)); return E_NOTIMPL; } -static HRESULT WINAPI isaxxmlreader_parse( - ISAXXMLReader* iface, - VARIANT varInput) +static HRESULT WINAPI isaxxmlreader_parse(ISAXXMLReader *iface, VARIANT input) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return internal_parse(This, varInput, FALSE); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return saxreader_parse(reader, input, false); } -static HRESULT WINAPI isaxxmlreader_parseURL( - ISAXXMLReader* iface, - const WCHAR *url) +static HRESULT WINAPI isaxxmlreader_parseURL(ISAXXMLReader *iface, const WCHAR *url) { - saxreader *This = impl_from_ISAXXMLReader( iface ); - return internal_parseURL(This, url, FALSE); + struct saxreader *reader = impl_from_ISAXXMLReader(iface); + return saxreader_parse_url(reader, url, false); } -static const struct ISAXXMLReaderVtbl SAXXMLReaderVtbl = +static const struct ISAXXMLReaderVtbl saxxmlreadervtbl = { isaxxmlreader_QueryInterface, isaxxmlreader_AddRef, @@ -3419,62 +6093,41 @@ static const struct ISAXXMLReaderVtbl SAXXMLReaderVtbl = isaxxmlreader_parseURL }; -static const tid_t saxreader_iface_tids[] = { +static const tid_t saxreader_iface_tids[] = +{ IVBSAXXMLReader_tid, 0 }; -static dispex_static_data_t saxreader_dispex = { + +static dispex_static_data_t saxreader_dispex = +{ NULL, IVBSAXXMLReader_tid, NULL, saxreader_iface_tids }; -HRESULT SAXXMLReader_create(MSXML_VERSION version, LPVOID *ppObj) +HRESULT SAXXMLReader_create(MSXML_VERSION version, void **obj) { - saxreader *reader; + struct saxreader *reader; - TRACE("(%p)\n", ppObj); + TRACE("%p\n", obj); - reader = malloc(sizeof(*reader)); - if( !reader ) + if (!(reader = calloc(1, sizeof(*reader)))) return E_OUTOFMEMORY; - reader->IVBSAXXMLReader_iface.lpVtbl = &VBSAXXMLReaderVtbl; - reader->ISAXXMLReader_iface.lpVtbl = &SAXXMLReaderVtbl; - reader->ref = 1; - memset(reader->saxhandlers, 0, sizeof(reader->saxhandlers)); - reader->isParsing = FALSE; - reader->xmldecl_version = NULL; - reader->pool.pool = NULL; - reader->pool.index = 0; - reader->pool.len = 0; + reader->IVBSAXXMLReader_iface.lpVtbl = &vbsaxxmlreadervtbl; + reader->ISAXXMLReader_iface.lpVtbl = &saxxmlreadervtbl; + reader->refcount = 1; reader->features = Namespaces | NamespacePrefixes; reader->version = version; reader->empty_bstr = SysAllocString(L""); - init_dispex(&reader->dispex, (IUnknown*)&reader->IVBSAXXMLReader_iface, &saxreader_dispex); - - memset(&reader->sax, 0, sizeof(xmlSAXHandler)); - reader->sax.initialized = XML_SAX2_MAGIC; - reader->sax.startDocument = libxmlStartDocument; - reader->sax.endDocument = libxmlEndDocument; - reader->sax.startElementNs = libxmlStartElementNS; - reader->sax.endElementNs = libxmlEndElementNS; - reader->sax.characters = libxmlCharacters; - reader->sax.setDocumentLocator = libxmlSetDocumentLocator; - reader->sax.comment = libxmlComment; - reader->sax.error = libxmlFatalError; - reader->sax.fatalError = libxmlFatalError; - reader->sax.cdataBlock = libxml_cdatablock; - reader->sax.resolveEntity = libxmlresolveentity; - reader->sax.processingInstruction = libxml_pi; - reader->sax.internalSubset = libxml_internalsubset; - reader->sax.externalSubset = libxml_externalsubset; - - *ppObj = &reader->IVBSAXXMLReader_iface; - - TRACE("returning iface %p\n", *ppObj); + init_dispex(&reader->dispex, (IUnknown *)&reader->IVBSAXXMLReader_iface, &saxreader_dispex); + + *obj = &reader->IVBSAXXMLReader_iface; + + TRACE("returning iface %p\n", *obj); return S_OK; } diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c index 56164f66e2f..aca56a00de5 100644 --- a/dlls/msxml3/tests/saxreader.c +++ b/dlls/msxml3/tests/saxreader.c @@ -2524,12 +2524,7 @@ static void test_saxreader(void) set_expected_seq(test_seq); hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE); - else - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE); - + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE); IStream_Release(stream); V_VT(&var) = VT_UNKNOWN; @@ -2655,13 +2650,7 @@ static void test_saxreader(void) V_BSTR(&var) = _bstr_(xmlspace_attr); hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) - { - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE); - } - else - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE); /* switch off 'namespaces' feature */ hr = ISAXXMLReader_putFeature(reader, L"http://xml.org/sax/features/namespaces", VARIANT_FALSE); @@ -2681,7 +2670,7 @@ static void test_saxreader(void) set_expected_seq(test_seq); hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE); IStream_Release(stream); hr = ISAXXMLReader_putFeature(reader, L"http://xml.org/sax/features/namespaces", VARIANT_TRUE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -2798,7 +2787,10 @@ static void test_saxreader_cdata(void) hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); sprintf(seqname, "%s: cdata test", table->name); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); + if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); + else + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, FALSE); IStream_Release(stream); @@ -2816,7 +2808,10 @@ static void test_saxreader_cdata(void) hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); sprintf(seqname, "%s: cdata test 2", table->name); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); + if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); + else + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, FALSE); IStream_Release(stream); @@ -2834,7 +2829,7 @@ static void test_saxreader_cdata(void) hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); sprintf(seqname, "%s: cdata test 3", table->name); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, FALSE); IStream_Release(stream); @@ -2891,7 +2886,7 @@ static void test_saxreader_pi(void) hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); sprintf(seqname, "%s: pi test", table->name); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, FALSE); VariantClear(&var); ISAXXMLReader_Release(reader); @@ -2947,7 +2942,7 @@ static void test_saxreader_characters(void) hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); sprintf(seqname, "%s: char data test", table->name); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, FALSE); VariantClear(&var); V_VT(&var) = VT_UNKNOWN; @@ -2962,7 +2957,10 @@ static void test_saxreader_characters(void) hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); sprintf(seqname, "%s: char data test", table->name); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); + if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); + else + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, FALSE); VariantClear(&var); ISAXXMLReader_Release(reader); @@ -3145,7 +3143,6 @@ static void test_saxreader_properties(void) V_DISPATCH(&v) = (IDispatch *)0xdeadbeef; hr = IVBSAXXMLReader_getProperty(vb_reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), &v); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(V_VT(&v) == VT_DISPATCH, "Unexpected type %d.\n", V_VT(&v)); ok(!V_DISPATCH(&v), "Unexpected value %p.\n", V_UNKNOWN(&v)); @@ -3153,7 +3150,6 @@ static void test_saxreader_properties(void) V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; hr = IVBSAXXMLReader_getProperty(vb_reader, _bstr_("http://xml.org/sax/properties/declaration-handler"), &v); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(V_VT(&v) == VT_DISPATCH, "Unexpected type %d.\n", V_VT(&v)); ok(!V_DISPATCH(&v), "Unexpected value %p.\n", V_UNKNOWN(&v)); @@ -3497,9 +3493,9 @@ static void test_saxreader_encoding(void) create_test_file(testXmlA, ucs4_le_test, sizeof(ucs4_le_test)); hr = ISAXXMLReader_parseURL(reader, L"test.xml"); if (IsEqualGUID(entry->guid, &CLSID_SAXXMLReader40)) + todo_wine ok(FAILED(hr), "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); DeleteFileA(testXmlA); @@ -3507,9 +3503,9 @@ static void test_saxreader_encoding(void) create_test_file(testXmlA, ucs4_be_test, sizeof(ucs4_be_test)); hr = ISAXXMLReader_parseURL(reader, L"test.xml"); if (IsEqualGUID(entry->guid, &CLSID_SAXXMLReader40)) + todo_wine ok(FAILED(hr), "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); DeleteFileA(testXmlA); @@ -3535,29 +3531,28 @@ static void test_saxreader_encoding(void) set_expected_seq(xml_win1252_seq); hr = ISAXXMLReader_parseURL(reader, L"test.xml"); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, xml_win1252_seq, "Content test with windows-1252", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, xml_win1252_seq, "Content test with windows-1252", FALSE); DeleteFileA(testXmlA); create_test_file(testXmlA, xml_win1253_test, sizeof(xml_win1253_test) - 1); set_expected_seq(xml_win1253_seq); hr = ISAXXMLReader_parseURL(reader, L"test.xml"); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, xml_win1253_seq, "Content test with windows-1252", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, xml_win1253_seq, "Content test with windows-1253", FALSE); DeleteFileA(testXmlA); create_test_file(testXmlA, xml_us_ascii_test, sizeof(xml_us_ascii_test) - 1); set_expected_seq(xml_us_ascii_seq); hr = ISAXXMLReader_parseURL(reader, L"test.xml"); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, xml_us_ascii_seq, "Content test with us-ascii", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, xml_us_ascii_seq, "Content test with us-ascii", FALSE); DeleteFileA(testXmlA); create_test_file(testXmlA, xml_iso_8859_1_test, sizeof(xml_iso_8859_1_test) - 1); set_expected_seq(xml_iso_8859_1_seq); hr = ISAXXMLReader_parseURL(reader, L"test.xml"); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, xml_iso_8859_1_seq, "Content test with iso-8859-1", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, xml_iso_8859_1_seq, "Content test with iso-8859-1", FALSE); DeleteFileA(testXmlA); ISAXXMLReader_Release(reader); @@ -6534,7 +6529,6 @@ static void test_saxreader_dtd(void) V_BSTR(&var) = SysAllocString(xml_dtd); hr = ISAXXMLReader_parse(reader, var); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); VariantClear(&var); diff --git a/dlls/msxml3/tests/xmldoc.c b/dlls/msxml3/tests/xmldoc.c index e4ba2d5c154..898b5f3c114 100644 --- a/dlls/msxml3/tests/xmldoc.c +++ b/dlls/msxml3/tests/xmldoc.c @@ -1314,7 +1314,6 @@ static void test_xmldoc_version(void) SysFreeString(s); hr = load_document(doc, doc_data4, sizeof(doc_data4) - 1); - todo_wine ok(hr == XML_E_INVALID_VERSION, "Unexpected hr %#lx.\n", hr); IXMLDocument_Release(doc); diff --git a/dlls/msxml6/tests/saxreader.c b/dlls/msxml6/tests/saxreader.c index 3f3657fa900..52519cee939 100644 --- a/dlls/msxml6/tests/saxreader.c +++ b/dlls/msxml6/tests/saxreader.c @@ -4749,7 +4749,7 @@ static void test_saxreader(void) V_BSTR(&var) = _bstr_(xmlspace_attr); hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE); /* switch off 'namespaces' feature */ hr = ISAXXMLReader_putFeature(reader, L"http://xml.org/sax/features/namespaces", VARIANT_FALSE); @@ -4763,7 +4763,7 @@ static void test_saxreader(void) set_expected_seq(test_seq); hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE); IStream_Release(stream); hr = ISAXXMLReader_putFeature(reader, L"http://xml.org/sax/features/namespaces", VARIANT_TRUE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -4813,7 +4813,7 @@ static void test_saxreader(void) set_expected_seq(test_seq); hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "pi test 1", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "pi test 1", FALSE); VariantClear(&var); ISAXXMLReader_Release(reader); @@ -5059,7 +5059,7 @@ static void test_saxreader_cdata(void) set_expected_seq(test_seq); hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "cdata test 3", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "cdata test 3", FALSE); IStream_Release(stream); @@ -5125,7 +5125,7 @@ static void test_saxreader_characters(void) set_expected_seq(chardata_test); hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, chardata_test, "char data test", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, chardata_test, "char data test", FALSE); VariantClear(&var); V_VT(&var) = VT_UNKNOWN; @@ -5164,7 +5164,7 @@ static void test_saxreader_pi(void) set_expected_seq(pi_test); hr = ISAXXMLReader_parse(reader, var); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_sequence(sequences, CONTENT_HANDLER_INDEX, pi_test, "pi test 1", TRUE); + ok_sequence(sequences, CONTENT_HANDLER_INDEX, pi_test, "pi test 1", FALSE); VariantClear(&var); ISAXXMLReader_Release(reader); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10172