blob: 196208c8d7506e48346eca56d35f3b2fdb1a865f [file] [edit]
/*
* SAXReader/MXWriter tests
*
* Copyright 2008 Piotr Caban
* Copyright 2011 Thomas Mullaly
* Copyright 2012 Nikolay Sivov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define COBJMACROS
#define CONST_VTABLE
#include <stdio.h>
#include <assert.h>
#include "windows.h"
#include "ole2.h"
#include "msxml2.h"
#include "msxml2did.h"
#include "ocidl.h"
#include "initguid.h"
#include "dispex.h"
#include "wine/test.h"
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
struct sink
{
IVBSAXContentHandler IVBSAXContentHandler_iface;
LONG refcount;
};
static struct sink *impl_from_IVBSAXContentHandler(IVBSAXContentHandler *iface)
{
return CONTAINING_RECORD(iface, struct sink, IVBSAXContentHandler_iface);
}
static HRESULT WINAPI vb_content_handler_QueryInterface(IVBSAXContentHandler *iface,
REFIID riid, void **obj)
{
if (IsEqualGUID(riid, &IID_IUnknown)
|| IsEqualGUID(riid, &IID_IDispatch)
|| IsEqualGUID(riid, &IID_IVBSAXContentHandler))
{
*obj = iface;
IVBSAXContentHandler_AddRef(iface);
return S_OK;
}
*obj = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI vb_content_handler_AddRef(IVBSAXContentHandler *iface)
{
struct sink *sink = impl_from_IVBSAXContentHandler(iface);
return InterlockedIncrement(&sink->refcount);
}
static ULONG WINAPI vb_content_handler_Release(IVBSAXContentHandler *iface)
{
struct sink *sink = impl_from_IVBSAXContentHandler(iface);
LONG refcount = InterlockedDecrement(&sink->refcount);
if (!refcount)
free(sink);
return refcount;
}
static HRESULT WINAPI vb_content_handler_GetTypeInfoCount(IVBSAXContentHandler *iface, UINT *count)
{
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
}
static HRESULT WINAPI vb_content_handler_GetTypeInfo(IVBSAXContentHandler *iface, UINT index,
LCID lcid, ITypeInfo **ti)
{
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
}
static HRESULT WINAPI vb_content_handler_GetIDsOfNames(IVBSAXContentHandler *iface, REFIID riid,
LPOLESTR *names, UINT cNames, LCID lcid, DISPID *rgDispId)
{
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
}
static HRESULT WINAPI vb_content_handler_Invoke(IVBSAXContentHandler *iface, DISPID dispIdMember,
REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo,
UINT *puArgErr)
{
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
}
static HRESULT WINAPI vb_content_handler_putref_documentLocator(IVBSAXContentHandler *iface, IVBSAXLocator *locator)
{
return S_OK;
}
static HRESULT WINAPI vb_content_handler_startDocument(IVBSAXContentHandler *iface)
{
return S_OK;
}
static HRESULT WINAPI vb_content_handler_endDocument(IVBSAXContentHandler *iface)
{
return S_OK;
}
static HRESULT WINAPI vb_content_handler_startPrefixMapping(IVBSAXContentHandler *iface, BSTR *prefix, BSTR *uri)
{
return S_OK;
}
static HRESULT WINAPI vb_content_handler_endPrefixMapping(IVBSAXContentHandler *iface, BSTR *prefix)
{
return S_OK;
}
static HRESULT WINAPI vb_content_handler_startElement(IVBSAXContentHandler *iface, BSTR *uri, BSTR *localName,
BSTR *qname, IVBSAXAttributes * oAttributes)
{
ok(uri != NULL && *uri != NULL, "Unexpected pointer.\n");
ok(localName != NULL && *localName != NULL, "Unexpected pointer.\n");
ok(qname != NULL && *qname != NULL, "Unexpected pointer.\n");
return S_OK;
}
static HRESULT WINAPI vb_content_handler_endElement(IVBSAXContentHandler *iface, BSTR *uri, BSTR *localName,
BSTR * strQName)
{
return S_OK;
}
static HRESULT WINAPI vb_content_handler_characters(IVBSAXContentHandler *iface, BSTR * chars)
{
return S_OK;
}
static HRESULT WINAPI vb_content_handler_ignorableWhitespace(IVBSAXContentHandler *iface, BSTR * chars)
{
return S_OK;
}
static HRESULT WINAPI vb_content_handler_processingInstruction(IVBSAXContentHandler *iface, BSTR * target, BSTR * data)
{
return S_OK;
}
static HRESULT WINAPI vb_content_handler_skippedEntity(IVBSAXContentHandler *iface, BSTR * name)
{
return S_OK;
}
static const IVBSAXContentHandlerVtbl vbcontenthandlervtbl =
{
vb_content_handler_QueryInterface,
vb_content_handler_AddRef,
vb_content_handler_Release,
vb_content_handler_GetTypeInfoCount,
vb_content_handler_GetTypeInfo,
vb_content_handler_GetIDsOfNames,
vb_content_handler_Invoke,
vb_content_handler_putref_documentLocator,
vb_content_handler_startDocument,
vb_content_handler_endDocument,
vb_content_handler_startPrefixMapping,
vb_content_handler_endPrefixMapping,
vb_content_handler_startElement,
vb_content_handler_endElement,
vb_content_handler_characters,
vb_content_handler_ignorableWhitespace,
vb_content_handler_processingInstruction,
vb_content_handler_skippedEntity,
};
static struct sink *create_test_sink(void)
{
struct sink *sink = calloc(1, sizeof(*sink));
sink->IVBSAXContentHandler_iface.lpVtbl = &vbcontenthandlervtbl;
sink->refcount = 1;
return sink;
}
#define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
static void _expect_ref(IUnknown* obj, ULONG ref, int line)
{
ULONG rc;
IUnknown_AddRef(obj);
rc = IUnknown_Release(obj);
ok_(__FILE__, line)(rc == ref, "expected refcount %ld, got %ld.\n", ref, rc);
}
#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
{
IUnknown *iface = iface_ptr;
HRESULT hr, expected_hr;
IUnknown *unk;
expected_hr = supported ? S_OK : E_NOINTERFACE;
hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr);
if (SUCCEEDED(hr))
IUnknown_Release(unk);
}
static LONG get_refcount(void *iface)
{
IUnknown *unk = iface;
LONG ref;
ref = IUnknown_AddRef(unk);
IUnknown_Release(unk);
return ref-1;
}
struct msxmlsupported_data_t
{
const GUID *clsid;
const char *name;
BOOL supported;
};
static BSTR alloc_str_from_narrow(const char *str)
{
int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
return ret;
}
static BSTR alloced_bstrs[512];
static int alloced_bstrs_count;
static BSTR _bstr_(const char *str)
{
assert(alloced_bstrs_count < ARRAY_SIZE(alloced_bstrs));
alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
return alloced_bstrs[alloced_bstrs_count++];
}
static void free_bstrs(void)
{
int i;
for (i = 0; i < alloced_bstrs_count; i++)
SysFreeString(alloced_bstrs[i]);
alloced_bstrs_count = 0;
}
static void test_saxstr(const char *file, unsigned line, BSTR str, const WCHAR *expected, BOOL todo, int *failcount)
{
int len, lenexp, cmp;
len = SysStringLen(str);
if (!expected) {
if (str && todo)
{
(*failcount)++;
todo_wine
ok_(file, line) (!str, "got %p, expected null str\n", str);
}
else
ok_(file, line) (!str, "got %p, expected null str\n", str);
if (len && todo)
{
(*failcount)++;
todo_wine
ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
}
else
ok_(file, line) (len == 0, "got len %d, expected 0\n", len);
return;
}
lenexp = lstrlenW(expected);
if (lenexp != len && todo)
{
(*failcount)++;
todo_wine
ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len),
lenexp, wine_dbgstr_w(expected));
}
else
ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len),
lenexp, wine_dbgstr_w(expected));
/* exit earlier on length mismatch */
if (lenexp != len) return;
cmp = lstrcmpW(str, expected);
if (cmp && todo)
{
(*failcount)++;
todo_wine
ok_(file, line) (!cmp, "unexpected str %s, expected %s\n", wine_dbgstr_wn(str, len), wine_dbgstr_w(expected));
}
else
ok_(file, line) (!cmp, "unexpected str %s, expected %s\n", wine_dbgstr_wn(str, len), wine_dbgstr_w(expected));
}
typedef enum _CH {
CH_ENDTEST,
CH_PUTDOCUMENTLOCATOR,
CH_STARTDOCUMENT,
CH_ENDDOCUMENT,
CH_STARTPREFIXMAPPING,
CH_ENDPREFIXMAPPING,
CH_STARTELEMENT,
CH_ENDELEMENT,
CH_CHARACTERS,
CH_IGNORABLEWHITESPACE,
CH_PROCESSINGINSTRUCTION,
CH_SKIPPEDENTITY,
LH_STARTCDATA,
LH_ENDCDATA,
LH_COMMENT,
EH_ERROR,
EH_FATALERROR,
EH_IGNORABLEWARNING,
EVENT_LAST
} CH;
static const char *event_names[EVENT_LAST] = {
"endtest",
"putDocumentLocator",
"startDocument",
"endDocument",
"startPrefixMapping",
"endPrefixMapping",
"startElement",
"endElement",
"characters",
"ignorableWhitespace",
"processingInstruction",
"skippedEntity",
"startCDATA",
"endCDATA",
"comment",
"error",
"fatalError",
"ignorableWarning"
};
struct attribute_entry
{
const WCHAR *uri;
const WCHAR *local;
const WCHAR *qname;
const WCHAR *value;
/* used for actual call data only, null for expected call data */
BSTR uriW;
BSTR localW;
BSTR qnameW;
BSTR valueW;
};
struct call_entry
{
CH id;
int line;
int column;
HRESULT ret;
const WCHAR *arg1;
const WCHAR *arg2;
const WCHAR *arg3;
/* allocated once at startElement callback */
struct attribute_entry *attributes;
int attr_count;
/* used for actual call data only, null for expected call data */
BSTR arg1W;
BSTR arg2W;
BSTR arg3W;
};
struct call_sequence
{
int count;
int size;
struct call_entry *sequence;
};
#define CONTENT_HANDLER_INDEX 0
#define NUM_CALL_SEQUENCES 1
static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
static void init_call_entry(ISAXLocator *locator, struct call_entry *call)
{
memset(call, 0, sizeof(*call));
ISAXLocator_getLineNumber(locator, &call->line);
ISAXLocator_getColumnNumber(locator, &call->column);
}
static void add_call(struct call_sequence **seq, int sequence_index,
const struct call_entry *call)
{
struct call_sequence *call_seq = seq[sequence_index];
if (!call_seq->sequence)
{
call_seq->size = 10;
call_seq->sequence = malloc(call_seq->size * sizeof (struct call_entry));
}
if (call_seq->count == call_seq->size)
{
call_seq->size *= 2;
call_seq->sequence = realloc(call_seq->sequence, call_seq->size * sizeof (struct call_entry));
}
assert(call_seq->sequence);
call_seq->sequence[call_seq->count].id = call->id;
call_seq->sequence[call_seq->count].line = call->line;
call_seq->sequence[call_seq->count].column = call->column;
call_seq->sequence[call_seq->count].arg1W = call->arg1W;
call_seq->sequence[call_seq->count].arg2W = call->arg2W;
call_seq->sequence[call_seq->count].arg3W = call->arg3W;
call_seq->sequence[call_seq->count].ret = call->ret;
call_seq->sequence[call_seq->count].attr_count = call->attr_count;
call_seq->sequence[call_seq->count].attributes = call->attributes;
call_seq->count++;
}
static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
{
int i;
struct call_sequence *call_seq = seg[sequence_index];
for (i = 0; i < call_seq->count; i++)
{
int j;
for (j = 0; j < call_seq->sequence[i].attr_count; j++)
{
SysFreeString(call_seq->sequence[i].attributes[j].uriW);
SysFreeString(call_seq->sequence[i].attributes[j].localW);
SysFreeString(call_seq->sequence[i].attributes[j].qnameW);
SysFreeString(call_seq->sequence[i].attributes[j].valueW);
}
free(call_seq->sequence[i].attributes);
call_seq->sequence[i].attr_count = 0;
SysFreeString(call_seq->sequence[i].arg1W);
SysFreeString(call_seq->sequence[i].arg2W);
SysFreeString(call_seq->sequence[i].arg3W);
}
free(call_seq->sequence);
call_seq->sequence = NULL;
call_seq->count = call_seq->size = 0;
}
static const char *get_event_name(CH event)
{
return event_names[event];
}
static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context,
BOOL todo, const char *file, int line, int *failcount)
{
int i, lenexp = 0;
/* attribute count is not stored for expected data */
if (expected->attributes)
{
struct attribute_entry *ptr = expected->attributes;
while (ptr->uri) { lenexp++; ptr++; };
}
/* check count first and exit earlier */
if (actual->attr_count != lenexp && todo)
{
(*failcount)++;
todo_wine
ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n",
context, get_event_name(actual->id), lenexp, actual->attr_count);
}
else
ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n",
context, get_event_name(actual->id), lenexp, actual->attr_count);
if (actual->attr_count != lenexp) return;
/* now compare all attributes strings */
for (i = 0; i < actual->attr_count; i++)
{
test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount);
test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount);
test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount);
test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount);
}
}
static void ok_sequence_(struct call_sequence **seq, int sequence_index,
const struct call_entry *expected, const char *context, BOOL todo,
const char *file, int line)
{
struct call_sequence *call_seq = seq[sequence_index];
static const struct call_entry end_of_sequence = { CH_ENDTEST };
const struct call_entry *actual, *sequence;
int failcount = 0;
add_call(seq, sequence_index, &end_of_sequence);
sequence = call_seq->sequence;
actual = sequence;
while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST)
{
if (expected->id == actual->id)
{
if (expected->line != -1)
{
/* always test position data */
if (expected->line != actual->line && todo)
{
todo_wine
{
failcount++;
ok_(file, line) (FALSE,
"%s: in event %s expecting line %d got %d\n",
context, get_event_name(actual->id), expected->line, actual->line);
}
}
else
{
ok_(file, line) (expected->line == actual->line,
"%s: in event %s expecting line %d got %d\n",
context, get_event_name(actual->id), expected->line, actual->line);
}
}
if (expected->column != -1)
{
if (expected->column != actual->column && todo)
{
todo_wine
{
failcount++;
ok_(file, line) (FALSE,
"%s: in event %s expecting column %d got %d\n",
context, get_event_name(actual->id), expected->column, actual->column);
}
}
else
{
ok_(file, line) (expected->column == actual->column,
"%s: in event %s expecting column %d got %d\n",
context, get_event_name(actual->id), expected->column, actual->column);
}
}
switch (actual->id)
{
case CH_PUTDOCUMENTLOCATOR:
case CH_STARTDOCUMENT:
case CH_ENDDOCUMENT:
case LH_STARTCDATA:
case LH_ENDCDATA:
break;
case CH_STARTPREFIXMAPPING:
/* prefix, uri */
test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
break;
case CH_ENDPREFIXMAPPING:
/* prefix */
test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
break;
case CH_STARTELEMENT:
/* compare attributes */
compare_attributes(actual, expected, context, todo, file, line, &failcount);
/* fallthrough */
case CH_ENDELEMENT:
/* uri, localname, qname */
test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount);
break;
case CH_CHARACTERS:
case CH_IGNORABLEWHITESPACE:
case LH_COMMENT:
/* char data */
test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
break;
case CH_PROCESSINGINSTRUCTION:
/* target, data */
test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount);
break;
case CH_SKIPPEDENTITY:
/* name */
test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount);
break;
case EH_FATALERROR:
/* test return value only */
if (expected->ret != actual->ret && todo)
{
failcount++;
ok_(file, line) (FALSE,
"%s: in event %s expecting ret %#lx got %#lx\n",
context, get_event_name(actual->id), expected->ret, actual->ret);
}
else
ok_(file, line) (expected->ret == actual->ret,
"%s: in event %s expecting ret %#lx got %#lx\n",
context, get_event_name(actual->id), expected->ret, actual->ret);
break;
case EH_ERROR:
case EH_IGNORABLEWARNING:
default:
ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id));
}
expected++;
actual++;
}
else if (todo)
{
failcount++;
todo_wine
{
ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
context, get_event_name(expected->id), get_event_name(actual->id));
}
flush_sequence(seq, sequence_index);
return;
}
else
{
ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n",
context, get_event_name(expected->id), get_event_name(actual->id));
expected++;
actual++;
}
}
if (todo)
{
todo_wine
{
if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
{
failcount++;
ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
context, get_event_name(expected->id), get_event_name(actual->id));
}
}
}
else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST)
{
ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n",
context, get_event_name(expected->id), get_event_name(actual->id));
}
if (todo && !failcount) /* succeeded yet marked todo */
{
todo_wine
{
ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
}
}
flush_sequence(seq, sequence_index);
}
#define ok_sequence(seq, index, exp, contx, todo) \
ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
static void init_call_sequences(struct call_sequence **seq, int n)
{
int i;
for (i = 0; i < n; i++)
seq[i] = calloc(1, sizeof(**seq));
}
static const WCHAR szSimpleXML[] =
L"<?xml version=\"1.0\" ?>\n"
"<BankAccount>\n"
" <Number>1234</Number>\n"
" <Name>Captain Ahab</Name>\n"
"</BankAccount>\n";
static const WCHAR carriage_ret_test[] =
L"<?xml version=\"1.0\"?>\r\n"
"<BankAccount>\r\n\t<Number>1234</Number>\r\n\t"
"<Name>Captain Ahab</Name>\r\n"
"</BankAccount>\r\n";
static const char testXML[] =
"<?xml version=\"1.0\" ?>\n"
"<BankAccount>\n"
" <Number>1234</Number>\n"
" <Name>Captain Ahab</Name>\n"
"</BankAccount>\n";
static const char test_attributes[] =
"<?xml version=\"1.0\" ?>\n"
"<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
"<node1 xmlns:p=\"test\" />"
"</document>\n";
static const char test_cdata_xml[] =
"<?xml version=\"1.0\" ?>"
"<a><![CDATA[Some \r\ntext\n\r\ndata\n\n]]></a>";
static const char test2_cdata_xml[] =
"<?xml version=\"1.0\" ?>"
"<a><![CDATA[\n\r\nSome \r\ntext\n\r\ndata\n\n]]></a>";
static const char test3_cdata_xml[] =
"<?xml version=\"1.0\" ?><a><![CDATA[Some text data]]></a>";
static const char test_pi_xml[] =
"<?xml version=\"1.0\" ?><a><?t some t\rex\r\nt ?></a>";
static const char test_chardata_xml[] =
"<?xml version=\"1.0\" ?><a>\nabc<b>de\nf</b>gh\n</a>";
static const char test_chardata_xml2[] =
"<?xml version=\"1.0\" ?><a>\rabc<b>de\rf</b>gh\r</a>";
static struct call_entry content_handler_test1_alternate[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTELEMENT, 2, 13, S_OK, L"", L"BankAccount", L"BankAccount" },
{ CH_CHARACTERS, 3, 4, S_OK, L"\n " },
{ CH_STARTELEMENT, 3, 11, S_OK, L"", L"Number", L"Number" },
{ CH_CHARACTERS, 3, 16, S_OK, L"1234" },
{ CH_ENDELEMENT, 3, 24, S_OK, L"", L"Number", L"Number" },
{ CH_CHARACTERS, 4, 4, S_OK, L"\n " },
{ CH_STARTELEMENT, 4, 9, S_OK, L"", L"Name", L"Name" },
{ CH_CHARACTERS, 4, 22, S_OK, L"Captain Ahab" },
{ CH_ENDELEMENT, 4, 28, S_OK, L"", L"Name", L"Name" },
{ CH_CHARACTERS, 5, 1, S_OK, L"\n" },
{ CH_ENDELEMENT, 5, 14, S_OK, L"", L"BankAccount", L"BankAccount" },
{ CH_ENDDOCUMENT, 6, 0, S_OK },
{ CH_ENDTEST }
};
static struct call_entry content_handler_test2_alternate[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 21, S_OK },
{ CH_STARTELEMENT, 2, 13, S_OK, L"", L"BankAccount", L"BankAccount" },
{ CH_CHARACTERS, 3, 0, S_OK, L"\n" },
{ CH_CHARACTERS, 3, 2, S_OK, L"\t" },
{ CH_STARTELEMENT, 3, 9, S_OK, L"", L"Number", L"Number" },
{ CH_CHARACTERS, 3, 14, S_OK, L"1234" },
{ CH_ENDELEMENT, 3, 22, S_OK, L"", L"Number", L"Number" },
{ CH_CHARACTERS, 4, 0, S_OK, L"\n" },
{ CH_CHARACTERS, 4, 2, S_OK, L"\t" },
{ CH_STARTELEMENT, 4, 7, S_OK, L"", L"Name", L"Name" },
{ CH_CHARACTERS, 4, 20, S_OK, L"Captain Ahab" },
{ CH_ENDELEMENT, 4, 26, S_OK, L"", L"Name", L"Name" },
{ CH_CHARACTERS, 5, 0, S_OK, L"\n" },
{ CH_ENDELEMENT, 5, 14, S_OK, L"", L"BankAccount", L"BankAccount" },
{ CH_ENDDOCUMENT, 6, 0, S_OK },
{ CH_ENDTEST }
};
static struct call_entry content_handler_testerror_alternate[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL },
{ EH_FATALERROR, 1, 0, E_FAIL },
{ CH_ENDTEST }
};
static struct call_entry content_handler_test_callback_rets_alt[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE },
{ CH_STARTDOCUMENT, 1, 22, S_FALSE },
{ CH_STARTELEMENT, 2, 13, S_FALSE, L"", L"BankAccount", L"BankAccount" },
{ CH_CHARACTERS, 3, 4, S_FALSE, L"\n " },
{ CH_STARTELEMENT, 3, 11, S_FALSE, L"", L"Number", L"Number" },
{ CH_CHARACTERS, 3, 16, S_FALSE, L"1234" },
{ CH_ENDELEMENT, 3, 24, S_FALSE, L"", L"Number", L"Number" },
{ CH_CHARACTERS, 4, 4, S_FALSE, L"\n " },
{ CH_STARTELEMENT, 4, 9, S_FALSE, L"", L"Name", L"Name" },
{ CH_CHARACTERS, 4, 22, S_FALSE, L"Captain Ahab" },
{ CH_ENDELEMENT, 4, 28, S_FALSE, L"", L"Name", L"Name" },
{ CH_CHARACTERS, 5, 1, S_FALSE, L"\n" },
{ CH_ENDELEMENT, 5, 14, S_FALSE, L"", L"BankAccount", L"BankAccount" },
{ CH_ENDDOCUMENT, 6, 0, S_FALSE },
{ CH_ENDTEST }
};
static struct attribute_entry ch_attributes2[] = {
{ L"", L"", L"xmlns:p", L"test" },
{ NULL }
};
static struct attribute_entry ch_attributes_alt_4[] =
{
{ L"prefix_test", L"arg1", L"test:arg1", L"arg1" },
{ L"", L"arg2", L"arg2", L"arg2" },
{ L"prefix_test", L"ar3", L"test:ar3", L"arg3" },
{ L"", L"", L"xmlns:test", L"prefix_test" },
{ L"", L"", L"xmlns", L"prefix" },
{ NULL }
};
static struct call_entry content_handler_test_attributes_alternate_4[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTPREFIXMAPPING, 2, 95, S_OK, L"test", L"prefix_test" },
{ CH_STARTPREFIXMAPPING, 2, 95, S_OK, L"", L"prefix" },
{ CH_STARTELEMENT, 2, 95, S_OK, L"prefix", L"document", L"document", ch_attributes_alt_4 },
{ CH_CHARACTERS, 3, 1, S_OK, L"\n" },
{ CH_STARTPREFIXMAPPING, 3, 24, S_OK, L"p", L"test" },
{ CH_STARTELEMENT, 3, 24, S_OK, L"prefix", L"node1", L"node1", ch_attributes2 },
{ CH_ENDELEMENT, 3, 24, S_OK, L"prefix", L"node1", L"node1" },
{ CH_ENDPREFIXMAPPING, 3, 24, S_OK, L"p" },
{ CH_ENDELEMENT, 3, 35, S_OK, L"prefix", L"document", L"document" },
{ CH_ENDPREFIXMAPPING, 3, 35, S_OK, L"test" },
{ CH_ENDPREFIXMAPPING, 3, 35, S_OK, L"" },
{ CH_ENDDOCUMENT, 4, 0, S_OK },
{ CH_ENDTEST }
};
/* 'namespace' feature switched off */
static struct attribute_entry ch_attributes_alt_no_ns[] = {
{ L"", L"", L"xmlns:test", L"prefix_test" },
{ L"", L"", L"xmlns", L"prefix" },
{ L"", L"", L"test:arg1", L"arg1" },
{ L"", L"", L"arg2", L"arg2" },
{ L"", L"", L"test:ar3", L"arg3" },
{ NULL }
};
static struct call_entry content_handler_test_attributes_alt_no_ns[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTELEMENT, 2, 95, S_OK, L"", L"", L"document", ch_attributes_alt_no_ns },
{ CH_CHARACTERS, 3, 1, S_OK, L"\n" },
{ CH_STARTELEMENT, 3, 24, S_OK, L"", L"", L"node1", ch_attributes2 },
{ CH_ENDELEMENT, 3, 24, S_OK, L"", L"", L"node1" },
{ CH_ENDELEMENT, 3, 35, S_OK, L"", L"", L"document" },
{ CH_ENDDOCUMENT, 4, 0, S_OK },
{ CH_ENDTEST }
};
/* 'namespaces' is on, 'namespace-prefixes' if off */
static struct attribute_entry ch_attributes_no_prefix[] =
{
{ L"prefix_test", L"arg1", L"test:arg1", L"arg1" },
{ L"", L"arg2", L"arg2", L"arg2" },
{ L"prefix_test", L"ar3", L"test:ar3", L"arg3" },
{ NULL }
};
static struct call_entry content_handler_test_attributes_alt_no_prefix[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTPREFIXMAPPING, 2, 95, S_OK, L"test", L"prefix_test" },
{ CH_STARTPREFIXMAPPING, 2, 95, S_OK, L"", L"prefix" },
{ CH_STARTELEMENT, 2, 95, S_OK, L"prefix", L"document", L"document", ch_attributes_no_prefix },
{ CH_CHARACTERS, 3, 1, S_OK, L"\n" },
{ CH_STARTPREFIXMAPPING, 3, 24, S_OK, L"p", L"test" },
{ CH_STARTELEMENT, 3, 24, S_OK, L"prefix", L"node1", L"node1", NULL },
{ CH_ENDELEMENT, 3, 24, S_OK, L"prefix", L"node1", L"node1" },
{ CH_ENDPREFIXMAPPING, 3, 24, S_OK, L"p" },
{ CH_ENDELEMENT, 3, 35, S_OK, L"prefix", L"document", L"document" },
{ CH_ENDPREFIXMAPPING, 3, 35, S_OK, L"test" },
{ CH_ENDPREFIXMAPPING, 3, 35, S_OK, L"" },
{ CH_ENDDOCUMENT, 4, 0, S_OK },
{ CH_ENDTEST }
};
static struct attribute_entry xmlspace_attrs[] =
{
{ L"http://www.w3.org/XML/1998/namespace", L"space", L"xml:space", L"preserve" },
{ NULL }
};
static struct call_entry xmlspaceattr_test_alternate[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 39, S_OK },
{ CH_STARTELEMENT, 1, 63, S_OK, L"", L"a", L"a", xmlspace_attrs },
{ CH_CHARACTERS, 1, 80, S_OK, L" Some text data " },
{ CH_ENDELEMENT, 1, 83, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 1, 83, S_OK },
{ CH_ENDTEST }
};
/* attribute value normalization test */
static const char attribute_normalize[] =
"<?xml version=\"1.0\" ?>\n"
"<a attr1=\" \r \n \tattr_value &#65; &#38; &amp;\t \r \n\r\n \n\"/>\n";
static struct attribute_entry attribute_norm_attrs[] =
{
{ L"", L"attr1", L"attr1", L" attr_value A & & " },
{ NULL }
};
static struct call_entry attribute_norm_alt[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTELEMENT, 8, 3, S_OK, L"", L"a", L"a", attribute_norm_attrs },
{ CH_ENDELEMENT, 8, 3, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 9, 0, S_OK },
{ CH_ENDTEST }
};
static struct call_entry pi_test[] =
{
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTELEMENT, 1, 25, S_OK, L"", L"a", L"a" },
{ CH_PROCESSINGINSTRUCTION, 3, 4, S_OK, L"t", L"some t\nex\nt " },
{ CH_ENDELEMENT, 3, 8, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 3, 8, S_OK },
{ CH_ENDTEST }
};
static struct call_entry chardata_test_v4[] =
{
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTELEMENT, 1, 25, S_OK, L"", L"a", L"a" },
{ CH_CHARACTERS, 2, 4, S_OK, L"\nabc" },
{ CH_STARTELEMENT, 2, 6, S_OK, L"", L"b", L"b" },
{ CH_CHARACTERS, 3, 2, S_OK, L"de\nf" },
{ CH_ENDELEMENT, 3, 5, S_OK, L"", L"b", L"b" },
{ CH_CHARACTERS, 4, 1, S_OK, L"gh\n" },
{ CH_ENDELEMENT, 4, 4, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 4, 4, S_OK },
{ CH_ENDTEST }
};
static struct call_entry chardata_test2_v4[] =
{
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTELEMENT, 1, 25, S_OK, L"", L"a", L"a" },
{ CH_CHARACTERS, 2, 0, S_OK, L"\n" },
{ CH_CHARACTERS, 2, 4, S_OK, L"abc" },
{ CH_STARTELEMENT, 2, 6, S_OK, L"", L"b", L"b" },
{ CH_CHARACTERS, 2, 9, S_OK, L"de" },
{ CH_CHARACTERS, 3, 0, S_OK, L"\n" },
{ CH_CHARACTERS, 3, 2, S_OK, L"f" },
{ CH_ENDELEMENT, 3, 5, S_OK, L"", L"b", L"b" },
{ CH_CHARACTERS, 3, 8, S_OK, L"gh" },
{ CH_CHARACTERS, 4, 0, S_OK, L"\n" },
{ CH_ENDELEMENT, 4, 4, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 4, 4, S_OK },
{ CH_ENDTEST }
};
/* this is what MSXML6 does */
static struct call_entry cdata_test_alt[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTELEMENT, 1, 25, S_OK, L"", L"a", L"a" },
{ LH_STARTCDATA, 1, 34, S_OK },
{ CH_CHARACTERS, 1, 40, S_OK, L"Some " },
{ CH_CHARACTERS, 2, 0, S_OK, L"\n" },
{ CH_CHARACTERS, 3, 1, S_OK, L"text\n" },
{ CH_CHARACTERS, 4, 0, S_OK, L"\n" },
{ CH_CHARACTERS, 6, 3, S_OK, L"data\n\n" },
{ LH_ENDCDATA, 6, 3, S_OK },
{ CH_ENDELEMENT, 6, 7, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 6, 7, S_OK },
{ CH_ENDTEST }
};
static struct call_entry cdata_test2_alt[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTELEMENT, 1, 25, S_OK, L"", L"a", L"a" },
{ LH_STARTCDATA, 1, 34, S_OK },
{ CH_CHARACTERS, 2, 1, S_OK, L"\n" },
{ CH_CHARACTERS, 3, 0, S_OK, L"\n" },
{ CH_CHARACTERS, 3, 6, S_OK, L"Some " },
{ CH_CHARACTERS, 4, 0, S_OK, L"\n" },
{ CH_CHARACTERS, 5, 1, S_OK, L"text\n" },
{ CH_CHARACTERS, 6, 0, S_OK, L"\n" },
{ CH_CHARACTERS, 8, 3, S_OK, L"data\n\n" },
{ LH_ENDCDATA, 8, 3, S_OK },
{ CH_ENDELEMENT, 8, 7, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 8, 7, S_OK },
{ CH_ENDTEST }
};
static struct call_entry cdata_test3_alt[] = {
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 22, S_OK },
{ CH_STARTELEMENT, 1, 25, S_OK, L"", L"a", L"a" },
{ LH_STARTCDATA, 1, 34, S_OK },
{ CH_CHARACTERS, 1, 51, S_OK, L"Some text data" },
{ LH_ENDCDATA, 1, 51, S_OK },
{ CH_ENDELEMENT, 1, 55, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 1, 55, S_OK },
{ CH_ENDTEST }
};
static struct attribute_entry read_test_attrs[] =
{
{ L"", L"attr", L"attr", L"val" },
{ NULL }
};
static struct call_entry read_test_seq[] = {
{ CH_PUTDOCUMENTLOCATOR, -1, 0, S_OK },
{ CH_STARTDOCUMENT, -1, -1, S_OK },
{ CH_STARTELEMENT, -1, -1, S_OK, L"", L"rootelem", L"rootelem" },
{ CH_STARTELEMENT, -1, -1, S_OK, L"", L"elem", L"elem", read_test_attrs },
{ CH_CHARACTERS, -1, -1, S_OK, L"text" },
{ CH_ENDELEMENT, -1, -1, S_OK, L"", L"elem", L"elem" },
{ CH_STARTELEMENT, -1, -1, S_OK, L"", L"elem", L"elem", read_test_attrs },
{ CH_CHARACTERS, -1, -1, S_OK, L"text" },
{ CH_ENDELEMENT, -1, -1, S_OK, L"", L"elem", L"elem" },
{ CH_STARTELEMENT, -1, -1, S_OK, L"", L"elem", L"elem", read_test_attrs },
{ CH_CHARACTERS, -1, -1, S_OK, L"text" },
{ CH_ENDELEMENT, -1, -1, S_OK, L"", L"elem", L"elem" },
{ CH_STARTELEMENT, -1, -1, S_OK, L"", L"elem", L"elem", read_test_attrs },
{ CH_CHARACTERS, -1, -1, S_OK, L"text" },
{ CH_ENDELEMENT, -1, -1, S_OK, L"", L"elem", L"elem" },
{ CH_ENDELEMENT, -1, -1, S_OK, L"", L"rootelem", L"rootelem" },
{ CH_ENDDOCUMENT, -1, -1, S_OK},
{ CH_ENDTEST }
};
static const char xmlspace_attr[] =
"<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
"<a xml:space=\"preserve\"> Some text data </a>";
static struct call_entry *expectCall;
static ISAXLocator *locator;
static ISAXXMLReader *g_reader;
static void set_expected_seq(struct call_entry *expected)
{
expectCall = expected;
}
/* to be called once on each tested callback return */
static HRESULT get_expected_ret(void)
{
HRESULT hr = expectCall->ret;
if (expectCall->id != CH_ENDTEST) expectCall++;
return hr;
}
static HRESULT WINAPI contentHandler_QueryInterface(
ISAXContentHandler* iface,
REFIID riid,
void **ppvObject)
{
*ppvObject = NULL;
if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
{
*ppvObject = iface;
}
else
{
return E_NOINTERFACE;
}
return S_OK;
}
static ULONG WINAPI contentHandler_AddRef(
ISAXContentHandler* iface)
{
return 2;
}
static ULONG WINAPI contentHandler_Release(
ISAXContentHandler* iface)
{
return 1;
}
static HRESULT WINAPI contentHandler_putDocumentLocator(
ISAXContentHandler* iface,
ISAXLocator *pLocator)
{
struct call_entry call;
IUnknown *unk;
HRESULT hr;
locator = pLocator;
init_call_entry(locator, &call);
call.id = CH_PUTDOCUMENTLOCATOR;
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXLocator, (void**)&unk);
ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
return get_expected_ret();
}
static ISAXAttributes *test_attr_ptr;
static HRESULT WINAPI contentHandler_startDocument(
ISAXContentHandler* iface)
{
struct call_entry call;
init_call_entry(locator, &call);
call.id = CH_STARTDOCUMENT;
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
test_attr_ptr = NULL;
return get_expected_ret();
}
static HRESULT WINAPI contentHandler_endDocument(
ISAXContentHandler* iface)
{
struct call_entry call;
init_call_entry(locator, &call);
call.id = CH_ENDDOCUMENT;
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static HRESULT WINAPI contentHandler_startPrefixMapping(
ISAXContentHandler* iface,
const WCHAR *prefix, int prefix_len,
const WCHAR *uri, int uri_len)
{
struct call_entry call;
ok(prefix != NULL, "prefix == NULL\n");
ok(uri != NULL, "uri == NULL\n");
init_call_entry(locator, &call);
call.id = CH_STARTPREFIXMAPPING;
call.arg1W = SysAllocStringLen(prefix, prefix_len);
call.arg2W = SysAllocStringLen(uri, uri_len);
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static HRESULT WINAPI contentHandler_endPrefixMapping(
ISAXContentHandler* iface,
const WCHAR *prefix, int len)
{
struct call_entry call;
ok(prefix != NULL, "prefix == NULL\n");
init_call_entry(locator, &call);
call.id = CH_ENDPREFIXMAPPING;
call.arg1W = SysAllocStringLen(prefix, len);
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static HRESULT WINAPI contentHandler_startElement(
ISAXContentHandler* iface,
const WCHAR *uri, int uri_len,
const WCHAR *localname, int local_len,
const WCHAR *qname, int qname_len,
ISAXAttributes *saxattr)
{
struct call_entry call;
HRESULT hr;
int len;
ok(uri != NULL, "uri == NULL\n");
ok(localname != NULL, "localname == NULL\n");
ok(qname != NULL, "qname == NULL\n");
ok(!!saxattr, "Unexpected pointer.\n");
check_interface(saxattr, &IID_ISAXAttributes, TRUE);
check_interface(saxattr, &IID_ISAXLocator, TRUE);
check_interface(saxattr, &IID_IMXAttributes, FALSE);
check_interface(saxattr, &IID_IVBSAXAttributes, FALSE);
check_interface(saxattr, &IID_IVBSAXLocator, FALSE);
check_interface(saxattr, &IID_IDispatch, FALSE);
check_interface(saxattr, &IID_IDispatchEx, FALSE);
todo_wine
check_interface(saxattr, &IID_ISAXXMLReader, TRUE);
check_interface(saxattr, &IID_IVBSAXXMLReader, FALSE);
init_call_entry(locator, &call);
call.id = CH_STARTELEMENT;
call.arg1W = SysAllocStringLen(uri, uri_len);
call.arg2W = SysAllocStringLen(localname, local_len);
call.arg3W = SysAllocStringLen(qname, qname_len);
if(!test_attr_ptr)
test_attr_ptr = saxattr;
ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr);
hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
todo_wine
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
/* store actual attributes */
len = 0;
hr = ISAXAttributes_getLength(saxattr, &len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (len)
{
VARIANT_BOOL v;
int i;
struct attribute_entry *attr;
attr = calloc(len, sizeof(*attr));
v = VARIANT_TRUE;
hr = ISAXXMLReader_getFeature(g_reader, L"http://xml.org/sax/features/namespaces", &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
for (i = 0; i < len; i++)
{
const WCHAR *value;
int value_len;
hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len,
&localname, &local_len, &qname, &qname_len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* if 'namespaces' switched off uri and local name contains garbage */
if (v == VARIANT_FALSE)
{
attr[i].uriW = SysAllocStringLen(NULL, 0);
attr[i].localW = SysAllocStringLen(NULL, 0);
}
else
{
attr[i].uriW = SysAllocStringLen(uri, uri_len);
attr[i].localW = SysAllocStringLen(localname, local_len);
}
attr[i].qnameW = SysAllocStringLen(qname, qname_len);
attr[i].valueW = SysAllocStringLen(value, value_len);
}
call.attributes = attr;
call.attr_count = len;
}
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static HRESULT WINAPI contentHandler_endElement(
ISAXContentHandler* iface,
const WCHAR *uri, int uri_len,
const WCHAR *localname, int local_len,
const WCHAR *qname, int qname_len)
{
struct call_entry call;
ok(uri != NULL, "uri == NULL\n");
ok(localname != NULL, "localname == NULL\n");
ok(qname != NULL, "qname == NULL\n");
init_call_entry(locator, &call);
call.id = CH_ENDELEMENT;
call.arg1W = SysAllocStringLen(uri, uri_len);
call.arg2W = SysAllocStringLen(localname, local_len);
call.arg3W = SysAllocStringLen(qname, qname_len);
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static HRESULT WINAPI contentHandler_characters(
ISAXContentHandler* iface,
const WCHAR *chars,
int len)
{
struct call_entry call;
ok(chars != NULL, "chars == NULL\n");
init_call_entry(locator, &call);
call.id = CH_CHARACTERS;
call.arg1W = SysAllocStringLen(chars, len);
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static HRESULT WINAPI contentHandler_ignorableWhitespace(
ISAXContentHandler* iface,
const WCHAR *chars, int len)
{
struct call_entry call;
ok(chars != NULL, "chars == NULL\n");
init_call_entry(locator, &call);
call.id = CH_IGNORABLEWHITESPACE;
call.arg1W = SysAllocStringLen(chars, len);
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static HRESULT WINAPI contentHandler_processingInstruction(
ISAXContentHandler* iface,
const WCHAR *target, int target_len,
const WCHAR *data, int data_len)
{
struct call_entry call;
ok(target != NULL, "target == NULL\n");
ok(data != NULL, "data == NULL\n");
init_call_entry(locator, &call);
call.id = CH_PROCESSINGINSTRUCTION;
call.arg1W = SysAllocStringLen(target, target_len);
call.arg2W = SysAllocStringLen(data, data_len);
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static HRESULT WINAPI contentHandler_skippedEntity(
ISAXContentHandler* iface,
const WCHAR *name, int len)
{
struct call_entry call;
ok(name != NULL, "name == NULL\n");
init_call_entry(locator, &call);
call.id = CH_SKIPPEDENTITY;
call.arg1W = SysAllocStringLen(name, len);
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static const ISAXContentHandlerVtbl contentHandlerVtbl =
{
contentHandler_QueryInterface,
contentHandler_AddRef,
contentHandler_Release,
contentHandler_putDocumentLocator,
contentHandler_startDocument,
contentHandler_endDocument,
contentHandler_startPrefixMapping,
contentHandler_endPrefixMapping,
contentHandler_startElement,
contentHandler_endElement,
contentHandler_characters,
contentHandler_ignorableWhitespace,
contentHandler_processingInstruction,
contentHandler_skippedEntity
};
static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
static HRESULT WINAPI isaxerrorHandler_QueryInterface(
ISAXErrorHandler* iface,
REFIID riid,
void **ppvObject)
{
*ppvObject = NULL;
if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
{
*ppvObject = iface;
}
else
{
return E_NOINTERFACE;
}
return S_OK;
}
static ULONG WINAPI isaxerrorHandler_AddRef(
ISAXErrorHandler* iface)
{
return 2;
}
static ULONG WINAPI isaxerrorHandler_Release(
ISAXErrorHandler* iface)
{
return 1;
}
static HRESULT WINAPI isaxerrorHandler_error(
ISAXErrorHandler* iface,
ISAXLocator *pLocator,
const WCHAR *pErrorMessage,
HRESULT hrErrorCode)
{
ok(0, "unexpected call\n");
return S_OK;
}
static HRESULT WINAPI isaxerrorHandler_fatalError(
ISAXErrorHandler* iface,
ISAXLocator *pLocator,
const WCHAR *message,
HRESULT hr)
{
struct call_entry call;
init_call_entry(locator, &call);
call.id = EH_FATALERROR;
call.ret = hr;
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
get_expected_ret();
return S_OK;
}
static HRESULT WINAPI isaxerrorHandler_ignorableWarning(
ISAXErrorHandler* iface,
ISAXLocator *pLocator,
const WCHAR *pErrorMessage,
HRESULT hrErrorCode)
{
ok(0, "unexpected call\n");
return S_OK;
}
static const ISAXErrorHandlerVtbl errorHandlerVtbl =
{
isaxerrorHandler_QueryInterface,
isaxerrorHandler_AddRef,
isaxerrorHandler_Release,
isaxerrorHandler_error,
isaxerrorHandler_fatalError,
isaxerrorHandler_ignorableWarning
};
static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
static HRESULT WINAPI isaxattributes_QueryInterface(
ISAXAttributes* iface,
REFIID riid,
void **ppvObject)
{
*ppvObject = NULL;
if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
{
*ppvObject = iface;
}
else
{
return E_NOINTERFACE;
}
return S_OK;
}
static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
{
return 2;
}
static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
{
return 1;
}
static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
{
*length = 4;
return S_OK;
}
static HRESULT WINAPI isaxattributes_getURI(
ISAXAttributes* iface,
int nIndex,
const WCHAR **pUrl,
int *pUriSize)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI isaxattributes_getLocalName(
ISAXAttributes* iface,
int nIndex,
const WCHAR **pLocalName,
int *pLocalNameLength)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI isaxattributes_getQName(
ISAXAttributes* iface,
int index,
const WCHAR **QName,
int *QNameLength)
{
static const WCHAR attrqnamesW[][15] = {L"a:attr1junk",
L"attr2junk",
L"attr3",
L"attr4"};
static const int attrqnamelen[] = {7, 5, 5, 5};
ok(index >= 0 && index <= 3, "invalid index received %d\n", index);
if (index >= 0 && index <= 3)
{
*QName = attrqnamesW[index];
*QNameLength = attrqnamelen[index];
}
else
{
*QName = NULL;
*QNameLength = 0;
}
return S_OK;
}
static HRESULT WINAPI isaxattributes_getName(
ISAXAttributes* iface,
int nIndex,
const WCHAR **pUri,
int * pUriLength,
const WCHAR ** pLocalName,
int * pLocalNameSize,
const WCHAR ** pQName,
int * pQNameLength)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI isaxattributes_getIndexFromName(
ISAXAttributes* iface,
const WCHAR * pUri,
int cUriLength,
const WCHAR * pLocalName,
int cocalNameLength,
int * index)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI isaxattributes_getIndexFromQName(
ISAXAttributes* iface,
const WCHAR * pQName,
int nQNameLength,
int * index)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI isaxattributes_getType(
ISAXAttributes* iface,
int nIndex,
const WCHAR ** pType,
int * pTypeLength)
{
ok(0, "unexpected call\n");
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)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI isaxattributes_getTypeFromQName(
ISAXAttributes* iface,
const WCHAR * pQName,
int nQName,
const WCHAR ** pType,
int * nType)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index,
const WCHAR **value, int *nValue)
{
static const WCHAR attrvaluesW[][10] = {L"a1junk",
L"a2junk",
L"<&\">'",
L"a\rb\nc\r\n"};
static const int attrvalueslen[] = {2, 2, 5, 7};
ok(index >= 0 && index <= 3, "invalid index received %d\n", index);
if (index >= 0 && index <= 3)
{
*value = attrvaluesW[index];
*nValue = attrvalueslen[index];
}
else
{
*value = NULL;
*nValue = 0;
}
return S_OK;
}
static HRESULT WINAPI isaxattributes_getValueFromName(
ISAXAttributes* iface,
const WCHAR * pUri,
int nUri,
const WCHAR * pLocalName,
int nLocalName,
const WCHAR ** pValue,
int * nValue)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI isaxattributes_getValueFromQName(
ISAXAttributes* iface,
const WCHAR * pQName,
int nQName,
const WCHAR ** pValue,
int * nValue)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static const ISAXAttributesVtbl SAXAttributesVtbl =
{
isaxattributes_QueryInterface,
isaxattributes_AddRef,
isaxattributes_Release,
isaxattributes_getLength,
isaxattributes_getURI,
isaxattributes_getLocalName,
isaxattributes_getQName,
isaxattributes_getName,
isaxattributes_getIndexFromName,
isaxattributes_getIndexFromQName,
isaxattributes_getType,
isaxattributes_getTypeFromName,
isaxattributes_getTypeFromQName,
isaxattributes_getValue,
isaxattributes_getValueFromName,
isaxattributes_getValueFromQName
};
static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
struct saxlexicalhandler
{
ISAXLexicalHandler ISAXLexicalHandler_iface;
LONG ref;
HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
};
static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface )
{
return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface);
}
static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out)
{
struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
*out = NULL;
if (IsEqualGUID(riid, &IID_IUnknown))
{
*out = iface;
ok(0, "got unexpected IID_IUnknown query\n");
}
else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler))
{
if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
*out = iface;
}
if (*out)
ISAXLexicalHandler_AddRef(iface);
else
return E_NOINTERFACE;
return S_OK;
}
static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
{
struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
return InterlockedIncrement(&handler->ref);
}
static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
{
struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface);
return InterlockedDecrement(&handler->ref);
}
static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
const WCHAR * pName, int nName, const WCHAR * pPublicId,
int nPublicId, const WCHAR * pSystemId, int nSystemId)
{
return S_OK;
}
static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
{
return S_OK;
}
static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
const WCHAR * pName, int nName)
{
ok(0, "call not expected\n");
return E_NOTIMPL;
}
static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
const WCHAR * pName, int nName)
{
ok(0, "call not expected\n");
return E_NOTIMPL;
}
static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
{
struct call_entry call;
init_call_entry(locator, &call);
call.id = LH_STARTCDATA;
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
{
struct call_entry call;
init_call_entry(locator, &call);
call.id = LH_ENDCDATA;
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
const WCHAR *chars, int len)
{
struct call_entry call;
init_call_entry(locator, &call);
call.id = LH_COMMENT;
call.arg1W = SysAllocStringLen(chars, len);
add_call(sequences, CONTENT_HANDLER_INDEX, &call);
return get_expected_ret();
}
static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
{
isaxlexical_QueryInterface,
isaxlexical_AddRef,
isaxlexical_Release,
isaxlexical_startDTD,
isaxlexical_endDTD,
isaxlexical_startEntity,
isaxlexical_endEntity,
isaxlexical_startCDATA,
isaxlexical_endCDATA,
isaxlexical_comment
};
static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr)
{
handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
handler->ref = 1;
handler->qi_hr = hr;
}
struct saxdeclhandler
{
ISAXDeclHandler ISAXDeclHandler_iface;
LONG ref;
HRESULT qi_hr; /* ret value for QueryInterface for handler riid */
};
static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface )
{
return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface);
}
static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out)
{
struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
*out = NULL;
if (IsEqualGUID(riid, &IID_IUnknown))
{
*out = iface;
ok(0, "got unexpected IID_IUnknown query\n");
}
else if (IsEqualGUID(riid, &IID_ISAXDeclHandler))
{
if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr;
*out = iface;
}
if (*out)
ISAXDeclHandler_AddRef(iface);
else
return E_NOINTERFACE;
return S_OK;
}
static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
{
struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
return InterlockedIncrement(&handler->ref);
}
static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
{
struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface);
return InterlockedDecrement(&handler->ref);
}
static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
{
return S_OK;
}
static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
int nValueDefault, const WCHAR * pValue, int nValue)
{
return S_OK;
}
static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
{
return S_OK;
}
static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
const WCHAR * pSystemId, int nSystemId)
{
return S_OK;
}
static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
{
isaxdecl_QueryInterface,
isaxdecl_AddRef,
isaxdecl_Release,
isaxdecl_elementDecl,
isaxdecl_attributeDecl,
isaxdecl_internalEntityDecl,
isaxdecl_externalEntityDecl
};
static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr)
{
handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
handler->ref = 1;
handler->qi_hr = hr;
}
static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
{
*ppvObject = NULL;
ok(!IsEqualGUID(riid, &IID_IPersistStream), "Did not expect QI for IPersistStream\n");
if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
*ppvObject = iface;
else
return E_NOINTERFACE;
return S_OK;
}
static ULONG WINAPI istream_AddRef(IStream *iface)
{
return 2;
}
static ULONG WINAPI istream_Release(IStream *iface)
{
return 1;
}
static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI istream_Revert(IStream *iface)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb, DWORD dwLockType)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb, DWORD dwLockType)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
{
return E_NOTIMPL;
}
static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static int read_cnt;
static HRESULT WINAPI instream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
{
static const char *ret_str;
if(!read_cnt)
ret_str = "<?xml version=\"1.0\" ?>\n<rootelem>";
else if(read_cnt < 5)
ret_str = "<elem attr=\"val\">text</elem>";
else if(read_cnt == 5)
ret_str = "</rootelem>\n";
else
ret_str = "";
read_cnt++;
strcpy(pv, ret_str);
*pcbRead = strlen(ret_str);
return S_OK;
}
static const IStreamVtbl instreamVtbl = {
istream_QueryInterface,
istream_AddRef,
istream_Release,
instream_Read,
istream_Write,
istream_Seek,
istream_SetSize,
istream_CopyTo,
istream_Commit,
istream_Revert,
istream_LockRegion,
istream_UnlockRegion,
istream_Stat,
istream_Clone
};
static IStream instream = { &instreamVtbl };
static struct saxlexicalhandler lexicalhandler;
static struct saxdeclhandler declhandler;
static IStream *create_test_stream(const char *data, int len)
{
ULARGE_INTEGER size;
LARGE_INTEGER pos;
IStream *stream;
ULONG written;
if (len == -1) len = strlen(data);
CreateStreamOnHGlobal(NULL, TRUE, &stream);
size.QuadPart = len;
IStream_SetSize(stream, size);
IStream_Write(stream, data, len, &written);
pos.QuadPart = 0;
IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
return stream;
}
static void test_saxreader(void)
{
HRESULT hr;
ISAXXMLReader *reader = NULL;
VARIANT var;
ISAXContentHandler *content;
ISAXErrorHandler *lpErrorHandler;
SAFEARRAY *sa;
SAFEARRAYBOUND SADim[1];
char *ptr = NULL;
IStream *stream;
ULONG written;
HANDLE file;
static const CHAR testXmlA[] = "test.xml";
IXMLDOMDocument *doc;
VARIANT_BOOL v;
struct call_entry *test_seq;
ISAXEntityResolver *resolver;
BSTR str;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
g_reader = reader;
check_interface(reader, &IID_IUnknown, TRUE);
check_interface(reader, &IID_ISAXXMLReader, TRUE);
todo_wine
check_interface(reader, &IID_ISAXLocator, TRUE);
todo_wine
check_interface(reader, &IID_IDispatch, FALSE);
todo_wine
check_interface(reader, &IID_IDispatchEx, FALSE);
todo_wine
check_interface(reader, &IID_IVBSAXXMLReader, FALSE);
check_interface(reader, &IID_IVBSAXLocator, FALSE);
hr = ISAXXMLReader_getContentHandler(reader, &content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(content == NULL, "Expected %p, got %p\n", NULL, content);
hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
hr = ISAXXMLReader_putContentHandler(reader, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXXMLReader_getContentHandler(reader, &content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(szSimpleXML);
test_seq = content_handler_test1_alternate;
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 1", FALSE);
VariantClear(&var);
SADim[0].lLbound = 0;
SADim[0].cElements = sizeof(testXML)-1;
sa = SafeArrayCreate(VT_UI1, 1, SADim);
SafeArrayAccessData(sa, (void**)&ptr);
memcpy(ptr, testXML, sizeof(testXML)-1);
SafeArrayUnaccessData(sa);
V_VT(&var) = VT_ARRAY|VT_UI1;
V_ARRAY(&var) = sa;
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 1: from safe array", FALSE);
SafeArrayDestroy(sa);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = NULL;
hr = ISAXXMLReader_parse(reader, var);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
V_VT(&var) = VT_DISPATCH;
V_DISPATCH(&var) = NULL;
hr = ISAXXMLReader_parse(reader, var);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
stream = create_test_stream(testXML, -1);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown*)stream;
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 1: from stream", FALSE);
IStream_Release(stream);
stream = create_test_stream(test_attributes, -1);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown*)stream;
test_seq = content_handler_test_attributes_alternate_4;
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", FALSE);
IStream_Release(stream);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown*)&instream;
test_seq = read_test_seq;
read_cnt = 0;
set_expected_seq(test_seq);
hr = ISAXXMLReader_parse(reader, var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(read_cnt == 7, "read_cnt = %d\n", read_cnt);
ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "Read call test", FALSE);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(carriage_ret_test);
test_seq = content_handler_test2_alternate;
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 2", FALSE);
VariantClear(&var);
/* from file url */
file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
ok(file != INVALID_HANDLE_VALUE, "Could not create file: %lu\n", GetLastError());
WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL);
CloseHandle(file);
test_seq = content_handler_test1_alternate;
set_expected_seq(test_seq);
hr = ISAXXMLReader_parseURL(reader, L"test.xml");
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE);
/* error handler */
test_seq = content_handler_testerror_alternate;
set_expected_seq(test_seq);
hr = ISAXXMLReader_parseURL(reader, L"test.xml");
ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE);
/* callback ret values */
test_seq = content_handler_test_callback_rets_alt;
set_expected_seq(test_seq);
hr = ISAXXMLReader_parseURL(reader, L"test.xml");
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE);
DeleteFileA(testXmlA);
/* parse from IXMLDOMDocument */
hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
&IID_IXMLDOMDocument, (void**)&doc);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
str = SysAllocString(szSimpleXML);
hr = IXMLDOMDocument_loadXML(doc, str, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
SysFreeString(str);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown*)doc;
test_seq = content_handler_test2_alternate;
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, "parse from IXMLDOMDocument", FALSE);
IXMLDOMDocument_Release(doc);
/* xml:space test */
test_seq = xmlspaceattr_test_alternate;
set_expected_seq(test_seq);
V_VT(&var) = VT_BSTR;
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", FALSE);
/* switch off 'namespaces' feature */
hr = ISAXXMLReader_putFeature(reader, L"http://xml.org/sax/features/namespaces", VARIANT_FALSE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
stream = create_test_stream(test_attributes, -1);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown*)stream;
test_seq = content_handler_test_attributes_alt_no_ns;
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", 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);
/* switch off 'namespace-prefixes' feature */
hr = ISAXXMLReader_putFeature(reader, L"http://xml.org/sax/features/namespace-prefixes", VARIANT_FALSE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
stream = create_test_stream(test_attributes, -1);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown*)stream;
test_seq = content_handler_test_attributes_alt_no_prefix;
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", FALSE);
IStream_Release(stream);
hr = ISAXXMLReader_putFeature(reader, L"http://xml.org/sax/features/namespace-prefixes", VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* attribute normalization */
stream = create_test_stream(attribute_normalize, -1);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown*)stream;
test_seq = attribute_norm_alt;
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, "attribute value normalization", FALSE);
IStream_Release(stream);
resolver = (void*)0xdeadbeef;
hr = ISAXXMLReader_getEntityResolver(reader, &resolver);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(resolver == NULL, "got %p\n", resolver);
hr = ISAXXMLReader_putEntityResolver(reader, NULL);
ok(hr == S_OK || broken(hr == E_FAIL), "Unexpected hr %#lx.\n", hr);
ISAXXMLReader_Release(reader);
free_bstrs();
}
static void test_saxreader_cdata(void)
{
struct call_entry *test_seq;
ISAXXMLReader *reader;
IStream *stream;
VARIANT var;
HRESULT hr;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
g_reader = reader;
hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* CDATA sections */
init_saxlexicalhandler(&lexicalhandler, S_OK);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown *)&lexicalhandler.ISAXLexicalHandler_iface;
hr = ISAXXMLReader_putProperty(reader, L"http://xml.org/sax/properties/lexical-handler", var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
stream = create_test_stream(test_cdata_xml, -1);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown *)stream;
test_seq = cdata_test_alt;
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", TRUE);
IStream_Release(stream);
/* 2. CDATA sections */
stream = create_test_stream(test2_cdata_xml, -1);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown*)stream;
test_seq = cdata_test2_alt;
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 2", TRUE);
IStream_Release(stream);
/* 3. CDATA sections */
stream = create_test_stream(test3_cdata_xml, -1);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown *)stream;
test_seq = cdata_test3_alt;
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", FALSE);
IStream_Release(stream);
ISAXXMLReader_Release(reader);
free_bstrs();
}
static void test_saxreader_pi(void)
{
ISAXXMLReader *reader;
VARIANT var;
HRESULT hr;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
g_reader = reader;
hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* PI */
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown *)create_test_stream(test_pi_xml, -1);
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", FALSE);
VariantClear(&var);
ISAXXMLReader_Release(reader);
free_bstrs();
}
static void test_saxreader_characters(void)
{
struct call_entry *test_seq;
ISAXXMLReader *reader;
VARIANT var;
HRESULT hr;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
g_reader = reader;
hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* Character data. */
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown *)create_test_stream(test_chardata_xml, -1);
test_seq = chardata_test_v4;
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, "char data test", FALSE);
VariantClear(&var);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown *)create_test_stream(test_chardata_xml2, -1);
test_seq = chardata_test2_v4;
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, "char data test 2", TRUE);
VariantClear(&var);
ISAXXMLReader_Release(reader);
free_bstrs();
}
static void test_saxreader_properties(void)
{
static const struct saxreader_props_test_t
{
const WCHAR *prop_name;
IUnknown *iface;
}
props_test_data[] =
{
{ L"http://xml.org/sax/properties/lexical-handler", (IUnknown *)&lexicalhandler.ISAXLexicalHandler_iface },
{ L"http://xml.org/sax/properties/declaration-handler", (IUnknown *)&declhandler.ISAXDeclHandler_iface },
{ 0 }
};
const struct saxreader_props_test_t *ptr = props_test_data;
IVBSAXXMLReader *vb_reader;
ISAXXMLReader *reader;
HRESULT hr;
VARIANT v;
BSTR str;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
while (ptr->prop_name)
{
VARIANT varref;
LONG ref;
init_saxlexicalhandler(&lexicalhandler, S_OK);
init_saxdeclhandler(&declhandler, S_OK);
V_VT(&v) = VT_EMPTY;
V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, ptr->prop_name, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
/* VT_UNKNOWN */
V_VT(&v) = VT_UNKNOWN;
V_UNKNOWN(&v) = ptr->iface;
ref = get_refcount(ptr->iface);
hr = ISAXXMLReader_putProperty(reader, ptr->prop_name, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(ref < get_refcount(ptr->iface), "Unexpected refcount.\n");
/* VT_DISPATCH */
V_VT(&v) = VT_DISPATCH;
V_UNKNOWN(&v) = ptr->iface;
ref = get_refcount(ptr->iface);
hr = ISAXXMLReader_putProperty(reader, ptr->prop_name, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(ref == get_refcount(ptr->iface), "got wrong refcount %ld, expected %ld\n", get_refcount(ptr->iface), ref);
/* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */
V_VT(&varref) = VT_UNKNOWN;
V_UNKNOWN(&varref) = ptr->iface;
V_VT(&v) = VT_VARIANT|VT_BYREF;
V_VARIANTREF(&v) = &varref;
ref = get_refcount(ptr->iface);
hr = ISAXXMLReader_putProperty(reader, ptr->prop_name, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(ref == get_refcount(ptr->iface), "got wrong refcount %ld, expected %ld\n", get_refcount(ptr->iface), ref);
/* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */
V_VT(&varref) = VT_DISPATCH;
V_UNKNOWN(&varref) = ptr->iface;
V_VT(&v) = VT_VARIANT|VT_BYREF;
V_VARIANTREF(&v) = &varref;
ref = get_refcount(ptr->iface);
hr = ISAXXMLReader_putProperty(reader, ptr->prop_name, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(ref == get_refcount(ptr->iface), "got wrong refcount %ld, expected %ld\n", get_refcount(ptr->iface), ref);
V_VT(&v) = VT_EMPTY;
V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
ref = get_refcount(ptr->iface);
hr = ISAXXMLReader_getProperty(reader, ptr->prop_name, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n");
VariantClear(&v);
V_VT(&v) = VT_EMPTY;
V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
hr = ISAXXMLReader_putProperty(reader, ptr->prop_name, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&v) = VT_EMPTY;
V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, ptr->prop_name, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
V_VT(&v) = VT_UNKNOWN;
V_UNKNOWN(&v) = ptr->iface;
hr = ISAXXMLReader_putProperty(reader, ptr->prop_name, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* only VT_EMPTY seems to be valid to reset property */
V_VT(&v) = VT_I4;
V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
hr = ISAXXMLReader_putProperty(reader, ptr->prop_name, v);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
V_VT(&v) = VT_EMPTY;
V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, ptr->prop_name, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
VariantClear(&v);
V_VT(&v) = VT_UNKNOWN;
V_UNKNOWN(&v) = NULL;
hr = ISAXXMLReader_putProperty(reader, ptr->prop_name, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&v) = VT_EMPTY;
V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, ptr->prop_name, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
/* block QueryInterface on handler riid */
V_VT(&v) = VT_UNKNOWN;
V_UNKNOWN(&v) = ptr->iface;
hr = ISAXXMLReader_putProperty(reader, ptr->prop_name, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE);
init_saxdeclhandler(&declhandler, E_NOINTERFACE);
V_VT(&v) = VT_UNKNOWN;
V_UNKNOWN(&v) = ptr->iface;
EXPECT_REF(ptr->iface, 1);
ref = get_refcount(ptr->iface);
hr = ISAXXMLReader_putProperty(reader, ptr->prop_name, v);
ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
EXPECT_REF(ptr->iface, 1);
V_VT(&v) = VT_EMPTY;
V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, ptr->prop_name, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v));
ptr++;
free_bstrs();
}
ISAXXMLReader_Release(reader);
/* Getters with VB interface */
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_IVBSAXXMLReader, (void **)&vb_reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&v) = VT_EMPTY;
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);
ok(V_VT(&v) == VT_DISPATCH, "Unexpected type %d.\n", V_VT(&v));
ok(!V_DISPATCH(&v), "Unexpected value %p.\n", V_UNKNOWN(&v));
V_VT(&v) = VT_EMPTY;
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);
ok(V_VT(&v) == VT_DISPATCH, "Unexpected type %d.\n", V_VT(&v));
ok(!V_DISPATCH(&v), "Unexpected value %p.\n", V_UNKNOWN(&v));
IVBSAXXMLReader_Release(vb_reader);
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER,
&IID_ISAXXMLReader, (void**)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* xmldecl-version property */
V_VT(&v) = VT_EMPTY;
V_BSTR(&v) = (void*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, L"xmldecl-version", &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
/* stream without declaration */
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = _bstr_("<element></element>");
hr = ISAXXMLReader_parse(reader, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&v) = VT_EMPTY;
V_BSTR(&v) = (void*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, L"xmldecl-version", &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
V_VT(&v) = VT_EMPTY;
V_BSTR(&v) = (void*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, L"xmldecl-encoding", &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
ok(!V_BSTR(&v), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
V_VT(&v) = VT_EMPTY;
V_BSTR(&v) = (void*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, L"charset", &v);
todo_wine
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine
ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
todo_wine
ok(!V_BSTR(&v), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
/* stream with declaration */
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>");
hr = ISAXXMLReader_parse(reader, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* VT_BSTR|VT_BYREF input type */
str = _bstr_("<?xml version=\"1.0\"?><element></element>");
V_VT(&v) = VT_BSTR|VT_BYREF;
V_BSTRREF(&v) = &str;
hr = ISAXXMLReader_parse(reader, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&v) = VT_EMPTY;
V_BSTR(&v) = (void*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, L"xmldecl-version", &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
ok(!lstrcmpW(V_BSTR(&v), L"1.0"), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
VariantClear(&v);
/* Encoding specified */
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = _bstr_("<?xml version=\"1.0\" encoding=\"uTf-16\"?><element></element>");
hr = ISAXXMLReader_parse(reader, v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&v) = VT_EMPTY;
V_BSTR(&v) = (void*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, L"xmldecl-encoding", &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
ok(!wcscmp(V_BSTR(&v), L"uTf-16"), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
VariantClear(&v);
V_VT(&v) = VT_EMPTY;
V_BSTR(&v) = (void*)0xdeadbeef;
hr = ISAXXMLReader_getProperty(reader, L"charset", &v);
todo_wine
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine
ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
todo_wine
ok(!V_BSTR(&v), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
ISAXXMLReader_Release(reader);
free_bstrs();
}
static void test_saxreader_max_xml_size(void)
{
static const char test_text[] =
"aaaaaaaaaa"
"aaaaaaaaaa"
"aaaaaaaaaa"
"aaaaaaaaaa"
"aaaaaaaaaa"
"aaaaaaaaaa"
"aaaaaaaaaa"
"aaaaaaaaaa"
"aaaaaaaaaa"
"aaaaaaaaaa";
ISAXXMLReader *reader;
LARGE_INTEGER pos;
IStream *stream;
DWORD written;
VARIANT var;
HRESULT hr;
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
IStream_Write(stream, "<a>", 3, &written);
for (int i = 0; i < 20; ++i)
IStream_Write(stream, test_text, sizeof(test_text)-1, &written);
IStream_Write(stream, "</a>", 4, &written);
pos.QuadPart = 0;
IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&var) = VT_EMPTY;
V_I4(&var) = 123;
hr = ISAXXMLReader_getProperty(reader, L"max-xml-size", &var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&var) == VT_I4, "Unexpected type %d.\n", V_VT(&var));
ok(!V_I4(&var), "Unexpected value %ld.\n", V_I4(&var));
V_VT(&var) = VT_R4;
V_R4(&var) = 10.0;
hr = ISAXXMLReader_putProperty(reader, L"max-xml-size", var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&var) = VT_EMPTY;
V_I4(&var) = 0;
hr = ISAXXMLReader_getProperty(reader, L"max-xml-size", &var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&var) == VT_I4, "Unexpected type %d.\n", V_VT(&var));
ok(V_I4(&var) == 10, "Unexpected value %ld.\n", V_I4(&var));
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = _bstr_("abc");
hr = ISAXXMLReader_putProperty(reader, L"max-xml-size", var);
ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
V_VT(&var) = VT_EMPTY;
V_I4(&var) = 0;
hr = ISAXXMLReader_getProperty(reader, L"max-xml-size", &var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&var) == VT_I4, "Unexpected type %d.\n", V_VT(&var));
ok(V_I4(&var) == 10, "Unexpected value %ld.\n", V_I4(&var));
V_VT(&var) = VT_I4;
V_I4(&var) = -123;
hr = ISAXXMLReader_putProperty(reader, L"max-xml-size", var);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
V_VT(&var) = VT_I4;
V_I4(&var) = 4194304;
hr = ISAXXMLReader_putProperty(reader, L"max-xml-size", var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&var) = VT_I4;
V_I4(&var) = 4194305;
hr = ISAXXMLReader_putProperty(reader, L"max-xml-size", var);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
/* Limit to 1K */
V_VT(&var) = VT_I4;
V_I4(&var) = 1;
hr = ISAXXMLReader_putProperty(reader, L"max-xml-size", var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
pos.QuadPart = 0;
IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown *)stream;
hr = ISAXXMLReader_parse(reader, var);
ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
V_VT(&var) = VT_I4;
V_I4(&var) = 3;
hr = ISAXXMLReader_putProperty(reader, L"max-xml-size", var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
pos.QuadPart = 0;
IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
V_VT(&var) = VT_UNKNOWN;
V_UNKNOWN(&var) = (IUnknown *)stream;
hr = ISAXXMLReader_parse(reader, var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ISAXXMLReader_Release(reader);
free_bstrs();
IStream_Release(stream);
}
static void test_saxreader_normalize_line_breaks(void)
{
ISAXXMLReader *reader;
VARIANT_BOOL v;
HRESULT hr;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
v = 123;
hr = ISAXXMLReader_getFeature(reader, L"normalize-line-breaks", &v);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
ok(v == 123, "Unexpected value %d.\n", v);
hr = ISAXXMLReader_putFeature(reader, L"normalize-line-breaks", VARIANT_FALSE);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXXMLReader_putFeature(reader, L"normalize-line-breaks", VARIANT_TRUE);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
ISAXXMLReader_Release(reader);
}
static void test_saxreader_exhaustive_errors(void)
{
ISAXXMLReader *reader;
VARIANT_BOOL v;
HRESULT hr;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
v = VARIANT_TRUE;
hr = ISAXXMLReader_getFeature(reader, L"exhaustive-errors", &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(v == VARIANT_FALSE, "Unexpected value %d.\n", v);
hr = ISAXXMLReader_putFeature(reader, L"exhaustive-errors", VARIANT_TRUE);
todo_wine
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXXMLReader_putFeature(reader, L"exhaustive-errors", VARIANT_FALSE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ISAXXMLReader_Release(reader);
}
static void test_saxreader_features(void)
{
static const WCHAR *feature_names[] =
{
L"http://xml.org/sax/features/namespaces",
L"http://xml.org/sax/features/namespace-prefixes",
NULL
};
ISAXXMLReader *reader;
VARIANT_BOOL value;
const WCHAR **name;
HRESULT hr;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
value = VARIANT_TRUE;
hr = ISAXXMLReader_getFeature(reader, L"exhaustive-errors", &value);
ok(hr == S_OK, "Failed to get feature value, hr %#lx.\n", hr);
ok(value == VARIANT_FALSE, "Unexpected default feature value.\n");
hr = ISAXXMLReader_putFeature(reader, L"exhaustive-errors", VARIANT_FALSE);
ok(hr == S_OK, "Failed to put feature value, hr %#lx.\n", hr);
value = VARIANT_TRUE;
hr = ISAXXMLReader_getFeature(reader, L"schema-validation", &value);
ok(hr == S_OK, "Failed to get feature value, hr %#lx.\n", hr);
ok(value == VARIANT_FALSE, "Unexpected default feature value.\n");
hr = ISAXXMLReader_putFeature(reader, L"exhaustive-errors", VARIANT_FALSE);
ok(hr == S_OK, "Failed to put feature value, hr %#lx.\n", hr);
name = feature_names;
while (*name)
{
value = 0xc;
hr = ISAXXMLReader_getFeature(reader, *name, &value);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(value == VARIANT_TRUE, "Unexpected value %#x.\n", value);
value = 0xc;
hr = ISAXXMLReader_putFeature(reader, *name, value);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
value = 0xd;
hr = ISAXXMLReader_getFeature(reader, *name, &value);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(value == VARIANT_TRUE, "Unexpected value %#x.\n", value);
hr = ISAXXMLReader_putFeature(reader, *name, VARIANT_FALSE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
value = 0xd;
hr = ISAXXMLReader_getFeature(reader, *name, &value);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(value == VARIANT_FALSE, "Unexpected value %#x.\n", value);
hr = ISAXXMLReader_putFeature(reader, *name, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
value = 0xd;
hr = ISAXXMLReader_getFeature(reader, *name, &value);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(value == VARIANT_TRUE, "Unexpected value %#x.\n", value);
name++;
}
ISAXXMLReader_Release(reader);
}
/* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
static const CHAR UTF8BOMTest[] =
"\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
"<a></a>\n";
static void create_test_file(const char *name, const void *data, DWORD size)
{
DWORD written;
HANDLE file;
file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
ok(file != INVALID_HANDLE_VALUE, "Could not create file: %lu\n", GetLastError());
WriteFile(file, data, size, &written, NULL);
CloseHandle(file);
}
static const WCHAR _80[] = {0x0080,0};
static struct call_entry xml_iso_8859_1_seq[] =
{
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 44, S_OK },
{ CH_STARTELEMENT, 1, 47, S_OK, L"", L"a", L"a" },
{ CH_CHARACTERS, 1, 49, S_OK, _80 },
{ CH_ENDELEMENT, 1, 52, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 1, 52, S_OK },
{ CH_ENDTEST }
};
static struct call_entry xml_win1252_seq[] =
{
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 46, S_OK },
{ CH_STARTELEMENT, 1, 49, S_OK, L"", L"a", L"a" },
{ CH_CHARACTERS, 1, 52, S_OK, L"\u00c1\u20ac" },
{ CH_ENDELEMENT, 1, 55, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 1, 55, S_OK },
{ CH_ENDTEST }
};
static struct call_entry xml_win1253_seq[] =
{
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 46, S_OK },
{ CH_STARTELEMENT, 1, 49, S_OK, L"", L"a", L"a" },
{ CH_CHARACTERS, 1, 51, S_OK, L"\u0391" },
{ CH_ENDELEMENT, 1, 54, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 1, 54, S_OK },
{ CH_ENDTEST }
};
static struct call_entry xml_us_ascii_seq[] =
{
{ CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK },
{ CH_STARTDOCUMENT, 1, 42, S_OK },
{ CH_STARTELEMENT, 1, 45, S_OK, L"", L"a", L"a" },
{ CH_CHARACTERS, 1, 47, S_OK, L"A" },
{ CH_ENDELEMENT, 1, 50, S_OK, L"", L"a", L"a" },
{ CH_ENDDOCUMENT, 1, 50, S_OK },
{ CH_ENDTEST }
};
static void test_saxreader_encoding(void)
{
static const DWORD ucs4_le_test[] =
{
'<','a','>','t','e','x','t','<','/','a','>',
};
static const char xml_win1252_test[] =
"<?xml version=\"1.0\" encoding=\"windows-1252\" ?><a>" "\xc1" "\x80" "</a>";
static const char xml_win1253_test[] =
"<?xml version=\"1.0\" encoding=\"windows-1253\" ?><a>" "\xc1" "</a>";
static const char xml_us_ascii_test[] =
"<?xml version=\"1.0\" encoding=\"us-ascii\" ?><a>" "\xc1" "</a>";
static const char xml_iso_8859_1_test[] =
"<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?><a>" "\x80" "</a>";
static const CHAR testXmlA[] = "test.xml";
DWORD ucs4_be_test[ARRAYSIZE(ucs4_le_test)];
ISAXXMLReader *reader;
VARIANT input;
HRESULT hr;
for (int i = 0; i < ARRAYSIZE(ucs4_le_test); ++i)
ucs4_be_test[i] = (ucs4_le_test[i] & 0xff) << 24;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* UTF-8 with BOM */
create_test_file(testXmlA, UTF8BOMTest, sizeof(UTF8BOMTest)-1);
hr = ISAXXMLReader_parseURL(reader, L"test.xml");
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
DeleteFileA(testXmlA);
/* UCS-4 LE */
create_test_file(testXmlA, ucs4_le_test, sizeof(ucs4_le_test));
hr = ISAXXMLReader_parseURL(reader, L"test.xml");
todo_wine
ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
DeleteFileA(testXmlA);
/* UCS-4 BE */
create_test_file(testXmlA, ucs4_be_test, sizeof(ucs4_be_test));
hr = ISAXXMLReader_parseURL(reader, L"test.xml");
todo_wine
ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
DeleteFileA(testXmlA);
/* try BSTR input with no BOM or '<?xml' instruction */
V_VT(&input) = VT_BSTR;
V_BSTR(&input) = _bstr_("<element></element>");
hr = ISAXXMLReader_parse(reader, input);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ISAXXMLReader_Release(reader);
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
create_test_file(testXmlA, xml_win1252_test, sizeof(xml_win1252_test) - 1);
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", 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-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");
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
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", FALSE);
DeleteFileA(testXmlA);
ISAXXMLReader_Release(reader);
free_bstrs();
}
static void test_mxwriter_handlers(void)
{
IMXWriter *writer;
HRESULT hr;
int i;
static REFIID riids[] =
{
&IID_ISAXContentHandler,
&IID_ISAXLexicalHandler,
&IID_ISAXDeclHandler,
&IID_ISAXDTDHandler,
&IID_ISAXErrorHandler,
&IID_IVBSAXDeclHandler,
&IID_IVBSAXLexicalHandler,
&IID_IVBSAXContentHandler,
&IID_IVBSAXDTDHandler,
&IID_IVBSAXErrorHandler
};
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
EXPECT_REF(writer, 1);
for (i = 0; i < ARRAY_SIZE(riids); i++)
{
IUnknown *handler;
IMXWriter *writer2;
/* handler from IMXWriter */
hr = IMXWriter_QueryInterface(writer, riids[i], (void**)&handler);
ok(hr == S_OK, "%s, unexpected hr %#lx.\n", wine_dbgstr_guid(riids[i]), hr);
/* IMXWriter from a handler */
hr = IUnknown_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
ok(hr == S_OK, "%s, unexpected hr %#lx.\n", wine_dbgstr_guid(riids[i]), hr);
ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
IMXWriter_Release(writer2);
IUnknown_Release(handler);
}
IMXWriter_Release(writer);
}
static void test_mxwriter_default_properties(void)
{
IMXWriter *writer;
VARIANT_BOOL b;
BSTR encoding;
HRESULT hr;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
b = VARIANT_FALSE;
hr = IMXWriter_get_byteOrderMark(writer, &b);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(b == VARIANT_TRUE, "Unexpected value %#x.\n", b);
b = VARIANT_TRUE;
hr = IMXWriter_get_disableOutputEscaping(writer, &b);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(b == VARIANT_FALSE, "Unexpected value %#x.\n", b);
b = VARIANT_TRUE;
hr = IMXWriter_get_indent(writer, &b);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(b == VARIANT_FALSE, "Unexpected value %#x.\n", b);
b = VARIANT_TRUE;
hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(b == VARIANT_FALSE, "Unexpected value %#x.\n", b);
b = VARIANT_TRUE;
hr = IMXWriter_get_standalone(writer, &b);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(b == VARIANT_FALSE, "Unexpected value %#x.\n", b);
hr = IMXWriter_get_encoding(writer, &encoding);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(encoding, L"UTF-16"), "Unexpected encoding %s.\n", wine_dbgstr_w(encoding));
SysFreeString(encoding);
IMXWriter_Release(writer);
}
static void test_mxwriter_properties(void)
{
ISAXContentHandler *content;
IMXWriter *writer;
VARIANT_BOOL b;
HRESULT hr;
BSTR str, str2;
VARIANT dest;
test_mxwriter_default_properties();
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_get_byteOrderMark(writer, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_get_indent(writer, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_get_standalone(writer, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
/* set and check */
hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
b = VARIANT_FALSE;
hr = IMXWriter_get_standalone(writer, &b);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(b == VARIANT_TRUE, "got %d\n", b);
hr = IMXWriter_get_encoding(writer, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
/* UTF-16 is a default setting apparently */
str = (void*)0xdeadbeef;
hr = IMXWriter_get_encoding(writer, &str);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(str, L"UTF-16"), "Unexpected string %s.\n", wine_dbgstr_w(str));
str2 = (void*)0xdeadbeef;
hr = IMXWriter_get_encoding(writer, &str2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(str != str2, "expected newly allocated, got same %p\n", str);
SysFreeString(str2);
SysFreeString(str);
/* put empty string */
str = SysAllocString(L"");
hr = IMXWriter_put_encoding(writer, str);
todo_wine
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
SysFreeString(str);
str = (void*)0xdeadbeef;
hr = IMXWriter_get_encoding(writer, &str);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(str, L"UTF-16"), "got %s\n", wine_dbgstr_w(str));
SysFreeString(str);
/* invalid encoding name */
str = SysAllocString(L"test");
hr = IMXWriter_put_encoding(writer, str);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
SysFreeString(str);
/* test case sensitivity */
hr = IMXWriter_put_encoding(writer, _bstr_("utf-8"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
str = (void*)0xdeadbeef;
hr = IMXWriter_get_encoding(writer, &str);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(str, L"utf-8"), "got %s\n", wine_dbgstr_w(str));
SysFreeString(str);
hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
str = (void*)0xdeadbeef;
hr = IMXWriter_get_encoding(writer, &str);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(str, L"uTf-16"), "got %s\n", wine_dbgstr_w(str));
SysFreeString(str);
/* how it affects document creation */
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
todo_wine
ok(!lstrcmpW(L"<?xml version=\"1.0\" standalone=\"yes\"?>\r\n",
V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
hr = IMXWriter_get_version(writer, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
/* default version is 'surprisingly' 1.0 */
hr = IMXWriter_get_version(writer, &str);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(str, L"1.0"), "got %s\n", wine_dbgstr_w(str));
SysFreeString(str);
/* store version string as is */
hr = IMXWriter_put_version(writer, NULL);
todo_wine
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_version(writer, _bstr_("1.0"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_version(writer, _bstr_(""));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_get_version(writer, &str);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine
ok(!lstrcmpW(str, L"1.0"), "got %s\n", wine_dbgstr_w(str));
SysFreeString(str);
hr = IMXWriter_put_version(writer, _bstr_("a.b"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_get_version(writer, &str);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(str, L"a.b"), "got %s\n", wine_dbgstr_w(str));
SysFreeString(str);
hr = IMXWriter_put_version(writer, _bstr_("2.0"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_get_version(writer, &str);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(str, L"2.0"), "got %s\n", wine_dbgstr_w(str));
SysFreeString(str);
IMXWriter_Release(writer);
free_bstrs();
}
static void test_mxwriter_flush(void)
{
ISAXContentHandler *content;
IMXWriter *writer;
LARGE_INTEGER pos;
ULARGE_INTEGER pos2;
IStream *stream;
VARIANT dest;
HRESULT hr;
char *buff;
LONG ref;
int len;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
EXPECT_REF(stream, 1);
/* detach when nothing was attached */
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* attach stream */
V_VT(&dest) = VT_UNKNOWN;
V_UNKNOWN(&dest) = (IUnknown*)stream;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine EXPECT_REF(stream, 3);
/* detach setting VT_EMPTY destination */
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
EXPECT_REF(stream, 1);
V_VT(&dest) = VT_UNKNOWN;
V_UNKNOWN(&dest) = (IUnknown*)stream;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* flush() doesn't detach a stream */
hr = IMXWriter_flush(writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine EXPECT_REF(stream, 3);
pos.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(pos2.QuadPart == 0, "expected stream beginning\n");
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
pos.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(pos2.QuadPart != 0, "expected stream beginning\n");
/* already started */
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* flushed on endDocument() */
pos.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(pos2.QuadPart != 0, "expected stream position moved\n");
IStream_Release(stream);
/* auto-flush feature */
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
EXPECT_REF(stream, 1);
V_VT(&dest) = VT_UNKNOWN;
V_UNKNOWN(&dest) = (IUnknown*)stream;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"a", -1, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* internal buffer is flushed automatically on certain threshold */
pos.QuadPart = 0;
pos2.QuadPart = 1;
hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(pos2.QuadPart == 0, "expected stream beginning\n");
len = 2048;
buff = malloc(len + 1);
memset(buff, 'A', len);
buff[len] = 0;
hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
pos.QuadPart = 0;
pos2.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(pos2.QuadPart != 0, "unexpected stream beginning\n");
hr = IMXWriter_get_output(writer, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
ref = get_refcount(stream);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest));
ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest));
ok(ref+1 == get_refcount(stream), "expected increased refcount\n");
VariantClear(&dest);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
IStream_Release(stream);
/* test char count lower than threshold */
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
EXPECT_REF(stream, 1);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"a", -1, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
pos.QuadPart = 0;
pos2.QuadPart = 1;
hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(pos2.QuadPart == 0, "expected stream beginning\n");
memset(buff, 'A', len);
buff[len] = 0;
hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
pos.QuadPart = 0;
pos2.QuadPart = 1;
hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(pos2.QuadPart == 0, "expected stream beginning\n");
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* test auto-flush function when stream is not set */
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"a", -1, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
memset(buff, 'A', len);
buff[len] = 0;
hr = ISAXContentHandler_characters(content, _bstr_(buff), len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
len += strlen("<a>");
ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len);
VariantClear(&dest);
free(buff);
ISAXContentHandler_Release(content);
IStream_Release(stream);
IMXWriter_Release(writer);
free_bstrs();
}
static void test_mxwriter_startenddocument(void)
{
ISAXContentHandler *content;
IMXWriter *writer;
VARIANT dest;
HRESULT hr;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void **)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n", V_BSTR(&dest)),
"got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
/* now try another startDocument */
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* and get duplicated prolog */
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
"<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n", V_BSTR(&dest)),
"got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
/* now with omitted declaration */
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
free_bstrs();
}
enum startendtype
{
StartElement = 0x001,
EndElement = 0x010,
StartEndElement = 0x011,
DisableEscaping = 0x100
};
struct writer_startendelement_t {
const GUID *clsid;
enum startendtype type;
const WCHAR *uri;
const WCHAR *local_name;
const WCHAR *qname;
const WCHAR *output;
HRESULT hr;
ISAXAttributes *attr;
};
static const WCHAR startelement_xml[] = L"<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\'\" attr4=\"a&#xA;b&#xA;c&#xA;\">";
static const WCHAR startendelement_xml[] = L"<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"&lt;&amp;&quot;&gt;\'\" attr4=\"a&#xA;b&#xA;c&#xA;\"/>";
static const struct writer_startendelement_t writer_startendelement[] =
{
{ &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
{ &CLSID_MXXMLWriter40, StartElement, L"uri", NULL, NULL, NULL, E_INVALIDARG },
{ &CLSID_MXXMLWriter40, StartElement, NULL, L"local", NULL, NULL, E_INVALIDARG },
{ &CLSID_MXXMLWriter40, StartElement, NULL, NULL, L"qname", NULL, E_INVALIDARG },
{ &CLSID_MXXMLWriter40, StartElement, L"uri", L"local", L"qname", L"<qname>", S_OK },
{ &CLSID_MXXMLWriter40, StartElement, L"uri", L"local", NULL, NULL, E_INVALIDARG },
{ &CLSID_MXXMLWriter40, StartElement, L"uri", L"local", L"uri:local", L"<uri:local>", S_OK },
{ &CLSID_MXXMLWriter40, StartElement, L"uri", L"local", L"uri:local2", L"<uri:local2>", S_OK },
/* endElement tests */
{ &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
{ &CLSID_MXXMLWriter40, EndElement, L"uri", NULL, NULL, NULL, E_INVALIDARG },
{ &CLSID_MXXMLWriter40, EndElement, NULL, L"local", NULL, NULL, E_INVALIDARG },
{ &CLSID_MXXMLWriter40, EndElement, NULL, NULL, L"qname", NULL, E_INVALIDARG },
{ &CLSID_MXXMLWriter40, EndElement, L"uri", L"local", L"qname", L"</qname>", S_OK },
{ &CLSID_MXXMLWriter40, EndElement, L"uri", L"local", NULL, NULL, E_INVALIDARG },
{ &CLSID_MXXMLWriter40, EndElement, L"uri", L"local", L"uri:local", L"</uri:local>", S_OK },
{ &CLSID_MXXMLWriter40, EndElement, L"uri", L"local", L"uri:local2", L"</uri:local2>", S_OK },
/* with attributes */
{ &CLSID_MXXMLWriter40, StartElement, L"uri", L"local", L"uri:local", startelement_xml, S_OK, &saxattributes },
/* empty elements */
{ &CLSID_MXXMLWriter40, StartEndElement, L"uri", L"local", L"uri:local", startendelement_xml, S_OK, &saxattributes },
{ &CLSID_MXXMLWriter40, StartEndElement, L"", L"", L"", L"</>", S_OK },
/* with disabled output escaping */
{ &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, L"uri", L"local", L"uri:local", startendelement_xml, S_OK, &saxattributes },
{ NULL }
};
struct class_support
{
const GUID *clsid;
const char *name;
const IID *iid;
BOOL supported;
};
static struct class_support class_support[] =
{
{ &CLSID_MXXMLWriter40, "MXXMLWriter40", &IID_IMXWriter },
{ &CLSID_SAXAttributes40, "SAXAttributes40", &IID_IMXAttributes },
{ &CLSID_SAXXMLReader40, "SAXXMLReader40", &IID_ISAXXMLReader },
{ NULL }
};
static void get_class_support_data(void)
{
struct class_support *table = class_support;
while (table->clsid)
{
IUnknown *unk;
HRESULT hr;
hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, table->iid, (void **)&unk);
if (hr == S_OK) IUnknown_Release(unk);
table->supported = hr == S_OK;
if (hr != S_OK) win_skip("class %s not supported\n", table->name);
table++;
}
}
static BOOL is_clsid_supported(const GUID *clsid)
{
const struct class_support *table = class_support;
while (table->clsid)
{
if (table->clsid == clsid) return table->supported;
table++;
}
return FALSE;
}
static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
{
int i = 0;
while (table->clsid)
{
ISAXContentHandler *content;
IMXWriter *writer;
HRESULT hr;
hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
&IID_IMXWriter, (void**)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (table->type & DisableEscaping)
{
hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
}
if (table->type & StartElement)
{
hr = ISAXContentHandler_startElement(content, table->uri, table->uri ? lstrlenW(table->uri) : 0,
table->local_name, table->local_name ? lstrlenW(table->local_name) : 0, table->qname,
table->qname ? lstrlenW(table->qname) : 0, table->attr);
ok(hr == table->hr, "test %d: got %#lx, expected %#lx\n", i, hr, table->hr);
}
if (table->type & EndElement)
{
hr = ISAXContentHandler_endElement(content, table->uri, table->uri ? lstrlenW(table->uri) : 0,
table->local_name, table->local_name ? lstrlenW(table->local_name) : 0, table->qname,
table->qname ? lstrlenW(table->qname) : 0);
ok(hr == table->hr, "test %d: got %#lx, expected %#lx\n", i, hr, table->hr);
}
/* test output */
if (hr == S_OK)
{
VARIANT dest;
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(table->output, V_BSTR(&dest)),
"test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), wine_dbgstr_w(table->output));
VariantClear(&dest);
}
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
table++;
i++;
}
free_bstrs();
}
/* point of these test is to start/end element with different names and name lengths */
struct writer_startendelement2_t {
const GUID *clsid;
const WCHAR *qnamestart;
int qnamestart_len;
const WCHAR *qnameend;
int qnameend_len;
const WCHAR *output;
HRESULT hr;
};
static const struct writer_startendelement2_t writer_startendelement2[] = {
{ &CLSID_MXXMLWriter40, L"a", -1, L"b", -1, L"<a/>", S_OK },
{ &CLSID_MXXMLWriter40, L"a", 1, L"b", 1, L"<a/>", S_OK },
{ NULL }
};
static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table)
{
int i = 0;
while (table->clsid)
{
ISAXContentHandler *content;
IMXWriter *writer;
HRESULT hr;
hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
&IID_IMXWriter, (void**)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, table->qnamestart, table->qnamestart_len, NULL);
ok(hr == table->hr, "test %d: got %#lx, expected %#lx\n", i, hr, table->hr);
hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, table->qnameend, table->qnameend_len);
ok(hr == table->hr, "test %d: got %#lx, expected %#lx\n", i, hr, table->hr);
/* test output */
if (hr == S_OK)
{
VARIANT dest;
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(table->output, V_BSTR(&dest)),
"test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), wine_dbgstr_w(table->output));
VariantClear(&dest);
}
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
table++;
i++;
free_bstrs();
}
}
static void test_mxwriter_startendelement(void)
{
ISAXContentHandler *content;
IVBSAXContentHandler *vb_content;
IMXWriter *writer;
VARIANT dest;
BSTR bstr_null = NULL, bstr_empty, bstr_a, bstr_b, bstr_ab;
HRESULT hr;
test_mxwriter_startendelement_batch(writer_startendelement);
test_mxwriter_startendelement_batch2(writer_startendelement2);
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXContentHandler, (void**)&vb_content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXContentHandler_startDocument(vb_content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
bstr_empty = SysAllocString(L"");
bstr_a = SysAllocString(L"a");
bstr_b = SysAllocString(L"b");
bstr_ab = SysAllocString(L"a:b");
hr = IVBSAXContentHandler_startElement(vb_content, &bstr_null, &bstr_empty, &bstr_b, NULL);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXContentHandler_startElement(vb_content, &bstr_empty, &bstr_b, &bstr_empty, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = IVBSAXContentHandler_startElement(vb_content, &bstr_empty, &bstr_empty, &bstr_b, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<><b>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = IVBSAXContentHandler_endElement(vb_content, &bstr_null, &bstr_null, &bstr_b);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXContentHandler_endElement(vb_content, &bstr_null, &bstr_a, &bstr_b);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXContentHandler_endElement(vb_content, &bstr_a, &bstr_b, &bstr_null);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXContentHandler_endElement(vb_content, &bstr_empty, &bstr_null, &bstr_b);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXContentHandler_endElement(vb_content, &bstr_empty, &bstr_b, &bstr_null);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXContentHandler_endElement(vb_content, &bstr_empty, &bstr_empty, &bstr_b);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<><b></b>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
SysFreeString(bstr_empty);
SysFreeString(bstr_a);
SysFreeString(bstr_b);
SysFreeString(bstr_ab);
hr = IVBSAXContentHandler_endDocument(vb_content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
IVBSAXContentHandler_Release(vb_content);
IMXWriter_Release(writer);
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* all string pointers should be not null */
hr = ISAXContentHandler_startElement(content, L"", 0, L"b", 1, L"", 0, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"b", 1, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<><b>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, L"a:b", 3);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endElement(content, NULL, 0, L"b", 1, L"a:b", 3);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
/* only local name is an error too */
hr = ISAXContentHandler_endElement(content, NULL, 0, L"b", 1, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"b", 1);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<><b></b>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"abcdef", 3, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<abc>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
IMXWriter_flush(writer);
hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"abdcdef", 3);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<abc></abd>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* length -1 */
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"a", -1, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<a>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
free_bstrs();
}
struct writer_characters_t {
const GUID *clsid;
const WCHAR *data;
const WCHAR *output;
};
static const struct writer_characters_t writer_characters[] =
{
{ &CLSID_MXXMLWriter40, L"< > & \" \'", L"&lt; &gt; &amp; \" \'" },
{ NULL }
};
static void test_mxwriter_characters(void)
{
static const WCHAR embedded_nullbytes[] = L"a\0b\0\0\0c";
const struct writer_characters_t *table = writer_characters;
IVBSAXContentHandler *vb_content;
ISAXContentHandler *content;
IMXWriter *writer;
VARIANT dest;
BSTR str;
HRESULT hr;
int i = 0;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void **)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXContentHandler, (void **)&vb_content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, L"TESTCHARDATA .", 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
str = _bstr_("VbChars");
hr = IVBSAXContentHandler_characters(vb_content, &str);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, L"TESTCHARDATA .", 14);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"VbCharsTESTCHARDATA .", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ISAXContentHandler_Release(content);
IVBSAXContentHandler_Release(vb_content);
IMXWriter_Release(writer);
/* try empty characters data to see if element is closed */
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void **)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"a", 1, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, L"TESTCHARDATA .", 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"a", 1);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<a></a>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
/* test embedded null bytes */
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void **)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(SysStringLen(V_BSTR(&dest)) == ARRAY_SIZE(embedded_nullbytes), "unexpected len %d\n", SysStringLen(V_BSTR(&dest)));
ok(!memcmp(V_BSTR(&dest), embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes)),
"got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void**)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXContentHandler, (void **)&vb_content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXContentHandler_startDocument(vb_content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
str = SysAllocStringLen(embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes));
hr = IVBSAXContentHandler_characters(vb_content, &str);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
SysFreeString(str);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
todo_wine
ok(SysStringLen(V_BSTR(&dest)) == 1, "Unexpected length %d.\n", SysStringLen(V_BSTR(&dest)));
ok(!memcmp(V_BSTR(&dest), embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes)),
"got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
IVBSAXContentHandler_Release(vb_content);
IMXWriter_Release(writer);
/* Newlines in consecutive calls */
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void **)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, L"ab\r", 3);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, L"\ncd", 3);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "Unexpected type %d.\n", V_VT(&dest));
ok(!lstrcmpW(L"ab\r\n\r\ncd", V_BSTR(&dest)), "Unexpected content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, L"\nab\rc\r\n", 7);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "Unexpected type %d.\n", V_VT(&dest));
ok(!lstrcmpW(L"\r\nab\r\nc\r\n", V_BSTR(&dest)), "Unexpected content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
while (table->clsid)
{
hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
&IID_IMXWriter, (void**)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, table->data, lstrlenW(table->data));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* test output */
if (hr == S_OK)
{
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(table->output, V_BSTR(&dest)),
"test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), wine_dbgstr_w(table->output));
VariantClear(&dest);
}
/* with disabled escaping */
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, table->data, lstrlenW(table->data));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* test output */
if (hr == S_OK)
{
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(table->data, V_BSTR(&dest)),
"test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), wine_dbgstr_w(table->data));
VariantClear(&dest);
}
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
table++;
i++;
}
free_bstrs();
}
static void test_mxwriter_stream(void)
{
IMXWriter *writer;
ISAXContentHandler *content;
HRESULT hr;
VARIANT dest;
IStream *stream;
LARGE_INTEGER pos;
ULARGE_INTEGER pos2;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_UNKNOWN;
V_UNKNOWN(&dest) = (IUnknown*)stream;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* Setting output of the mxwriter causes the current output to be flushed,
* and the writer to start over.
*/
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
pos.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(pos2.QuadPart != 0, "expected stream position moved\n");
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
todo_wine
ok(!lstrcmpW(L"<?xml version=\"1.0\" standalone=\"no\"?>\r\n", V_BSTR(&dest)),
"Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
/* test when BOM is written to output stream */
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
pos.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_UNKNOWN;
V_UNKNOWN(&dest) = (IUnknown*)stream;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
pos.QuadPart = 0;
pos2.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(pos2.QuadPart == 2, "got wrong position\n");
IStream_Release(stream);
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
free_bstrs();
}
static const char *encoding_names[] = {
"iso-8859-1",
"iso-8859-2",
"iso-8859-3",
"iso-8859-4",
"iso-8859-5",
"iso-8859-7",
"iso-8859-9",
"iso-8859-13",
"iso-8859-15",
NULL
};
static void test_mxwriter_encoding(void)
{
ISAXContentHandler *content;
IMXWriter *writer;
IStream *stream;
const char *enc;
VARIANT dest;
HRESULT hr;
HGLOBAL g;
char *ptr;
BSTR s;
int i;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* The content is always re-encoded to UTF-16 when the output is
* retrieved as a BSTR.
*/
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
todo_wine
ok(!lstrcmpW(L"<?xml version=\"1.0\" standalone=\"no\"?>\r\n", V_BSTR(&dest)),
"got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
/* switch encoding when something is written already */
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_UNKNOWN;
V_UNKNOWN(&dest) = (IUnknown*)stream;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* write empty element */
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"a", 1, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"a", 1);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* switch */
hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_flush(writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = GetHGlobalFromStream(stream, &g);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ptr = GlobalLock(g);
ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]);
GlobalUnlock(g);
/* so output is unaffected, encoding name is stored however */
hr = IMXWriter_get_encoding(writer, &s);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(s, L"UTF-16"), "got %s\n", wine_dbgstr_w(s));
SysFreeString(s);
IStream_Release(stream);
i = 0;
enc = encoding_names[i];
while (enc)
{
char expectedA[200];
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_UNKNOWN;
V_UNKNOWN(&dest) = (IUnknown*)stream;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_encoding(writer, _bstr_(enc));
ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */,
"%s: encoding not accepted\n", enc);
if (hr != S_OK)
{
enc = encoding_names[++i];
IStream_Release(stream);
continue;
}
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_flush(writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* prepare expected string */
*expectedA = 0;
strcat(expectedA, "<?xml version=\"1.0\" encoding=\"");
strcat(expectedA, enc);
strcat(expectedA, "\" standalone=\"no\"?>\r\n");
hr = GetHGlobalFromStream(stream, &g);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ptr = GlobalLock(g);
ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA);
GlobalUnlock(g);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
IStream_Release(stream);
enc = encoding_names[++i];
}
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
free_bstrs();
}
static void test_obj_dispex(IUnknown *obj)
{
DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
IDispatchEx *dispex;
IUnknown *unk;
DWORD props;
UINT ticnt;
HRESULT hr;
BSTR name;
DISPID did;
hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (FAILED(hr)) return;
ticnt = 0;
hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(ticnt == 1, "ticnt=%u\n", ticnt);
name = SysAllocString(L"*");
hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
SysFreeString(name);
hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
props = 0;
hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
ok(props == 0, "Unexpected value %ld.\n", props);
hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
if (SUCCEEDED(hr)) SysFreeString(name);
hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
unk = (IUnknown*)0xdeadbeef;
hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
ok(unk == (IUnknown*)0xdeadbeef, "got %p\n", unk);
name = SysAllocString(L"testprop");
hr = IDispatchEx_GetDispID(dispex, name, fdexNameEnsure, &did);
ok(hr == DISP_E_UNKNOWNNAME, "Unexpected hr %#lx.\n", hr);
SysFreeString(name);
IDispatchEx_Release(dispex);
}
static void test_saxreader_dispex(void)
{
IVBSAXXMLReader *vbreader;
ISAXXMLReader *reader;
DISPPARAMS dispparams;
DISPID dispid;
IUnknown *unk;
VARIANT arg;
HRESULT hr;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
check_interface(reader, &IID_IUnknown, TRUE);
check_interface(reader, &IID_ISAXXMLReader, TRUE);
todo_wine
check_interface(reader, &IID_IVBSAXXMLReader, FALSE);
todo_wine
check_interface(reader, &IID_IDispatch, FALSE);
todo_wine
check_interface(reader, &IID_IDispatchEx, FALSE);
ISAXXMLReader_Release(reader);
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_IVBSAXXMLReader, (void **)&vbreader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
check_interface(vbreader, &IID_IUnknown, TRUE);
check_interface(vbreader, &IID_ISAXXMLReader, TRUE);
check_interface(vbreader, &IID_IVBSAXXMLReader, TRUE);
check_interface(vbreader, &IID_IDispatch, TRUE);
check_interface(vbreader, &IID_IDispatchEx, TRUE);
hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void **)&unk);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
test_obj_dispex(unk);
IUnknown_Release(unk);
dispid = DISPID_PROPERTYPUT;
dispparams.cArgs = 1;
dispparams.cNamedArgs = 1;
dispparams.rgdispidNamedArgs = &dispid;
dispparams.rgvarg = &arg;
V_VT(&arg) = VT_DISPATCH;
V_DISPATCH(&arg) = NULL;
/* propputref is callable as PROPERTYPUT and PROPERTYPUTREF */
hr = IVBSAXXMLReader_Invoke(vbreader,
DISPID_SAX_XMLREADER_CONTENTHANDLER,
&IID_NULL,
0,
DISPATCH_PROPERTYPUT,
&dispparams,
NULL,
NULL,
NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXXMLReader_Invoke(vbreader,
DISPID_SAX_XMLREADER_CONTENTHANDLER,
&IID_NULL,
0,
DISPATCH_PROPERTYPUTREF,
&dispparams,
NULL,
NULL,
NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
IVBSAXXMLReader_Release(vbreader);
}
static void test_mxwriter_dispex(void)
{
IDispatchEx *dispex;
IMXWriter *writer;
IUnknown *unk;
HRESULT hr;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void **)&dispex);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void **)&unk);
test_obj_dispex(unk);
IUnknown_Release(unk);
IDispatchEx_Release(dispex);
IMXWriter_Release(writer);
}
static void test_mxwriter_comment(void)
{
IVBSAXLexicalHandler *vblexical;
ISAXContentHandler *content;
ISAXLexicalHandler *lexical;
IMXWriter *writer;
VARIANT dest;
HRESULT hr;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void **)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void **)&lexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void **)&vblexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXLexicalHandler_comment(lexical, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
if (0) /* crashes */
hr = IVBSAXLexicalHandler_comment(vblexical, NULL);
hr = ISAXLexicalHandler_comment(lexical, L"comment", 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<!---->\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = ISAXLexicalHandler_comment(lexical, L"comment", 7);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<!---->\r\n<!--comment-->\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
ISAXLexicalHandler_Release(lexical);
IVBSAXLexicalHandler_Release(vblexical);
IMXWriter_Release(writer);
free_bstrs();
}
static void test_mxwriter_cdata(void)
{
IVBSAXLexicalHandler *vblexical;
ISAXContentHandler *content;
ISAXLexicalHandler *lexical;
IMXWriter *writer;
VARIANT dest;
HRESULT hr;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void **)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void **)&lexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void **)&vblexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXLexicalHandler_startCDATA(lexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<![CDATA[", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = IVBSAXLexicalHandler_startCDATA(vblexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* all these are escaped for text nodes */
hr = ISAXContentHandler_characters(content, L"< > & \"", 7);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, L"\na\rb\r\n", 6);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXLexicalHandler_endCDATA(lexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
todo_wine
ok(!lstrcmpW(L"<![CDATA[<![CDATA[< > & \"\r\na\r\nb\r\n]]>", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
ISAXLexicalHandler_Release(lexical);
IVBSAXLexicalHandler_Release(vblexical);
IMXWriter_Release(writer);
free_bstrs();
}
static void test_mxwriter_pi(void)
{
ISAXContentHandler *content;
IMXWriter *writer;
VARIANT dest;
HRESULT hr;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void **)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_processingInstruction(content, L"target", 0, NULL, 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_processingInstruction(content, L"target", 6, NULL, 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<?\?>\r\n<?target?>\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = ISAXContentHandler_processingInstruction(content, L"target", 4, L"data", 4);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<?\?>\r\n<?target?>\r\n<?targ data?>\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_processingInstruction(content, L"target", 6, L"data", 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<?target?>\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
}
static void test_mxwriter_ignorablespaces(void)
{
ISAXContentHandler *content;
IMXWriter *writer;
VARIANT dest;
HRESULT hr;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void **)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_ignorableWhitespace(content, L"data", 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_ignorableWhitespace(content, L"data", 4);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_ignorableWhitespace(content, L"data", 1);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"datad", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
}
static void test_mxwriter_dtd(void)
{
IVBSAXLexicalHandler *vblexical;
ISAXContentHandler *content;
ISAXLexicalHandler *lexical;
IVBSAXDeclHandler *vbdecl;
ISAXDeclHandler *decl;
ISAXDTDHandler *dtd;
IMXWriter *writer;
VARIANT dest;
HRESULT hr;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXDeclHandler, (void**)&vbdecl);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
if (0) /* crashes */
hr = IVBSAXLexicalHandler_startDTD(vblexical, NULL, NULL, NULL);
hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, L"pub", 3, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, L"sys", 3);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, L"pub", 3, L"sys", 3);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXLexicalHandler_startDTD(lexical, L"name", 4, NULL, 0, NULL, 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<!DOCTYPE name [\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
/* system id is required if public is present */
hr = ISAXLexicalHandler_startDTD(lexical, L"name", 4, L"pub", 3, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXLexicalHandler_startDTD(lexical, L"name", 4, L"pub", 3, L"sys", 3);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
"<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = ISAXLexicalHandler_endDTD(lexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXLexicalHandler_endDTD(vblexical);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\""
"<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n",
V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
/* element declaration */
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
if (0) /* crashes */
hr = IVBSAXDeclHandler_elementDecl(vbdecl, NULL, NULL);
hr = ISAXDeclHandler_elementDecl(decl, L"name", 4, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_elementDecl(decl, L"name", 4, L"content", 7);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<!ELEMENT name content>\r\n",
V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_elementDecl(decl, L"name", 4, L"content", 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<!ELEMENT name >\r\n",
V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
/* attribute declaration */
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_attributeDecl(decl, L"element", 7, L"attribute", 9, L"CDATA", 5,
L"#REQUIRED", 9, L"value", 5);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
todo_wine
ok(!lstrcmpW(L"<!ATTLIST element attribute CDATA #REQUIRED>\r\n",
V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
hr = ISAXDeclHandler_attributeDecl(decl, L"element", 7, L"attribute2", 10, L"CDATA", 5,
L"#REQUIRED", 9, L"value2", 6);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_attributeDecl(decl, L"element2", 8, L"attribute3", 10, L"CDATA", 5,
L"#REQUIRED", 9, L"value3", 6);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
todo_wine
ok(!lstrcmpW(L"<!ATTLIST element attribute CDATA #REQUIRED>\r\n"
"<!ATTLIST element attribute2 CDATA #REQUIRED>\r\n"
"<!ATTLIST element2 attribute3 CDATA #REQUIRED>\r\n",
V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
/* internal entities */
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
if (0) /* crashes */
hr = IVBSAXDeclHandler_internalEntityDecl(vbdecl, NULL, NULL);
hr = ISAXDeclHandler_internalEntityDecl(decl, L"name", -1, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_internalEntityDecl(decl, L"name", 4, L"value", 5);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<!ENTITY name \"value\">\r\n", V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
/* external entities */
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_externalEntityDecl(decl, NULL, 0, NULL, 0, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
if (0) /* crashes */
hr = IVBSAXDeclHandler_externalEntityDecl(vbdecl, NULL, NULL, NULL);
hr = ISAXDeclHandler_externalEntityDecl(decl, L"name", 0, NULL, 0, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_externalEntityDecl(decl, L"name", -1, NULL, 0, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_externalEntityDecl(decl, L"name", 4, L"pubid", 5, L"sysid", 5);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_externalEntityDecl(decl, L"name", 4, NULL, 0, L"sysid", 5);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDeclHandler_externalEntityDecl(decl, L"name", 4, L"pubid", 5, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<!ENTITY name PUBLIC \"pubid\" \"sysid\">\r\n<!ENTITY name SYSTEM \"sysid\">\r\n",
V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
/* notation declaration */
hr = IMXWriter_QueryInterface(writer, &IID_ISAXDTDHandler, (void**)&dtd);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_put_output(writer, dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDTDHandler_notationDecl(dtd, NULL, 0, NULL, 0, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXDTDHandler_notationDecl(dtd, L"name", 4, NULL, 0, NULL, 0);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXDTDHandler_notationDecl(dtd, L"name", 4, L"pubid", 5, NULL, 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDTDHandler_notationDecl(dtd, L"name", 4, L"pubid", 5, L"sysid", 5);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXDTDHandler_notationDecl(dtd, L"name", 4, NULL, 0, L"sysid", 5);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(
L"<!NOTATION name"
"<!NOTATION name PUBLIC \"pubid\">\r\n"
"<!NOTATION name PUBLIC \"pubid\" \"sysid\">\r\n"
"<!NOTATION name SYSTEM \"sysid\">\r\n",
V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXDTDHandler_Release(dtd);
ISAXContentHandler_Release(content);
ISAXLexicalHandler_Release(lexical);
IVBSAXLexicalHandler_Release(vblexical);
IVBSAXDeclHandler_Release(vbdecl);
ISAXDeclHandler_Release(decl);
IMXWriter_Release(writer);
free_bstrs();
}
typedef struct {
const CLSID *clsid;
const char *uri;
const char *local;
const char *qname;
const char *type;
const char *value;
HRESULT hr;
} addattribute_test_t;
static const addattribute_test_t addattribute_data[] = {
{ &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG },
{ &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG },
{ &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG },
{ &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK },
{ NULL }
};
static void test_mxattr_addAttribute(void)
{
const addattribute_test_t *table = addattribute_data;
int i = 0;
while (table->clsid)
{
ISAXAttributes *saxattr;
IMXAttributes *mxattr;
const WCHAR *value;
int len, index;
HRESULT hr;
hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
&IID_IMXAttributes, (void**)&mxattr);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
len = -1;
hr = ISAXAttributes_getLength(saxattr, &len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(len == 0, "got %d\n", len);
hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local),
_bstr_(table->qname), _bstr_(table->type), _bstr_(table->value));
ok(hr == table->hr, "%d: got %#lx, expected %#lx.\n", i, hr, table->hr);
if (hr == S_OK)
{
/* SAXAttributes40 crash on this test */
if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
{
hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getType(saxattr, 0, NULL, &len);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getType(saxattr, 0, &value, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
}
len = -1;
hr = ISAXAttributes_getValue(saxattr, 0, &value, &len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
table->value);
ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
len = -1;
value = (void*)0xdeadbeef;
hr = ISAXAttributes_getType(saxattr, 0, &value, &len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (table->type)
{
ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
table->type);
ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len);
}
else
{
ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value));
ok(len == 0, "%d: got wrong type value length %d\n", i, len);
}
hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL);
if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) ||
IsEqualGUID(table->clsid, &CLSID_SAXAttributes30))
{
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
}
else
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
index = -1;
hr = ISAXAttributes_getIndexFromQName(saxattr, L"nonexistent", 11, &index);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
ok(index == -1, "%d: got wrong index %d\n", i, index);
index = -1;
hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
ok(index == -1, "%d: got wrong index %d\n", i, index);
index = -1;
hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(index == 0, "%d: got wrong index %d\n", i, index);
index = -1;
hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
ok(index == -1, "%d: got wrong index %d\n", i, index);
if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40))
{
hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
}
else
{
hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
/* versions 4 and 6 crash */
hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local),
strlen(table->local), NULL, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
}
hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
table->value);
ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
if (table->uri) {
hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri),
_bstr_(table->local), strlen(table->local), &value, &len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value),
table->value);
ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len);
}
}
len = -1;
hr = ISAXAttributes_getLength(saxattr, &len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (table->hr == S_OK)
ok(len == 1, "%d: got %d length, expected 1\n", i, len);
else
ok(len == 0, "%d: got %d length, expected 0\n", i, len);
ISAXAttributes_Release(saxattr);
IMXAttributes_Release(mxattr);
table++;
i++;
}
free_bstrs();
}
static void test_mxattr_clear(void)
{
ISAXAttributes *saxattr;
IMXAttributes *mxattr;
const WCHAR *ptr;
HRESULT hr;
int len;
hr = CoCreateInstance(&CLSID_SAXAttributes40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXAttributes, (void**)&mxattr);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = IMXAttributes_clear(mxattr);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"),
_bstr_("qname"), _bstr_("type"), _bstr_("value"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
len = -1;
hr = ISAXAttributes_getLength(saxattr, &len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(len == 1, "got %d\n", len);
if (0) /* crashes */
{
hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len);
hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL);
}
len = 0;
hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(len == 5, "got %d\n", len);
ok(!lstrcmpW(ptr, L"qname"), "got %s\n", wine_dbgstr_w(ptr));
hr = IMXAttributes_clear(mxattr);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
len = -1;
hr = ISAXAttributes_getLength(saxattr, &len);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(len == 0, "got %d\n", len);
len = -1;
ptr = (void*)0xdeadbeef;
hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
ok(len == -1, "got %d\n", len);
ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr);
IMXAttributes_Release(mxattr);
ISAXAttributes_Release(saxattr);
free_bstrs();
}
static void test_mxattr_dispex(void)
{
IMXAttributes *mxattr;
IDispatchEx *dispex;
IUnknown *unk;
HRESULT hr;
hr = CoCreateInstance(&CLSID_SAXAttributes40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXAttributes, (void **)&mxattr);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk);
test_obj_dispex(unk);
IUnknown_Release(unk);
IDispatchEx_Release(dispex);
IMXAttributes_Release(mxattr);
}
static void test_mxattr_qi(void)
{
static const GUID *classes[] = { &CLSID_SAXAttributes40 };
IMXAttributes *mxattr;
HRESULT hr;
for (int i = 0; i < ARRAYSIZE(classes); ++i)
{
hr = CoCreateInstance(classes[i], NULL, CLSCTX_INPROC_SERVER, &IID_IMXAttributes, (void **)&mxattr);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
check_interface(mxattr, &IID_IMXAttributes, TRUE);
check_interface(mxattr, &IID_ISAXAttributes, TRUE);
check_interface(mxattr, &IID_IVBSAXAttributes, TRUE);
check_interface(mxattr, &IID_IDispatch, TRUE);
check_interface(mxattr, &IID_IDispatchEx, TRUE);
IMXAttributes_Release(mxattr);
}
}
static void test_mxattr_localname(void)
{
ISAXAttributes *saxattr;
IMXAttributes *mxattr;
HRESULT hr;
int index;
hr = CoCreateInstance(&CLSID_SAXAttributes40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXAttributes, (void **)&mxattr);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
/* add some ambiguous attribute names */
hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
_bstr_("a:localname"), _bstr_(""), _bstr_("value"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"),
_bstr_("b:localname"), _bstr_(""), _bstr_("value"));
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
index = -1;
hr = ISAXAttributes_getIndexFromName(saxattr, L"uri", 3, L"localname", 9, &index);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(index == 0, "Unexpected index %d\n", index);
index = -1;
hr = ISAXAttributes_getIndexFromName(saxattr, L"uri1", 4, L"localname", 9, &index);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
ok(index == -1, "Unexpected index %d\n", index);
index = -1;
hr = ISAXAttributes_getIndexFromName(saxattr, L"uri", 3, L"localname1", 10, &index);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
ok(index == -1, "Unexpected index %d\n", index);
hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getIndexFromName(saxattr, L"uri", 3, L"localname1", 10, NULL);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getIndexFromName(saxattr, L"uri", 3, NULL, 0, &index);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, L"localname1", 10, &index);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
ISAXAttributes_Release(saxattr);
IMXAttributes_Release(mxattr);
free_bstrs();
}
static void test_mxwriter_indent(void)
{
ISAXContentHandler *content;
IMXWriter *writer;
VARIANT dest;
HRESULT hr;
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_indent(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"a", -1, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_characters(content, L"", 0);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"b", -1, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"c", -1, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"c", -1);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"b", -1);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"a", -1);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = ISAXContentHandler_endDocument(content);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(L"<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n<a><b>\r\n\t\t<c/>\r\n\t</b>\r\n</a>", V_BSTR(&dest)),
"got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
free_bstrs();
}
static void test_saxreader_vb_content_handler(void)
{
IVBSAXXMLReader *reader;
struct sink *sink;
VARIANT var;
HRESULT hr;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_IVBSAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
sink = create_test_sink();
hr = IVBSAXXMLReader_putref_contentHandler(reader, &sink->IVBSAXContentHandler_iface);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = _bstr_("<a>text</a>");
hr = IVBSAXXMLReader_parse(reader, var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
IVBSAXContentHandler_Release(&sink->IVBSAXContentHandler_iface);
IVBSAXXMLReader_Release(reader);
free_bstrs();
}
static void test_mxwriter_from_reader(void)
{
IVBSAXContentHandler *content_handler;
IVBSAXXMLReader *reader;
IMXWriter *writer;
VARIANT var;
HRESULT hr;
hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, &IID_IVBSAXXMLReader, (void **)&reader);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = CoCreateInstance(&CLSID_MXXMLWriter40, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void **)&writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXContentHandler, (void **)&content_handler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IVBSAXXMLReader_putref_contentHandler(reader, content_handler);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = _bstr_("<a>text</a>");
hr = IVBSAXXMLReader_parse(reader, var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
VariantClear(&var);
V_VT(&var) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &var);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(V_VT(&var) == VT_BSTR, "Unexpected output type %d.\n", V_VT(&var));
ok(!lstrcmpW(L"<a>text</a>", V_BSTR(&var)), "Unexpected content %s.\n", wine_dbgstr_w(V_BSTR(&var)));
VariantClear(&var);
IMXWriter_Release(writer);
IVBSAXXMLReader_Release(reader);
IVBSAXContentHandler_Release(content_handler);
}
START_TEST(saxreader)
{
HRESULT hr;
hr = CoInitialize(NULL);
ok(hr == S_OK, "failed to init com\n");
init_call_sequences(sequences, NUM_CALL_SEQUENCES);
get_class_support_data();
if (is_clsid_supported(&CLSID_SAXXMLReader40))
{
test_saxreader();
test_saxreader_properties();
test_saxreader_max_xml_size();
test_saxreader_normalize_line_breaks();
test_saxreader_exhaustive_errors();
test_saxreader_features();
test_saxreader_encoding();
test_saxreader_dispex();
test_saxreader_vb_content_handler();
test_saxreader_cdata();
test_saxreader_pi();
test_saxreader_characters();
}
if (is_clsid_supported(&CLSID_MXXMLWriter40))
{
test_mxwriter_handlers();
test_mxwriter_startenddocument();
test_mxwriter_startendelement();
test_mxwriter_characters();
test_mxwriter_comment();
test_mxwriter_cdata();
test_mxwriter_pi();
test_mxwriter_ignorablespaces();
test_mxwriter_dtd();
test_mxwriter_properties();
test_mxwriter_flush();
test_mxwriter_stream();
test_mxwriter_encoding();
test_mxwriter_dispex();
test_mxwriter_indent();
test_mxwriter_from_reader();
}
if (is_clsid_supported(&CLSID_SAXAttributes40))
{
test_mxattr_qi();
test_mxattr_addAttribute();
test_mxattr_clear();
test_mxattr_localname();
test_mxattr_dispex();
}
CoUninitialize();
}