1 /* 2 * SAXReader/MXWriter tests 3 * 4 * Copyright 2008 Piotr Caban 5 * Copyright 2011 Thomas Mullaly 6 * Copyright 2012 Nikolay Sivov 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #define COBJMACROS 24 #define CONST_VTABLE 25 26 #include <stdio.h> 27 #include <assert.h> 28 29 #include "windows.h" 30 #include "ole2.h" 31 #include "msxml2.h" 32 #include "msxml2did.h" 33 #include "ocidl.h" 34 #include "dispex.h" 35 36 #include "wine/heap.h" 37 #include "wine/test.h" 38 39 static const WCHAR emptyW[] = {0}; 40 41 #define EXPECT_HR(hr,hr_exp) \ 42 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp) 43 44 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__) 45 static void _expect_ref(IUnknown* obj, ULONG ref, int line) 46 { 47 ULONG rc; 48 IUnknown_AddRef(obj); 49 rc = IUnknown_Release(obj); 50 ok_(__FILE__, line)(rc == ref, "expected refcount %d, got %d\n", ref, rc); 51 } 52 53 static LONG get_refcount(void *iface) 54 { 55 IUnknown *unk = iface; 56 LONG ref; 57 58 ref = IUnknown_AddRef(unk); 59 IUnknown_Release(unk); 60 return ref-1; 61 } 62 63 struct msxmlsupported_data_t 64 { 65 const GUID *clsid; 66 const char *name; 67 BOOL supported; 68 }; 69 70 static BOOL is_clsid_supported(const GUID *clsid, const struct msxmlsupported_data_t *table) 71 { 72 while (table->clsid) 73 { 74 if (table->clsid == clsid) return table->supported; 75 table++; 76 } 77 return FALSE; 78 } 79 80 static BSTR alloc_str_from_narrow(const char *str) 81 { 82 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); 83 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */ 84 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); 85 return ret; 86 } 87 88 static BSTR alloced_bstrs[512]; 89 static int alloced_bstrs_count; 90 91 static BSTR _bstr_(const char *str) 92 { 93 assert(alloced_bstrs_count < ARRAY_SIZE(alloced_bstrs)); 94 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str); 95 return alloced_bstrs[alloced_bstrs_count++]; 96 } 97 98 static void free_bstrs(void) 99 { 100 int i; 101 for (i = 0; i < alloced_bstrs_count; i++) 102 SysFreeString(alloced_bstrs[i]); 103 alloced_bstrs_count = 0; 104 } 105 106 static void test_saxstr(const char *file, unsigned line, BSTR str, const char *expected, BOOL todo, int *failcount) 107 { 108 int len, lenexp, cmp; 109 WCHAR buf[1024]; 110 111 len = SysStringLen(str); 112 113 if (!expected) { 114 if (str && todo) 115 { 116 (*failcount)++; 117 todo_wine 118 ok_(file, line) (!str, "got %p, expected null str\n", str); 119 } 120 else 121 ok_(file, line) (!str, "got %p, expected null str\n", str); 122 123 if (len && todo) 124 { 125 (*failcount)++; 126 todo_wine 127 ok_(file, line) (len == 0, "got len %d, expected 0\n", len); 128 } 129 else 130 ok_(file, line) (len == 0, "got len %d, expected 0\n", len); 131 return; 132 } 133 134 lenexp = strlen(expected); 135 if (lenexp != len && todo) 136 { 137 (*failcount)++; 138 todo_wine 139 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected); 140 } 141 else 142 ok_(file, line) (lenexp == len, "len %d (%s), expected %d (%s)\n", len, wine_dbgstr_wn(str, len), lenexp, expected); 143 144 /* exit earlier on length mismatch */ 145 if (lenexp != len) return; 146 147 MultiByteToWideChar(CP_ACP, 0, expected, -1, buf, ARRAY_SIZE(buf)); 148 149 cmp = memcmp(str, buf, lenexp*sizeof(WCHAR)); 150 if (cmp && todo) 151 { 152 (*failcount)++; 153 todo_wine 154 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n", 155 wine_dbgstr_wn(str, len), expected); 156 } 157 else 158 ok_(file, line) (!cmp, "unexpected str %s, expected %s\n", 159 wine_dbgstr_wn(str, len), expected); 160 } 161 162 typedef enum _CH { 163 CH_ENDTEST, 164 CH_PUTDOCUMENTLOCATOR, 165 CH_STARTDOCUMENT, 166 CH_ENDDOCUMENT, 167 CH_STARTPREFIXMAPPING, 168 CH_ENDPREFIXMAPPING, 169 CH_STARTELEMENT, 170 CH_ENDELEMENT, 171 CH_CHARACTERS, 172 CH_IGNORABLEWHITESPACE, 173 CH_PROCESSINGINSTRUCTION, 174 CH_SKIPPEDENTITY, 175 LH_STARTCDATA, 176 LH_ENDCDATA, 177 EH_ERROR, 178 EH_FATALERROR, 179 EH_IGNORABLEWARNING, 180 EVENT_LAST 181 } CH; 182 183 static const char *event_names[EVENT_LAST] = { 184 "endtest", 185 "putDocumentLocator", 186 "startDocument", 187 "endDocument", 188 "startPrefixMapping", 189 "endPrefixMapping", 190 "startElement", 191 "endElement", 192 "characters", 193 "ignorableWhitespace", 194 "processingInstruction", 195 "skippedEntity", 196 "startCDATA", 197 "endCDATA", 198 "error", 199 "fatalError", 200 "ignorableWarning" 201 }; 202 203 struct attribute_entry { 204 const char *uri; 205 const char *local; 206 const char *qname; 207 const char *value; 208 209 /* used for actual call data only, null for expected call data */ 210 BSTR uriW; 211 BSTR localW; 212 BSTR qnameW; 213 BSTR valueW; 214 }; 215 216 struct call_entry { 217 CH id; 218 int line; 219 int column; 220 HRESULT ret; 221 const char *arg1; 222 const char *arg2; 223 const char *arg3; 224 225 /* allocated once at startElement callback */ 226 struct attribute_entry *attributes; 227 int attr_count; 228 229 /* used for actual call data only, null for expected call data */ 230 BSTR arg1W; 231 BSTR arg2W; 232 BSTR arg3W; 233 }; 234 235 struct call_sequence 236 { 237 int count; 238 int size; 239 struct call_entry *sequence; 240 }; 241 242 #define CONTENT_HANDLER_INDEX 0 243 #define NUM_CALL_SEQUENCES 1 244 static struct call_sequence *sequences[NUM_CALL_SEQUENCES]; 245 246 static void init_call_entry(ISAXLocator *locator, struct call_entry *call) 247 { 248 memset(call, 0, sizeof(*call)); 249 ISAXLocator_getLineNumber(locator, &call->line); 250 ISAXLocator_getColumnNumber(locator, &call->column); 251 } 252 253 static void add_call(struct call_sequence **seq, int sequence_index, 254 const struct call_entry *call) 255 { 256 struct call_sequence *call_seq = seq[sequence_index]; 257 258 if (!call_seq->sequence) 259 { 260 call_seq->size = 10; 261 call_seq->sequence = heap_alloc(call_seq->size * sizeof (struct call_entry)); 262 } 263 264 if (call_seq->count == call_seq->size) 265 { 266 call_seq->size *= 2; 267 call_seq->sequence = heap_realloc(call_seq->sequence, call_seq->size * sizeof (struct call_entry)); 268 } 269 270 assert(call_seq->sequence); 271 272 call_seq->sequence[call_seq->count].id = call->id; 273 call_seq->sequence[call_seq->count].line = call->line; 274 call_seq->sequence[call_seq->count].column = call->column; 275 call_seq->sequence[call_seq->count].arg1W = call->arg1W; 276 call_seq->sequence[call_seq->count].arg2W = call->arg2W; 277 call_seq->sequence[call_seq->count].arg3W = call->arg3W; 278 call_seq->sequence[call_seq->count].ret = call->ret; 279 call_seq->sequence[call_seq->count].attr_count = call->attr_count; 280 call_seq->sequence[call_seq->count].attributes = call->attributes; 281 282 call_seq->count++; 283 } 284 285 static inline void flush_sequence(struct call_sequence **seg, int sequence_index) 286 { 287 int i; 288 289 struct call_sequence *call_seq = seg[sequence_index]; 290 291 for (i = 0; i < call_seq->count; i++) 292 { 293 int j; 294 295 for (j = 0; j < call_seq->sequence[i].attr_count; j++) 296 { 297 SysFreeString(call_seq->sequence[i].attributes[j].uriW); 298 SysFreeString(call_seq->sequence[i].attributes[j].localW); 299 SysFreeString(call_seq->sequence[i].attributes[j].qnameW); 300 SysFreeString(call_seq->sequence[i].attributes[j].valueW); 301 } 302 heap_free(call_seq->sequence[i].attributes); 303 call_seq->sequence[i].attr_count = 0; 304 305 SysFreeString(call_seq->sequence[i].arg1W); 306 SysFreeString(call_seq->sequence[i].arg2W); 307 SysFreeString(call_seq->sequence[i].arg3W); 308 } 309 310 heap_free(call_seq->sequence); 311 call_seq->sequence = NULL; 312 call_seq->count = call_seq->size = 0; 313 } 314 315 static const char *get_event_name(CH event) 316 { 317 return event_names[event]; 318 } 319 320 static void compare_attributes(const struct call_entry *actual, const struct call_entry *expected, const char *context, 321 BOOL todo, const char *file, int line, int *failcount) 322 { 323 int i, lenexp = 0; 324 325 /* attribute count is not stored for expected data */ 326 if (expected->attributes) 327 { 328 struct attribute_entry *ptr = expected->attributes; 329 while (ptr->uri) { lenexp++; ptr++; }; 330 } 331 332 /* check count first and exit earlier */ 333 if (actual->attr_count != lenexp && todo) 334 { 335 (*failcount)++; 336 todo_wine 337 ok_(file, line) (FALSE, "%s: in event %s expecting attr count %d got %d\n", 338 context, get_event_name(actual->id), lenexp, actual->attr_count); 339 } 340 else 341 ok_(file, line) (actual->attr_count == lenexp, "%s: in event %s expecting attr count %d got %d\n", 342 context, get_event_name(actual->id), lenexp, actual->attr_count); 343 344 if (actual->attr_count != lenexp) return; 345 346 /* now compare all attributes strings */ 347 for (i = 0; i < actual->attr_count; i++) 348 { 349 test_saxstr(file, line, actual->attributes[i].uriW, expected->attributes[i].uri, todo, failcount); 350 test_saxstr(file, line, actual->attributes[i].localW, expected->attributes[i].local, todo, failcount); 351 test_saxstr(file, line, actual->attributes[i].qnameW, expected->attributes[i].qname, todo, failcount); 352 test_saxstr(file, line, actual->attributes[i].valueW, expected->attributes[i].value, todo, failcount); 353 } 354 } 355 356 static void ok_sequence_(struct call_sequence **seq, int sequence_index, 357 const struct call_entry *expected, const char *context, BOOL todo, 358 const char *file, int line) 359 { 360 struct call_sequence *call_seq = seq[sequence_index]; 361 static const struct call_entry end_of_sequence = { CH_ENDTEST }; 362 const struct call_entry *actual, *sequence; 363 int failcount = 0; 364 365 add_call(seq, sequence_index, &end_of_sequence); 366 367 sequence = call_seq->sequence; 368 actual = sequence; 369 370 while (expected->id != CH_ENDTEST && actual->id != CH_ENDTEST) 371 { 372 if (expected->id == actual->id) 373 { 374 if (expected->line != -1) 375 { 376 /* always test position data */ 377 if (expected->line != actual->line && todo) 378 { 379 todo_wine 380 { 381 failcount++; 382 ok_(file, line) (FALSE, 383 "%s: in event %s expecting line %d got %d\n", 384 context, get_event_name(actual->id), expected->line, actual->line); 385 } 386 } 387 else 388 { 389 ok_(file, line) (expected->line == actual->line, 390 "%s: in event %s expecting line %d got %d\n", 391 context, get_event_name(actual->id), expected->line, actual->line); 392 } 393 } 394 395 396 if (expected->column != -1) 397 { 398 if (expected->column != actual->column && todo) 399 { 400 todo_wine 401 { 402 failcount++; 403 ok_(file, line) (FALSE, 404 "%s: in event %s expecting column %d got %d\n", 405 context, get_event_name(actual->id), expected->column, actual->column); 406 } 407 } 408 else 409 { 410 ok_(file, line) (expected->column == actual->column, 411 "%s: in event %s expecting column %d got %d\n", 412 context, get_event_name(actual->id), expected->column, actual->column); 413 } 414 } 415 416 switch (actual->id) 417 { 418 case CH_PUTDOCUMENTLOCATOR: 419 case CH_STARTDOCUMENT: 420 case CH_ENDDOCUMENT: 421 case LH_STARTCDATA: 422 case LH_ENDCDATA: 423 break; 424 case CH_STARTPREFIXMAPPING: 425 /* prefix, uri */ 426 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount); 427 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount); 428 break; 429 case CH_ENDPREFIXMAPPING: 430 /* prefix */ 431 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount); 432 break; 433 case CH_STARTELEMENT: 434 /* compare attributes */ 435 compare_attributes(actual, expected, context, todo, file, line, &failcount); 436 /* fallthrough */ 437 case CH_ENDELEMENT: 438 /* uri, localname, qname */ 439 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount); 440 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount); 441 test_saxstr(file, line, actual->arg3W, expected->arg3, todo, &failcount); 442 break; 443 case CH_CHARACTERS: 444 case CH_IGNORABLEWHITESPACE: 445 /* char data */ 446 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount); 447 break; 448 case CH_PROCESSINGINSTRUCTION: 449 /* target, data */ 450 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount); 451 test_saxstr(file, line, actual->arg2W, expected->arg2, todo, &failcount); 452 break; 453 case CH_SKIPPEDENTITY: 454 /* name */ 455 test_saxstr(file, line, actual->arg1W, expected->arg1, todo, &failcount); 456 break; 457 case EH_FATALERROR: 458 /* test return value only */ 459 if (expected->ret != actual->ret && todo) 460 { 461 failcount++; 462 ok_(file, line) (FALSE, 463 "%s: in event %s expecting ret 0x%08x got 0x%08x\n", 464 context, get_event_name(actual->id), expected->ret, actual->ret); 465 } 466 else 467 ok_(file, line) (expected->ret == actual->ret, 468 "%s: in event %s expecting ret 0x%08x got 0x%08x\n", 469 context, get_event_name(actual->id), expected->ret, actual->ret); 470 break; 471 case EH_ERROR: 472 case EH_IGNORABLEWARNING: 473 default: 474 ok(0, "%s: callback not handled, %s\n", context, get_event_name(actual->id)); 475 } 476 expected++; 477 actual++; 478 } 479 else if (todo) 480 { 481 failcount++; 482 todo_wine 483 { 484 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n", 485 context, get_event_name(expected->id), get_event_name(actual->id)); 486 } 487 488 flush_sequence(seq, sequence_index); 489 return; 490 } 491 else 492 { 493 ok_(file, line) (FALSE, "%s: call %s was expected, but got call %s instead\n", 494 context, get_event_name(expected->id), get_event_name(actual->id)); 495 expected++; 496 actual++; 497 } 498 } 499 500 if (todo) 501 { 502 todo_wine 503 { 504 if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST) 505 { 506 failcount++; 507 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n", 508 context, get_event_name(expected->id), get_event_name(actual->id)); 509 } 510 } 511 } 512 else if (expected->id != CH_ENDTEST || actual->id != CH_ENDTEST) 513 { 514 ok_(file, line) (FALSE, "%s: the call sequence is not complete: expected %s - actual %s\n", 515 context, get_event_name(expected->id), get_event_name(actual->id)); 516 } 517 518 if (todo && !failcount) /* succeeded yet marked todo */ 519 { 520 todo_wine 521 { 522 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context); 523 } 524 } 525 526 flush_sequence(seq, sequence_index); 527 } 528 529 #define ok_sequence(seq, index, exp, contx, todo) \ 530 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__) 531 532 static void init_call_sequences(struct call_sequence **seq, int n) 533 { 534 int i; 535 536 for (i = 0; i < n; i++) 537 seq[i] = heap_alloc_zero(sizeof(struct call_sequence)); 538 } 539 540 static const WCHAR szSimpleXML[] = { 541 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n', 542 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n', 543 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n', 544 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n', 545 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0' 546 }; 547 548 static const WCHAR carriage_ret_test[] = { 549 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n', 550 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n', 551 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n', 552 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n', 553 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0' 554 }; 555 556 static const WCHAR szUtf16XML[] = { 557 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ', 558 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ', 559 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n' 560 }; 561 562 static const CHAR szUtf16BOM[] = {0xff, 0xfe}; 563 564 static const CHAR szUtf8XML[] = 565 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n"; 566 567 static const char utf8xml2[] = 568 "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\r\n"; 569 570 static const char testXML[] = 571 "<?xml version=\"1.0\" ?>\n" 572 "<BankAccount>\n" 573 " <Number>1234</Number>\n" 574 " <Name>Captain Ahab</Name>\n" 575 "</BankAccount>\n"; 576 577 static const char test_attributes[] = 578 "<?xml version=\"1.0\" ?>\n" 579 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n" 580 "<node1 xmlns:p=\"test\" />" 581 "</document>\n"; 582 583 static const char test_cdata_xml[] = 584 "<?xml version=\"1.0\" ?>" 585 "<a><![CDATA[Some \r\ntext\n\r\ndata\n\n]]></a>"; 586 587 static const char test2_cdata_xml[] = 588 "<?xml version=\"1.0\" ?>" 589 "<a><![CDATA[\n\r\nSome \r\ntext\n\r\ndata\n\n]]></a>"; 590 591 static const char test3_cdata_xml[] = 592 "<?xml version=\"1.0\" ?><a><![CDATA[Some text data]]></a>"; 593 594 static struct call_entry content_handler_test1[] = { 595 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK }, 596 { CH_STARTDOCUMENT, 0, 0, S_OK }, 597 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" }, 598 { CH_CHARACTERS, 2, 14, S_OK, "\n " }, 599 { CH_STARTELEMENT, 3, 12, S_OK, "", "Number", "Number" }, 600 { CH_CHARACTERS, 3, 12, S_OK, "1234" }, 601 { CH_ENDELEMENT, 3, 18, S_OK, "", "Number", "Number" }, 602 { CH_CHARACTERS, 3, 25, S_OK, "\n " }, 603 { CH_STARTELEMENT, 4, 10, S_OK, "", "Name", "Name" }, 604 { CH_CHARACTERS, 4, 10, S_OK, "Captain Ahab" }, 605 { CH_ENDELEMENT, 4, 24, S_OK, "", "Name", "Name" }, 606 { CH_CHARACTERS, 4, 29, S_OK, "\n" }, 607 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" }, 608 { CH_ENDDOCUMENT, 0, 0, S_OK}, 609 { CH_ENDTEST } 610 }; 611 612 /* applies to versions 4 and 6 */ 613 static struct call_entry content_handler_test1_alternate[] = { 614 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 615 { CH_STARTDOCUMENT, 1, 22, S_OK }, 616 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" }, 617 { CH_CHARACTERS, 3, 4, S_OK, "\n " }, 618 { CH_STARTELEMENT, 3, 11, S_OK, "", "Number", "Number" }, 619 { CH_CHARACTERS, 3, 16, S_OK, "1234" }, 620 { CH_ENDELEMENT, 3, 24, S_OK, "", "Number", "Number" }, 621 { CH_CHARACTERS, 4, 4, S_OK, "\n " }, 622 { CH_STARTELEMENT, 4, 9, S_OK, "", "Name", "Name" }, 623 { CH_CHARACTERS, 4, 22, S_OK, "Captain Ahab" }, 624 { CH_ENDELEMENT, 4, 28, S_OK, "", "Name", "Name" }, 625 { CH_CHARACTERS, 5, 1, S_OK, "\n" }, 626 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" }, 627 { CH_ENDDOCUMENT, 6, 0, S_OK }, 628 { CH_ENDTEST } 629 }; 630 631 static struct call_entry content_handler_test2[] = { 632 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK }, 633 { CH_STARTDOCUMENT, 0, 0, S_OK }, 634 { CH_STARTELEMENT, 2, 14, S_OK, "", "BankAccount", "BankAccount" }, 635 { CH_CHARACTERS, 2, 14, S_OK, "\n" }, 636 { CH_CHARACTERS, 2, 16, S_OK, "\t" }, 637 { CH_STARTELEMENT, 3, 10, S_OK, "", "Number", "Number" }, 638 { CH_CHARACTERS, 3, 10, S_OK, "1234" }, 639 { CH_ENDELEMENT, 3, 16, S_OK, "", "Number", "Number" }, 640 { CH_CHARACTERS, 3, 23, S_OK, "\n" }, 641 { CH_CHARACTERS, 3, 25, S_OK, "\t" }, 642 { CH_STARTELEMENT, 4, 8, S_OK, "", "Name", "Name" }, 643 { CH_CHARACTERS, 4, 8, S_OK, "Captain Ahab" }, 644 { CH_ENDELEMENT, 4, 22, S_OK, "", "Name", "Name" }, 645 { CH_CHARACTERS, 4, 27, S_OK, "\n" }, 646 { CH_ENDELEMENT, 5, 3, S_OK, "", "BankAccount", "BankAccount" }, 647 { CH_ENDDOCUMENT, 0, 0, S_OK }, 648 { CH_ENDTEST } 649 }; 650 651 static struct call_entry content_handler_test2_alternate[] = { 652 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 653 { CH_STARTDOCUMENT, 1, 21, S_OK }, 654 { CH_STARTELEMENT, 2, 13, S_OK, "", "BankAccount", "BankAccount" }, 655 { CH_CHARACTERS, 3, 0, S_OK, "\n" }, 656 { CH_CHARACTERS, 3, 2, S_OK, "\t" }, 657 { CH_STARTELEMENT, 3, 9, S_OK, "", "Number", "Number" }, 658 { CH_CHARACTERS, 3, 14, S_OK, "1234" }, 659 { CH_ENDELEMENT, 3, 22, S_OK, "", "Number", "Number" }, 660 { CH_CHARACTERS, 4, 0, S_OK, "\n" }, 661 { CH_CHARACTERS, 4, 2, S_OK, "\t" }, 662 { CH_STARTELEMENT, 4, 7, S_OK, "", "Name", "Name" }, 663 { CH_CHARACTERS, 4, 20, S_OK, "Captain Ahab" }, 664 { CH_ENDELEMENT, 4, 26, S_OK, "", "Name", "Name" }, 665 { CH_CHARACTERS, 5, 0, S_OK, "\n" }, 666 { CH_ENDELEMENT, 5, 14, S_OK, "", "BankAccount", "BankAccount" }, 667 { CH_ENDDOCUMENT, 6, 0, S_OK }, 668 { CH_ENDTEST } 669 }; 670 671 static struct call_entry content_handler_testerror[] = { 672 { CH_PUTDOCUMENTLOCATOR, 0, 0, E_FAIL }, 673 { EH_FATALERROR, 0, 0, E_FAIL }, 674 { CH_ENDTEST } 675 }; 676 677 static struct call_entry content_handler_testerror_alternate[] = { 678 { CH_PUTDOCUMENTLOCATOR, 1, 0, E_FAIL }, 679 { EH_FATALERROR, 1, 0, E_FAIL }, 680 { CH_ENDTEST } 681 }; 682 683 static struct call_entry content_handler_test_callback_rets[] = { 684 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_FALSE }, 685 { CH_STARTDOCUMENT, 0, 0, S_FALSE }, 686 { EH_FATALERROR, 0, 0, S_FALSE }, 687 { CH_ENDTEST } 688 }; 689 690 static struct call_entry content_handler_test_callback_rets_alt[] = { 691 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_FALSE }, 692 { CH_STARTDOCUMENT, 1, 22, S_FALSE }, 693 { CH_STARTELEMENT, 2, 13, S_FALSE, "", "BankAccount", "BankAccount" }, 694 { CH_CHARACTERS, 3, 4, S_FALSE, "\n " }, 695 { CH_STARTELEMENT, 3, 11, S_FALSE, "", "Number", "Number" }, 696 { CH_CHARACTERS, 3, 16, S_FALSE, "1234" }, 697 { CH_ENDELEMENT, 3, 24, S_FALSE, "", "Number", "Number" }, 698 { CH_CHARACTERS, 4, 4, S_FALSE, "\n " }, 699 { CH_STARTELEMENT, 4, 9, S_FALSE, "", "Name", "Name" }, 700 { CH_CHARACTERS, 4, 22, S_FALSE, "Captain Ahab" }, 701 { CH_ENDELEMENT, 4, 28, S_FALSE, "", "Name", "Name" }, 702 { CH_CHARACTERS, 5, 1, S_FALSE, "\n" }, 703 { CH_ENDELEMENT, 5, 14, S_FALSE, "", "BankAccount", "BankAccount" }, 704 { CH_ENDDOCUMENT, 6, 0, S_FALSE }, 705 { CH_ENDTEST } 706 }; 707 708 static struct attribute_entry ch_attributes1[] = { 709 { "", "", "xmlns:test", "prefix_test" }, 710 { "", "", "xmlns", "prefix" }, 711 { "prefix_test", "arg1", "test:arg1", "arg1" }, 712 { "", "arg2", "arg2", "arg2" }, 713 { "prefix_test", "ar3", "test:ar3", "arg3" }, 714 { NULL } 715 }; 716 717 static struct attribute_entry ch_attributes2[] = { 718 { "", "", "xmlns:p", "test" }, 719 { NULL } 720 }; 721 722 static struct call_entry content_handler_test_attributes[] = { 723 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK }, 724 { CH_STARTDOCUMENT, 0, 0, S_OK }, 725 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" }, 726 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" }, 727 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes1 }, 728 { CH_CHARACTERS, 2, 96, S_OK, "\n" }, 729 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" }, 730 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", ch_attributes2 }, 731 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" }, 732 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" }, 733 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" }, 734 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" }, 735 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" }, 736 { CH_ENDDOCUMENT, 0, 0 }, 737 { CH_ENDTEST } 738 }; 739 740 static struct attribute_entry ch_attributes_alt_4[] = { 741 { "prefix_test", "arg1", "test:arg1", "arg1" }, 742 { "", "arg2", "arg2", "arg2" }, 743 { "prefix_test", "ar3", "test:ar3", "arg3" }, 744 { "", "", "xmlns:test", "prefix_test" }, 745 { "", "", "xmlns", "prefix" }, 746 { NULL } 747 }; 748 749 static struct call_entry content_handler_test_attributes_alternate_4[] = { 750 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 751 { CH_STARTDOCUMENT, 1, 22, S_OK }, 752 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" }, 753 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" }, 754 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_4 }, 755 { CH_CHARACTERS, 3, 1, S_OK, "\n" }, 756 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" }, 757 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2 }, 758 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" }, 759 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" }, 760 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" }, 761 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" }, 762 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" }, 763 { CH_ENDDOCUMENT, 4, 0, S_OK }, 764 { CH_ENDTEST } 765 }; 766 767 /* 'namespace' feature switched off */ 768 static struct attribute_entry ch_attributes_alt_no_ns[] = { 769 { "", "", "xmlns:test", "prefix_test" }, 770 { "", "", "xmlns", "prefix" }, 771 { "", "", "test:arg1", "arg1" }, 772 { "", "", "arg2", "arg2" }, 773 { "", "", "test:ar3", "arg3" }, 774 { NULL } 775 }; 776 777 static struct call_entry content_handler_test_attributes_alt_no_ns[] = { 778 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 779 { CH_STARTDOCUMENT, 1, 22, S_OK }, 780 { CH_STARTELEMENT, 2, 95, S_OK, "", "", "document", ch_attributes_alt_no_ns }, 781 { CH_CHARACTERS, 3, 1, S_OK, "\n" }, 782 { CH_STARTELEMENT, 3, 24, S_OK, "", "", "node1", ch_attributes2 }, 783 { CH_ENDELEMENT, 3, 24, S_OK, "", "", "node1" }, 784 { CH_ENDELEMENT, 3, 35, S_OK, "", "", "document" }, 785 { CH_ENDDOCUMENT, 4, 0, S_OK }, 786 { CH_ENDTEST } 787 }; 788 789 static struct attribute_entry ch_attributes_alt_6[] = { 790 { "prefix_test", "arg1", "test:arg1", "arg1" }, 791 { "", "arg2", "arg2", "arg2" }, 792 { "prefix_test", "ar3", "test:ar3", "arg3" }, 793 { "http://www.w3.org/2000/xmlns/", "", "xmlns:test", "prefix_test" }, 794 { "http://www.w3.org/2000/xmlns/", "", "xmlns", "prefix" }, 795 { NULL } 796 }; 797 798 static struct attribute_entry ch_attributes2_6[] = { 799 { "http://www.w3.org/2000/xmlns/", "", "xmlns:p", "test" }, 800 { NULL } 801 }; 802 803 static struct call_entry content_handler_test_attributes_alternate_6[] = { 804 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 805 { CH_STARTDOCUMENT, 1, 22, S_OK }, 806 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" }, 807 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" }, 808 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_alt_6 }, 809 { CH_CHARACTERS, 3, 1, S_OK, "\n" }, 810 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" }, 811 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", ch_attributes2_6 }, 812 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" }, 813 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" }, 814 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" }, 815 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" }, 816 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" }, 817 { CH_ENDDOCUMENT, 4, 0, S_OK }, 818 { CH_ENDTEST } 819 }; 820 821 /* 'namespaces' is on, 'namespace-prefixes' if off */ 822 static struct attribute_entry ch_attributes_no_prefix[] = { 823 { "prefix_test", "arg1", "test:arg1", "arg1" }, 824 { "", "arg2", "arg2", "arg2" }, 825 { "prefix_test", "ar3", "test:ar3", "arg3" }, 826 { NULL } 827 }; 828 829 static struct call_entry content_handler_test_attributes_alt_no_prefix[] = { 830 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 831 { CH_STARTDOCUMENT, 1, 22, S_OK }, 832 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "test", "prefix_test" }, 833 { CH_STARTPREFIXMAPPING, 2, 95, S_OK, "", "prefix" }, 834 { CH_STARTELEMENT, 2, 95, S_OK, "prefix", "document", "document", ch_attributes_no_prefix }, 835 { CH_CHARACTERS, 3, 1, S_OK, "\n" }, 836 { CH_STARTPREFIXMAPPING, 3, 24, S_OK, "p", "test" }, 837 { CH_STARTELEMENT, 3, 24, S_OK, "prefix", "node1", "node1", NULL }, 838 { CH_ENDELEMENT, 3, 24, S_OK, "prefix", "node1", "node1" }, 839 { CH_ENDPREFIXMAPPING, 3, 24, S_OK, "p" }, 840 { CH_ENDELEMENT, 3, 35, S_OK, "prefix", "document", "document" }, 841 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "test" }, 842 { CH_ENDPREFIXMAPPING, 3, 35, S_OK, "" }, 843 { CH_ENDDOCUMENT, 4, 0, S_OK }, 844 { CH_ENDTEST } 845 }; 846 847 static struct call_entry content_handler_test_attributes_no_prefix[] = { 848 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK }, 849 { CH_STARTDOCUMENT, 0, 0, S_OK }, 850 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "test", "prefix_test" }, 851 { CH_STARTPREFIXMAPPING, 2, 96, S_OK, "", "prefix" }, 852 { CH_STARTELEMENT, 2, 96, S_OK, "prefix", "document", "document", ch_attributes_no_prefix }, 853 { CH_CHARACTERS, 2, 96, S_OK, "\n" }, 854 { CH_STARTPREFIXMAPPING, 3, 25, S_OK, "p", "test" }, 855 { CH_STARTELEMENT, 3, 25, S_OK, "prefix", "node1", "node1", NULL }, 856 { CH_ENDELEMENT, 3, 25, S_OK, "prefix", "node1", "node1" }, 857 { CH_ENDPREFIXMAPPING, 3, 25, S_OK, "p" }, 858 { CH_ENDELEMENT, 3, 27, S_OK, "prefix", "document", "document" }, 859 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "" }, 860 { CH_ENDPREFIXMAPPING, 3, 27, S_OK, "test" }, 861 { CH_ENDDOCUMENT, 0, 0 }, 862 { CH_ENDTEST } 863 }; 864 865 static struct attribute_entry xmlspace_attrs[] = { 866 { "http://www.w3.org/XML/1998/namespace", "space", "xml:space", "preserve" }, 867 { NULL } 868 }; 869 870 static struct call_entry xmlspaceattr_test[] = { 871 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK }, 872 { CH_STARTDOCUMENT, 0, 0, S_OK }, 873 { CH_STARTELEMENT, 1, 64, S_OK, "", "a", "a", xmlspace_attrs }, 874 { CH_CHARACTERS, 1, 64, S_OK, " Some text data " }, 875 { CH_ENDELEMENT, 1, 82, S_OK, "", "a", "a" }, 876 { CH_ENDDOCUMENT, 0, 0, S_OK }, 877 { CH_ENDTEST } 878 }; 879 880 static struct call_entry xmlspaceattr_test_alternate[] = { 881 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 882 { CH_STARTDOCUMENT, 1, 39, S_OK }, 883 { CH_STARTELEMENT, 1, 63, S_OK, "", "a", "a", xmlspace_attrs }, 884 { CH_CHARACTERS, 1, 80, S_OK, " Some text data " }, 885 { CH_ENDELEMENT, 1, 83, S_OK, "", "a", "a" }, 886 { CH_ENDDOCUMENT, 1, 83, S_OK }, 887 { CH_ENDTEST } 888 }; 889 890 /* attribute value normalization test */ 891 static const char attribute_normalize[] = 892 "<?xml version=\"1.0\" ?>\n" 893 "<a attr1=\" \r \n \tattr_value A & &\t \r \n\r\n \n\"/>\n"; 894 895 static struct attribute_entry attribute_norm_attrs[] = { 896 { "", "attr1", "attr1", " attr_value A & & " }, 897 { NULL } 898 }; 899 900 static struct call_entry attribute_norm[] = { 901 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK }, 902 { CH_STARTDOCUMENT, 0, 0, S_OK }, 903 { CH_STARTELEMENT, 6, 4, S_OK, "", "a", "a", attribute_norm_attrs }, 904 { CH_ENDELEMENT, 6, 4, S_OK, "", "a", "a" }, 905 { CH_ENDDOCUMENT, 0, 0, S_OK }, 906 { CH_ENDTEST } 907 }; 908 909 static struct call_entry attribute_norm_alt[] = { 910 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 911 { CH_STARTDOCUMENT, 1, 22, S_OK }, 912 { CH_STARTELEMENT, 8, 3, S_OK, "", "a", "a", attribute_norm_attrs }, 913 { CH_ENDELEMENT, 8, 3, S_OK, "", "a", "a" }, 914 { CH_ENDDOCUMENT, 9, 0, S_OK }, 915 { CH_ENDTEST } 916 }; 917 918 static struct call_entry cdata_test[] = { 919 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK }, 920 { CH_STARTDOCUMENT, 0, 0, S_OK }, 921 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" }, 922 { LH_STARTCDATA, 1, 35, S_OK }, 923 { CH_CHARACTERS, 1, 35, S_OK, "Some \n" }, 924 { CH_CHARACTERS, 1, 42, S_OK, "text\n\n" }, 925 { CH_CHARACTERS, 1, 49, S_OK, "data\n\n" }, 926 { LH_ENDCDATA, 1, 49, S_OK }, 927 { CH_ENDELEMENT, 6, 6, S_OK, "", "a", "a" }, 928 { CH_ENDDOCUMENT, 0, 0, S_OK }, 929 { CH_ENDTEST } 930 }; 931 932 static struct call_entry cdata_test2[] = { 933 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK }, 934 { CH_STARTDOCUMENT, 0, 0, S_OK }, 935 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" }, 936 { LH_STARTCDATA, 1, 35, S_OK }, 937 { CH_CHARACTERS, 1, 35, S_OK, "\n\n" }, 938 { CH_CHARACTERS, 1, 38, S_OK, "Some \n" }, 939 { CH_CHARACTERS, 1, 45, S_OK, "text\n\n" }, 940 { CH_CHARACTERS, 1, 52, S_OK, "data\n\n" }, 941 { LH_ENDCDATA, 1, 52, S_OK }, 942 { CH_ENDELEMENT, 8, 6, S_OK, "", "a", "a" }, 943 { CH_ENDDOCUMENT, 0, 0, S_OK }, 944 { CH_ENDTEST } 945 }; 946 947 static struct call_entry cdata_test3[] = { 948 { CH_PUTDOCUMENTLOCATOR, 0, 0, S_OK }, 949 { CH_STARTDOCUMENT, 0, 0, S_OK }, 950 { CH_STARTELEMENT, 1, 26, S_OK, "", "a", "a" }, 951 { LH_STARTCDATA, 1, 35, S_OK }, 952 { CH_CHARACTERS, 1, 35, S_OK, "Some text data" }, 953 { LH_ENDCDATA, 1, 35, S_OK }, 954 { CH_ENDELEMENT, 1, 54, S_OK, "", "a", "a" }, 955 { CH_ENDDOCUMENT, 0, 0, S_OK }, 956 { CH_ENDTEST } 957 }; 958 959 /* this is what MSXML6 does */ 960 static struct call_entry cdata_test_alt[] = { 961 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 962 { CH_STARTDOCUMENT, 1, 22, S_OK }, 963 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" }, 964 { LH_STARTCDATA, 1, 34, S_OK }, 965 { CH_CHARACTERS, 1, 40, S_OK, "Some " }, 966 { CH_CHARACTERS, 2, 0, S_OK, "\n" }, 967 { CH_CHARACTERS, 3, 1, S_OK, "text\n" }, 968 { CH_CHARACTERS, 4, 0, S_OK, "\n" }, 969 { CH_CHARACTERS, 6, 3, S_OK, "data\n\n" }, 970 { LH_ENDCDATA, 6, 3, S_OK }, 971 { CH_ENDELEMENT, 6, 7, S_OK, "", "a", "a" }, 972 { CH_ENDDOCUMENT, 6, 7, S_OK }, 973 { CH_ENDTEST } 974 }; 975 976 static struct call_entry cdata_test2_alt[] = { 977 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 978 { CH_STARTDOCUMENT, 1, 22, S_OK }, 979 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" }, 980 { LH_STARTCDATA, 1, 34, S_OK }, 981 { CH_CHARACTERS, 2, 1, S_OK, "\n" }, 982 { CH_CHARACTERS, 3, 0, S_OK, "\n" }, 983 { CH_CHARACTERS, 3, 6, S_OK, "Some " }, 984 { CH_CHARACTERS, 4, 0, S_OK, "\n" }, 985 { CH_CHARACTERS, 5, 1, S_OK, "text\n" }, 986 { CH_CHARACTERS, 6, 0, S_OK, "\n" }, 987 { CH_CHARACTERS, 8, 3, S_OK, "data\n\n" }, 988 { LH_ENDCDATA, 8, 3, S_OK }, 989 { CH_ENDELEMENT, 8, 7, S_OK, "", "a", "a" }, 990 { CH_ENDDOCUMENT, 8, 7, S_OK }, 991 { CH_ENDTEST } 992 }; 993 994 static struct call_entry cdata_test3_alt[] = { 995 { CH_PUTDOCUMENTLOCATOR, 1, 0, S_OK }, 996 { CH_STARTDOCUMENT, 1, 22, S_OK }, 997 { CH_STARTELEMENT, 1, 25, S_OK, "", "a", "a" }, 998 { LH_STARTCDATA, 1, 34, S_OK }, 999 { CH_CHARACTERS, 1, 51, S_OK, "Some text data" }, 1000 { LH_ENDCDATA, 1, 51, S_OK }, 1001 { CH_ENDELEMENT, 1, 55, S_OK, "", "a", "a" }, 1002 { CH_ENDDOCUMENT, 1, 55, S_OK }, 1003 { CH_ENDTEST } 1004 }; 1005 1006 static struct attribute_entry read_test_attrs[] = { 1007 { "", "attr", "attr", "val" }, 1008 { NULL } 1009 }; 1010 1011 static struct call_entry read_test_seq[] = { 1012 { CH_PUTDOCUMENTLOCATOR, -1, 0, S_OK }, 1013 { CH_STARTDOCUMENT, -1, -1, S_OK }, 1014 { CH_STARTELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" }, 1015 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs }, 1016 { CH_CHARACTERS, -1, -1, S_OK, "text" }, 1017 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" }, 1018 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs }, 1019 { CH_CHARACTERS, -1, -1, S_OK, "text" }, 1020 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" }, 1021 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs }, 1022 { CH_CHARACTERS, -1, -1, S_OK, "text" }, 1023 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" }, 1024 { CH_STARTELEMENT, -1, -1, S_OK, "", "elem", "elem", read_test_attrs }, 1025 { CH_CHARACTERS, -1, -1, S_OK, "text" }, 1026 { CH_ENDELEMENT, -1, -1, S_OK, "", "elem", "elem" }, 1027 { CH_ENDELEMENT, -1, -1, S_OK, "", "rootelem", "rootelem" }, 1028 { CH_ENDDOCUMENT, -1, -1, S_OK}, 1029 { CH_ENDTEST } 1030 }; 1031 1032 static const char xmlspace_attr[] = 1033 "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" 1034 "<a xml:space=\"preserve\"> Some text data </a>"; 1035 1036 static struct call_entry *expectCall; 1037 static ISAXLocator *locator; 1038 static ISAXXMLReader *g_reader; 1039 int msxml_version; 1040 1041 static void set_expected_seq(struct call_entry *expected) 1042 { 1043 expectCall = expected; 1044 } 1045 1046 /* to be called once on each tested callback return */ 1047 static HRESULT get_expected_ret(void) 1048 { 1049 HRESULT hr = expectCall->ret; 1050 if (expectCall->id != CH_ENDTEST) expectCall++; 1051 return hr; 1052 } 1053 1054 static HRESULT WINAPI contentHandler_QueryInterface( 1055 ISAXContentHandler* iface, 1056 REFIID riid, 1057 void **ppvObject) 1058 { 1059 *ppvObject = NULL; 1060 1061 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler)) 1062 { 1063 *ppvObject = iface; 1064 } 1065 else 1066 { 1067 return E_NOINTERFACE; 1068 } 1069 1070 return S_OK; 1071 } 1072 1073 static ULONG WINAPI contentHandler_AddRef( 1074 ISAXContentHandler* iface) 1075 { 1076 return 2; 1077 } 1078 1079 static ULONG WINAPI contentHandler_Release( 1080 ISAXContentHandler* iface) 1081 { 1082 return 1; 1083 } 1084 1085 static HRESULT WINAPI contentHandler_putDocumentLocator( 1086 ISAXContentHandler* iface, 1087 ISAXLocator *pLocator) 1088 { 1089 struct call_entry call; 1090 IUnknown *unk; 1091 HRESULT hr; 1092 1093 locator = pLocator; 1094 1095 init_call_entry(locator, &call); 1096 call.id = CH_PUTDOCUMENTLOCATOR; 1097 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1098 1099 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXLocator, (void**)&unk); 1100 EXPECT_HR(hr, E_NOINTERFACE); 1101 1102 if (msxml_version >= 6) { 1103 ISAXAttributes *attr, *attr1; 1104 IMXAttributes *mxattr; 1105 1106 EXPECT_REF(pLocator, 1); 1107 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr); 1108 EXPECT_HR(hr, S_OK); 1109 EXPECT_REF(pLocator, 2); 1110 hr = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr1); 1111 EXPECT_HR(hr, S_OK); 1112 EXPECT_REF(pLocator, 3); 1113 ok(attr == attr1, "got %p, %p\n", attr, attr1); 1114 1115 hr = ISAXAttributes_QueryInterface(attr, &IID_IVBSAXAttributes, (void**)&unk); 1116 EXPECT_HR(hr, E_NOINTERFACE); 1117 1118 hr = ISAXLocator_QueryInterface(pLocator, &IID_IVBSAXAttributes, (void**)&unk); 1119 EXPECT_HR(hr, E_NOINTERFACE); 1120 1121 hr = ISAXAttributes_QueryInterface(attr, &IID_IMXAttributes, (void**)&mxattr); 1122 EXPECT_HR(hr, E_NOINTERFACE); 1123 1124 ISAXAttributes_Release(attr); 1125 ISAXAttributes_Release(attr1); 1126 } 1127 1128 return get_expected_ret(); 1129 } 1130 1131 static ISAXAttributes *test_attr_ptr; 1132 static HRESULT WINAPI contentHandler_startDocument( 1133 ISAXContentHandler* iface) 1134 { 1135 struct call_entry call; 1136 1137 init_call_entry(locator, &call); 1138 call.id = CH_STARTDOCUMENT; 1139 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1140 1141 test_attr_ptr = NULL; 1142 1143 return get_expected_ret(); 1144 } 1145 1146 static HRESULT WINAPI contentHandler_endDocument( 1147 ISAXContentHandler* iface) 1148 { 1149 struct call_entry call; 1150 1151 init_call_entry(locator, &call); 1152 call.id = CH_ENDDOCUMENT; 1153 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1154 1155 return get_expected_ret(); 1156 } 1157 1158 static HRESULT WINAPI contentHandler_startPrefixMapping( 1159 ISAXContentHandler* iface, 1160 const WCHAR *prefix, int prefix_len, 1161 const WCHAR *uri, int uri_len) 1162 { 1163 struct call_entry call; 1164 1165 init_call_entry(locator, &call); 1166 call.id = CH_STARTPREFIXMAPPING; 1167 call.arg1W = SysAllocStringLen(prefix, prefix_len); 1168 call.arg2W = SysAllocStringLen(uri, uri_len); 1169 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1170 1171 return get_expected_ret(); 1172 } 1173 1174 static HRESULT WINAPI contentHandler_endPrefixMapping( 1175 ISAXContentHandler* iface, 1176 const WCHAR *prefix, int len) 1177 { 1178 struct call_entry call; 1179 1180 init_call_entry(locator, &call); 1181 call.id = CH_ENDPREFIXMAPPING; 1182 call.arg1W = SysAllocStringLen(prefix, len); 1183 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1184 1185 return get_expected_ret(); 1186 } 1187 1188 static HRESULT WINAPI contentHandler_startElement( 1189 ISAXContentHandler* iface, 1190 const WCHAR *uri, int uri_len, 1191 const WCHAR *localname, int local_len, 1192 const WCHAR *qname, int qname_len, 1193 ISAXAttributes *saxattr) 1194 { 1195 struct call_entry call; 1196 IMXAttributes *mxattr; 1197 HRESULT hr; 1198 int len; 1199 1200 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr); 1201 EXPECT_HR(hr, E_NOINTERFACE); 1202 1203 init_call_entry(locator, &call); 1204 call.id = CH_STARTELEMENT; 1205 call.arg1W = SysAllocStringLen(uri, uri_len); 1206 call.arg2W = SysAllocStringLen(localname, local_len); 1207 call.arg3W = SysAllocStringLen(qname, qname_len); 1208 1209 if(!test_attr_ptr) 1210 test_attr_ptr = saxattr; 1211 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr); 1212 1213 /* store actual attributes */ 1214 len = 0; 1215 hr = ISAXAttributes_getLength(saxattr, &len); 1216 EXPECT_HR(hr, S_OK); 1217 1218 if (len) 1219 { 1220 VARIANT_BOOL v; 1221 int i; 1222 1223 struct attribute_entry *attr; 1224 attr = heap_alloc_zero(len * sizeof(*attr)); 1225 1226 v = VARIANT_TRUE; 1227 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v); 1228 EXPECT_HR(hr, S_OK); 1229 1230 for (i = 0; i < len; i++) 1231 { 1232 const WCHAR *value; 1233 int value_len; 1234 1235 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len, 1236 &localname, &local_len, &qname, &qname_len); 1237 EXPECT_HR(hr, S_OK); 1238 1239 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len); 1240 EXPECT_HR(hr, S_OK); 1241 1242 /* if 'namespaces' switched off uri and local name contains garbage */ 1243 if (v == VARIANT_FALSE && msxml_version > 0) 1244 { 1245 attr[i].uriW = SysAllocStringLen(NULL, 0); 1246 attr[i].localW = SysAllocStringLen(NULL, 0); 1247 } 1248 else 1249 { 1250 attr[i].uriW = SysAllocStringLen(uri, uri_len); 1251 attr[i].localW = SysAllocStringLen(localname, local_len); 1252 } 1253 1254 attr[i].qnameW = SysAllocStringLen(qname, qname_len); 1255 attr[i].valueW = SysAllocStringLen(value, value_len); 1256 } 1257 1258 call.attributes = attr; 1259 call.attr_count = len; 1260 } 1261 1262 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1263 1264 return get_expected_ret(); 1265 } 1266 1267 static HRESULT WINAPI contentHandler_endElement( 1268 ISAXContentHandler* iface, 1269 const WCHAR *uri, int uri_len, 1270 const WCHAR *localname, int local_len, 1271 const WCHAR *qname, int qname_len) 1272 { 1273 struct call_entry call; 1274 1275 init_call_entry(locator, &call); 1276 call.id = CH_ENDELEMENT; 1277 call.arg1W = SysAllocStringLen(uri, uri_len); 1278 call.arg2W = SysAllocStringLen(localname, local_len); 1279 call.arg3W = SysAllocStringLen(qname, qname_len); 1280 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1281 1282 return get_expected_ret(); 1283 } 1284 1285 static HRESULT WINAPI contentHandler_characters( 1286 ISAXContentHandler* iface, 1287 const WCHAR *chars, 1288 int len) 1289 { 1290 struct call_entry call; 1291 1292 init_call_entry(locator, &call); 1293 call.id = CH_CHARACTERS; 1294 call.arg1W = SysAllocStringLen(chars, len); 1295 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1296 1297 return get_expected_ret(); 1298 } 1299 1300 static HRESULT WINAPI contentHandler_ignorableWhitespace( 1301 ISAXContentHandler* iface, 1302 const WCHAR *chars, int len) 1303 { 1304 struct call_entry call; 1305 1306 init_call_entry(locator, &call); 1307 call.id = CH_IGNORABLEWHITESPACE; 1308 call.arg1W = SysAllocStringLen(chars, len); 1309 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1310 1311 return get_expected_ret(); 1312 } 1313 1314 static HRESULT WINAPI contentHandler_processingInstruction( 1315 ISAXContentHandler* iface, 1316 const WCHAR *target, int target_len, 1317 const WCHAR *data, int data_len) 1318 { 1319 struct call_entry call; 1320 1321 init_call_entry(locator, &call); 1322 call.id = CH_PROCESSINGINSTRUCTION; 1323 call.arg1W = SysAllocStringLen(target, target_len); 1324 call.arg2W = SysAllocStringLen(data, data_len); 1325 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1326 1327 return get_expected_ret(); 1328 } 1329 1330 static HRESULT WINAPI contentHandler_skippedEntity( 1331 ISAXContentHandler* iface, 1332 const WCHAR *name, int len) 1333 { 1334 struct call_entry call; 1335 1336 init_call_entry(locator, &call); 1337 call.id = CH_SKIPPEDENTITY; 1338 call.arg1W = SysAllocStringLen(name, len); 1339 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1340 1341 return get_expected_ret(); 1342 } 1343 1344 static const ISAXContentHandlerVtbl contentHandlerVtbl = 1345 { 1346 contentHandler_QueryInterface, 1347 contentHandler_AddRef, 1348 contentHandler_Release, 1349 contentHandler_putDocumentLocator, 1350 contentHandler_startDocument, 1351 contentHandler_endDocument, 1352 contentHandler_startPrefixMapping, 1353 contentHandler_endPrefixMapping, 1354 contentHandler_startElement, 1355 contentHandler_endElement, 1356 contentHandler_characters, 1357 contentHandler_ignorableWhitespace, 1358 contentHandler_processingInstruction, 1359 contentHandler_skippedEntity 1360 }; 1361 1362 static ISAXContentHandler contentHandler = { &contentHandlerVtbl }; 1363 1364 static HRESULT WINAPI isaxerrorHandler_QueryInterface( 1365 ISAXErrorHandler* iface, 1366 REFIID riid, 1367 void **ppvObject) 1368 { 1369 *ppvObject = NULL; 1370 1371 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler)) 1372 { 1373 *ppvObject = iface; 1374 } 1375 else 1376 { 1377 return E_NOINTERFACE; 1378 } 1379 1380 return S_OK; 1381 } 1382 1383 static ULONG WINAPI isaxerrorHandler_AddRef( 1384 ISAXErrorHandler* iface) 1385 { 1386 return 2; 1387 } 1388 1389 static ULONG WINAPI isaxerrorHandler_Release( 1390 ISAXErrorHandler* iface) 1391 { 1392 return 1; 1393 } 1394 1395 static HRESULT WINAPI isaxerrorHandler_error( 1396 ISAXErrorHandler* iface, 1397 ISAXLocator *pLocator, 1398 const WCHAR *pErrorMessage, 1399 HRESULT hrErrorCode) 1400 { 1401 ok(0, "unexpected call\n"); 1402 return S_OK; 1403 } 1404 1405 static HRESULT WINAPI isaxerrorHandler_fatalError( 1406 ISAXErrorHandler* iface, 1407 ISAXLocator *pLocator, 1408 const WCHAR *message, 1409 HRESULT hr) 1410 { 1411 struct call_entry call; 1412 1413 init_call_entry(locator, &call); 1414 call.id = EH_FATALERROR; 1415 call.ret = hr; 1416 1417 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1418 1419 get_expected_ret(); 1420 return S_OK; 1421 } 1422 1423 static HRESULT WINAPI isaxerrorHandler_ignorableWarning( 1424 ISAXErrorHandler* iface, 1425 ISAXLocator *pLocator, 1426 const WCHAR *pErrorMessage, 1427 HRESULT hrErrorCode) 1428 { 1429 ok(0, "unexpected call\n"); 1430 return S_OK; 1431 } 1432 1433 static const ISAXErrorHandlerVtbl errorHandlerVtbl = 1434 { 1435 isaxerrorHandler_QueryInterface, 1436 isaxerrorHandler_AddRef, 1437 isaxerrorHandler_Release, 1438 isaxerrorHandler_error, 1439 isaxerrorHandler_fatalError, 1440 isaxerrorHandler_ignorableWarning 1441 }; 1442 1443 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl }; 1444 1445 static HRESULT WINAPI isaxattributes_QueryInterface( 1446 ISAXAttributes* iface, 1447 REFIID riid, 1448 void **ppvObject) 1449 { 1450 *ppvObject = NULL; 1451 1452 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes)) 1453 { 1454 *ppvObject = iface; 1455 } 1456 else 1457 { 1458 return E_NOINTERFACE; 1459 } 1460 1461 return S_OK; 1462 } 1463 1464 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface) 1465 { 1466 return 2; 1467 } 1468 1469 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface) 1470 { 1471 return 1; 1472 } 1473 1474 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length) 1475 { 1476 *length = 3; 1477 return S_OK; 1478 } 1479 1480 static HRESULT WINAPI isaxattributes_getURI( 1481 ISAXAttributes* iface, 1482 int nIndex, 1483 const WCHAR **pUrl, 1484 int *pUriSize) 1485 { 1486 ok(0, "unexpected call\n"); 1487 return E_NOTIMPL; 1488 } 1489 1490 static HRESULT WINAPI isaxattributes_getLocalName( 1491 ISAXAttributes* iface, 1492 int nIndex, 1493 const WCHAR **pLocalName, 1494 int *pLocalNameLength) 1495 { 1496 ok(0, "unexpected call\n"); 1497 return E_NOTIMPL; 1498 } 1499 1500 static HRESULT WINAPI isaxattributes_getQName( 1501 ISAXAttributes* iface, 1502 int index, 1503 const WCHAR **QName, 1504 int *QNameLength) 1505 { 1506 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0}, 1507 {'a','t','t','r','2','j','u','n','k',0}, 1508 {'a','t','t','r','3',0}}; 1509 static const int attrqnamelen[] = {7, 5, 5}; 1510 1511 ok(index >= 0 && index <= 2, "invalid index received %d\n", index); 1512 1513 if (index >= 0 && index <= 2) { 1514 *QName = attrqnamesW[index]; 1515 *QNameLength = attrqnamelen[index]; 1516 } else { 1517 *QName = NULL; 1518 *QNameLength = 0; 1519 } 1520 1521 return S_OK; 1522 } 1523 1524 static HRESULT WINAPI isaxattributes_getName( 1525 ISAXAttributes* iface, 1526 int nIndex, 1527 const WCHAR **pUri, 1528 int * pUriLength, 1529 const WCHAR ** pLocalName, 1530 int * pLocalNameSize, 1531 const WCHAR ** pQName, 1532 int * pQNameLength) 1533 { 1534 ok(0, "unexpected call\n"); 1535 return E_NOTIMPL; 1536 } 1537 1538 static HRESULT WINAPI isaxattributes_getIndexFromName( 1539 ISAXAttributes* iface, 1540 const WCHAR * pUri, 1541 int cUriLength, 1542 const WCHAR * pLocalName, 1543 int cocalNameLength, 1544 int * index) 1545 { 1546 ok(0, "unexpected call\n"); 1547 return E_NOTIMPL; 1548 } 1549 1550 static HRESULT WINAPI isaxattributes_getIndexFromQName( 1551 ISAXAttributes* iface, 1552 const WCHAR * pQName, 1553 int nQNameLength, 1554 int * index) 1555 { 1556 ok(0, "unexpected call\n"); 1557 return E_NOTIMPL; 1558 } 1559 1560 static HRESULT WINAPI isaxattributes_getType( 1561 ISAXAttributes* iface, 1562 int nIndex, 1563 const WCHAR ** pType, 1564 int * pTypeLength) 1565 { 1566 ok(0, "unexpected call\n"); 1567 return E_NOTIMPL; 1568 } 1569 1570 static HRESULT WINAPI isaxattributes_getTypeFromName( 1571 ISAXAttributes* iface, 1572 const WCHAR * pUri, 1573 int nUri, 1574 const WCHAR * pLocalName, 1575 int nLocalName, 1576 const WCHAR ** pType, 1577 int * nType) 1578 { 1579 ok(0, "unexpected call\n"); 1580 return E_NOTIMPL; 1581 } 1582 1583 static HRESULT WINAPI isaxattributes_getTypeFromQName( 1584 ISAXAttributes* iface, 1585 const WCHAR * pQName, 1586 int nQName, 1587 const WCHAR ** pType, 1588 int * nType) 1589 { 1590 ok(0, "unexpected call\n"); 1591 return E_NOTIMPL; 1592 } 1593 1594 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index, 1595 const WCHAR **value, int *nValue) 1596 { 1597 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0}, 1598 {'a','2','j','u','n','k',0}, 1599 {'<','&','"','>','\'',0}}; 1600 static const int attrvalueslen[] = {2, 2, 5}; 1601 1602 ok(index >= 0 && index <= 2, "invalid index received %d\n", index); 1603 1604 if (index >= 0 && index <= 2) { 1605 *value = attrvaluesW[index]; 1606 *nValue = attrvalueslen[index]; 1607 } else { 1608 *value = NULL; 1609 *nValue = 0; 1610 } 1611 1612 return S_OK; 1613 } 1614 1615 static HRESULT WINAPI isaxattributes_getValueFromName( 1616 ISAXAttributes* iface, 1617 const WCHAR * pUri, 1618 int nUri, 1619 const WCHAR * pLocalName, 1620 int nLocalName, 1621 const WCHAR ** pValue, 1622 int * nValue) 1623 { 1624 ok(0, "unexpected call\n"); 1625 return E_NOTIMPL; 1626 } 1627 1628 static HRESULT WINAPI isaxattributes_getValueFromQName( 1629 ISAXAttributes* iface, 1630 const WCHAR * pQName, 1631 int nQName, 1632 const WCHAR ** pValue, 1633 int * nValue) 1634 { 1635 ok(0, "unexpected call\n"); 1636 return E_NOTIMPL; 1637 } 1638 1639 static const ISAXAttributesVtbl SAXAttributesVtbl = 1640 { 1641 isaxattributes_QueryInterface, 1642 isaxattributes_AddRef, 1643 isaxattributes_Release, 1644 isaxattributes_getLength, 1645 isaxattributes_getURI, 1646 isaxattributes_getLocalName, 1647 isaxattributes_getQName, 1648 isaxattributes_getName, 1649 isaxattributes_getIndexFromName, 1650 isaxattributes_getIndexFromQName, 1651 isaxattributes_getType, 1652 isaxattributes_getTypeFromName, 1653 isaxattributes_getTypeFromQName, 1654 isaxattributes_getValue, 1655 isaxattributes_getValueFromName, 1656 isaxattributes_getValueFromQName 1657 }; 1658 1659 static ISAXAttributes saxattributes = { &SAXAttributesVtbl }; 1660 1661 struct saxlexicalhandler 1662 { 1663 ISAXLexicalHandler ISAXLexicalHandler_iface; 1664 LONG ref; 1665 1666 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */ 1667 }; 1668 1669 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface ) 1670 { 1671 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface); 1672 } 1673 1674 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out) 1675 { 1676 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface); 1677 1678 *out = NULL; 1679 1680 if (IsEqualGUID(riid, &IID_IUnknown)) 1681 { 1682 *out = iface; 1683 ok(0, "got unexpected IID_IUnknown query\n"); 1684 } 1685 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler)) 1686 { 1687 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr; 1688 *out = iface; 1689 } 1690 1691 if (*out) 1692 ISAXLexicalHandler_AddRef(iface); 1693 else 1694 return E_NOINTERFACE; 1695 1696 return S_OK; 1697 } 1698 1699 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface) 1700 { 1701 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface); 1702 return InterlockedIncrement(&handler->ref); 1703 } 1704 1705 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface) 1706 { 1707 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface); 1708 return InterlockedDecrement(&handler->ref); 1709 } 1710 1711 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface, 1712 const WCHAR * pName, int nName, const WCHAR * pPublicId, 1713 int nPublicId, const WCHAR * pSystemId, int nSystemId) 1714 { 1715 ok(0, "call not expected\n"); 1716 return E_NOTIMPL; 1717 } 1718 1719 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface) 1720 { 1721 ok(0, "call not expected\n"); 1722 return E_NOTIMPL; 1723 } 1724 1725 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface, 1726 const WCHAR * pName, int nName) 1727 { 1728 ok(0, "call not expected\n"); 1729 return E_NOTIMPL; 1730 } 1731 1732 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface, 1733 const WCHAR * pName, int nName) 1734 { 1735 ok(0, "call not expected\n"); 1736 return E_NOTIMPL; 1737 } 1738 1739 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface) 1740 { 1741 struct call_entry call; 1742 1743 init_call_entry(locator, &call); 1744 call.id = LH_STARTCDATA; 1745 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1746 1747 return get_expected_ret(); 1748 } 1749 1750 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface) 1751 { 1752 struct call_entry call; 1753 1754 init_call_entry(locator, &call); 1755 call.id = LH_ENDCDATA; 1756 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1757 1758 return get_expected_ret(); 1759 } 1760 1761 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface, 1762 const WCHAR * pChars, int nChars) 1763 { 1764 ok(0, "call not expected\n"); 1765 return E_NOTIMPL; 1766 } 1767 1768 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl = 1769 { 1770 isaxlexical_QueryInterface, 1771 isaxlexical_AddRef, 1772 isaxlexical_Release, 1773 isaxlexical_startDTD, 1774 isaxlexical_endDTD, 1775 isaxlexical_startEntity, 1776 isaxlexical_endEntity, 1777 isaxlexical_startCDATA, 1778 isaxlexical_endCDATA, 1779 isaxlexical_comment 1780 }; 1781 1782 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr) 1783 { 1784 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl; 1785 handler->ref = 1; 1786 handler->qi_hr = hr; 1787 } 1788 1789 struct saxdeclhandler 1790 { 1791 ISAXDeclHandler ISAXDeclHandler_iface; 1792 LONG ref; 1793 1794 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */ 1795 }; 1796 1797 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface ) 1798 { 1799 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface); 1800 } 1801 1802 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out) 1803 { 1804 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface); 1805 1806 *out = NULL; 1807 1808 if (IsEqualGUID(riid, &IID_IUnknown)) 1809 { 1810 *out = iface; 1811 ok(0, "got unexpected IID_IUnknown query\n"); 1812 } 1813 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler)) 1814 { 1815 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr; 1816 *out = iface; 1817 } 1818 1819 if (*out) 1820 ISAXDeclHandler_AddRef(iface); 1821 else 1822 return E_NOINTERFACE; 1823 1824 return S_OK; 1825 } 1826 1827 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface) 1828 { 1829 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface); 1830 return InterlockedIncrement(&handler->ref); 1831 } 1832 1833 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface) 1834 { 1835 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface); 1836 return InterlockedDecrement(&handler->ref); 1837 } 1838 1839 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface, 1840 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel) 1841 { 1842 ok(0, "call not expected\n"); 1843 return E_NOTIMPL; 1844 } 1845 1846 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface, 1847 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName, 1848 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault, 1849 int nValueDefault, const WCHAR * pValue, int nValue) 1850 { 1851 ok(0, "call not expected\n"); 1852 return E_NOTIMPL; 1853 } 1854 1855 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface, 1856 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue) 1857 { 1858 ok(0, "call not expected\n"); 1859 return E_NOTIMPL; 1860 } 1861 1862 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface, 1863 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId, 1864 const WCHAR * pSystemId, int nSystemId) 1865 { 1866 ok(0, "call not expected\n"); 1867 return E_NOTIMPL; 1868 } 1869 1870 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl = 1871 { 1872 isaxdecl_QueryInterface, 1873 isaxdecl_AddRef, 1874 isaxdecl_Release, 1875 isaxdecl_elementDecl, 1876 isaxdecl_attributeDecl, 1877 isaxdecl_internalEntityDecl, 1878 isaxdecl_externalEntityDecl 1879 }; 1880 1881 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr) 1882 { 1883 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl; 1884 handler->ref = 1; 1885 handler->qi_hr = hr; 1886 } 1887 1888 typedef struct mxwriter_write_test_t { 1889 BOOL last; 1890 const BYTE *data; 1891 DWORD cb; 1892 BOOL null_written; 1893 BOOL fail_write; 1894 } mxwriter_write_test; 1895 1896 typedef struct mxwriter_stream_test_t { 1897 VARIANT_BOOL bom; 1898 const char *encoding; 1899 mxwriter_write_test expected_writes[4]; 1900 } mxwriter_stream_test; 1901 1902 static const mxwriter_write_test *current_write_test; 1903 static DWORD current_stream_test_index; 1904 1905 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject) 1906 { 1907 *ppvObject = NULL; 1908 1909 ok(!IsEqualGUID(riid, &IID_IPersistStream), "Did not expect QI for IPersistStream\n"); 1910 1911 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown)) 1912 *ppvObject = iface; 1913 else 1914 return E_NOINTERFACE; 1915 1916 return S_OK; 1917 } 1918 1919 static ULONG WINAPI istream_AddRef(IStream *iface) 1920 { 1921 return 2; 1922 } 1923 1924 static ULONG WINAPI istream_Release(IStream *iface) 1925 { 1926 return 1; 1927 } 1928 1929 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead) 1930 { 1931 ok(0, "unexpected call\n"); 1932 return E_NOTIMPL; 1933 } 1934 1935 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten) 1936 { 1937 ok(0, "unexpected call\n"); 1938 return E_NOTIMPL; 1939 } 1940 1941 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, 1942 ULARGE_INTEGER *plibNewPosition) 1943 { 1944 ok(0, "unexpected call\n"); 1945 return E_NOTIMPL; 1946 } 1947 1948 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize) 1949 { 1950 ok(0, "unexpected call\n"); 1951 return E_NOTIMPL; 1952 } 1953 1954 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb, 1955 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten) 1956 { 1957 ok(0, "unexpected call\n"); 1958 return E_NOTIMPL; 1959 } 1960 1961 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags) 1962 { 1963 ok(0, "unexpected call\n"); 1964 return E_NOTIMPL; 1965 } 1966 1967 static HRESULT WINAPI istream_Revert(IStream *iface) 1968 { 1969 ok(0, "unexpected call\n"); 1970 return E_NOTIMPL; 1971 } 1972 1973 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, 1974 ULARGE_INTEGER cb, DWORD dwLockType) 1975 { 1976 ok(0, "unexpected call\n"); 1977 return E_NOTIMPL; 1978 } 1979 1980 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, 1981 ULARGE_INTEGER cb, DWORD dwLockType) 1982 { 1983 ok(0, "unexpected call\n"); 1984 return E_NOTIMPL; 1985 } 1986 1987 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag) 1988 { 1989 return E_NOTIMPL; 1990 } 1991 1992 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm) 1993 { 1994 ok(0, "unexpected call\n"); 1995 return E_NOTIMPL; 1996 } 1997 1998 static HRESULT WINAPI mxstream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten) 1999 { 2000 BOOL fail = FALSE; 2001 2002 ok(pv != NULL, "pv == NULL\n"); 2003 2004 if(current_write_test->last) { 2005 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index); 2006 return E_FAIL; 2007 } 2008 2009 fail = current_write_test->fail_write; 2010 2011 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n", 2012 current_write_test->cb, cb, current_stream_test_index); 2013 2014 if(!pcbWritten) 2015 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index); 2016 else 2017 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index); 2018 2019 ++current_write_test; 2020 2021 if(pcbWritten) 2022 *pcbWritten = cb; 2023 2024 return fail ? E_FAIL : S_OK; 2025 } 2026 2027 static const IStreamVtbl mxstreamVtbl = { 2028 istream_QueryInterface, 2029 istream_AddRef, 2030 istream_Release, 2031 istream_Read, 2032 mxstream_Write, 2033 istream_Seek, 2034 istream_SetSize, 2035 istream_CopyTo, 2036 istream_Commit, 2037 istream_Revert, 2038 istream_LockRegion, 2039 istream_UnlockRegion, 2040 istream_Stat, 2041 istream_Clone 2042 }; 2043 2044 static IStream mxstream = { &mxstreamVtbl }; 2045 2046 static int read_cnt; 2047 2048 static HRESULT WINAPI instream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead) 2049 { 2050 static const char *ret_str; 2051 2052 if(!read_cnt) 2053 ret_str = "<?xml version=\"1.0\" ?>\n<rootelem>"; 2054 else if(read_cnt < 5) 2055 ret_str = "<elem attr=\"val\">text</elem>"; 2056 else if(read_cnt == 5) 2057 ret_str = "</rootelem>\n"; 2058 else 2059 ret_str = ""; 2060 2061 read_cnt++; 2062 strcpy(pv, ret_str); 2063 *pcbRead = strlen(ret_str); 2064 return S_OK; 2065 } 2066 2067 static const IStreamVtbl instreamVtbl = { 2068 istream_QueryInterface, 2069 istream_AddRef, 2070 istream_Release, 2071 instream_Read, 2072 istream_Write, 2073 istream_Seek, 2074 istream_SetSize, 2075 istream_CopyTo, 2076 istream_Commit, 2077 istream_Revert, 2078 istream_LockRegion, 2079 istream_UnlockRegion, 2080 istream_Stat, 2081 istream_Clone 2082 }; 2083 2084 static IStream instream = { &instreamVtbl }; 2085 2086 static struct msxmlsupported_data_t reader_support_data[] = 2087 { 2088 { &CLSID_SAXXMLReader, "SAXReader" }, 2089 { &CLSID_SAXXMLReader30, "SAXReader30" }, 2090 { &CLSID_SAXXMLReader40, "SAXReader40" }, 2091 { &CLSID_SAXXMLReader60, "SAXReader60" }, 2092 { NULL } 2093 }; 2094 2095 static struct saxlexicalhandler lexicalhandler; 2096 static struct saxdeclhandler declhandler; 2097 2098 static IStream *create_test_stream(const char *data, int len) 2099 { 2100 ULARGE_INTEGER size; 2101 LARGE_INTEGER pos; 2102 IStream *stream; 2103 ULONG written; 2104 2105 if (len == -1) len = strlen(data); 2106 CreateStreamOnHGlobal(NULL, TRUE, &stream); 2107 size.QuadPart = len; 2108 IStream_SetSize(stream, size); 2109 IStream_Write(stream, data, len, &written); 2110 pos.QuadPart = 0; 2111 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL); 2112 2113 return stream; 2114 } 2115 2116 static void test_saxreader(void) 2117 { 2118 const struct msxmlsupported_data_t *table = reader_support_data; 2119 HRESULT hr; 2120 ISAXXMLReader *reader = NULL; 2121 VARIANT var; 2122 ISAXContentHandler *content; 2123 ISAXErrorHandler *lpErrorHandler; 2124 SAFEARRAY *sa; 2125 SAFEARRAYBOUND SADim[1]; 2126 char *ptr = NULL; 2127 IStream *stream; 2128 ULONG written; 2129 HANDLE file; 2130 static const CHAR testXmlA[] = "test.xml"; 2131 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0}; 2132 IXMLDOMDocument *doc; 2133 char seqname[50]; 2134 VARIANT_BOOL v; 2135 2136 while (table->clsid) 2137 { 2138 struct call_entry *test_seq; 2139 ISAXEntityResolver *resolver; 2140 BSTR str; 2141 2142 if (!is_clsid_supported(table->clsid, reader_support_data)) 2143 { 2144 table++; 2145 continue; 2146 } 2147 2148 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader); 2149 EXPECT_HR(hr, S_OK); 2150 g_reader = reader; 2151 2152 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) 2153 msxml_version = 4; 2154 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2155 msxml_version = 6; 2156 else 2157 msxml_version = 0; 2158 2159 /* crashes on old versions */ 2160 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) && 2161 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2162 { 2163 hr = ISAXXMLReader_getContentHandler(reader, NULL); 2164 EXPECT_HR(hr, E_POINTER); 2165 2166 hr = ISAXXMLReader_getErrorHandler(reader, NULL); 2167 EXPECT_HR(hr, E_POINTER); 2168 } 2169 2170 hr = ISAXXMLReader_getContentHandler(reader, &content); 2171 EXPECT_HR(hr, S_OK); 2172 ok(content == NULL, "Expected %p, got %p\n", NULL, content); 2173 2174 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler); 2175 EXPECT_HR(hr, S_OK); 2176 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler); 2177 2178 hr = ISAXXMLReader_putContentHandler(reader, NULL); 2179 EXPECT_HR(hr, S_OK); 2180 2181 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler); 2182 EXPECT_HR(hr, S_OK); 2183 2184 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler); 2185 EXPECT_HR(hr, S_OK); 2186 2187 hr = ISAXXMLReader_getContentHandler(reader, &content); 2188 EXPECT_HR(hr, S_OK); 2189 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content); 2190 2191 V_VT(&var) = VT_BSTR; 2192 V_BSTR(&var) = SysAllocString(szSimpleXML); 2193 2194 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2195 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2196 test_seq = content_handler_test1_alternate; 2197 else 2198 test_seq = content_handler_test1; 2199 set_expected_seq(test_seq); 2200 hr = ISAXXMLReader_parse(reader, var); 2201 EXPECT_HR(hr, S_OK); 2202 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE); 2203 2204 VariantClear(&var); 2205 2206 SADim[0].lLbound = 0; 2207 SADim[0].cElements = sizeof(testXML)-1; 2208 sa = SafeArrayCreate(VT_UI1, 1, SADim); 2209 SafeArrayAccessData(sa, (void**)&ptr); 2210 memcpy(ptr, testXML, sizeof(testXML)-1); 2211 SafeArrayUnaccessData(sa); 2212 V_VT(&var) = VT_ARRAY|VT_UI1; 2213 V_ARRAY(&var) = sa; 2214 2215 set_expected_seq(test_seq); 2216 hr = ISAXXMLReader_parse(reader, var); 2217 EXPECT_HR(hr, S_OK); 2218 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE); 2219 2220 SafeArrayDestroy(sa); 2221 2222 V_VT(&var) = VT_UNKNOWN; 2223 V_UNKNOWN(&var) = NULL; 2224 hr = ISAXXMLReader_parse(reader, var); 2225 ok(hr == E_INVALIDARG, "got %#x\n", hr); 2226 2227 V_VT(&var) = VT_DISPATCH; 2228 V_DISPATCH(&var) = NULL; 2229 hr = ISAXXMLReader_parse(reader, var); 2230 ok(hr == E_INVALIDARG, "got %#x\n", hr); 2231 2232 stream = create_test_stream(testXML, -1); 2233 V_VT(&var) = VT_UNKNOWN; 2234 V_UNKNOWN(&var) = (IUnknown*)stream; 2235 2236 set_expected_seq(test_seq); 2237 hr = ISAXXMLReader_parse(reader, var); 2238 EXPECT_HR(hr, S_OK); 2239 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE); 2240 2241 IStream_Release(stream); 2242 2243 stream = create_test_stream(test_attributes, -1); 2244 V_VT(&var) = VT_UNKNOWN; 2245 V_UNKNOWN(&var) = (IUnknown*)stream; 2246 2247 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) 2248 test_seq = content_handler_test_attributes_alternate_4; 2249 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2250 test_seq = content_handler_test_attributes_alternate_6; 2251 else 2252 test_seq = content_handler_test_attributes; 2253 2254 set_expected_seq(test_seq); 2255 hr = ISAXXMLReader_parse(reader, var); 2256 EXPECT_HR(hr, S_OK); 2257 2258 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2259 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2260 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE); 2261 else 2262 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE); 2263 2264 IStream_Release(stream); 2265 2266 V_VT(&var) = VT_UNKNOWN; 2267 V_UNKNOWN(&var) = (IUnknown*)&instream; 2268 2269 test_seq = read_test_seq; 2270 read_cnt = 0; 2271 set_expected_seq(test_seq); 2272 hr = ISAXXMLReader_parse(reader, var); 2273 EXPECT_HR(hr, S_OK); 2274 ok(read_cnt == 7, "read_cnt = %d\n", read_cnt); 2275 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "Read call test", FALSE); 2276 2277 V_VT(&var) = VT_BSTR; 2278 V_BSTR(&var) = SysAllocString(carriage_ret_test); 2279 2280 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2281 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2282 test_seq = content_handler_test2_alternate; 2283 else 2284 test_seq = content_handler_test2; 2285 2286 set_expected_seq(test_seq); 2287 hr = ISAXXMLReader_parse(reader, var); 2288 EXPECT_HR(hr, S_OK); 2289 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE); 2290 2291 VariantClear(&var); 2292 2293 /* from file url */ 2294 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 2295 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError()); 2296 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL); 2297 CloseHandle(file); 2298 2299 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2300 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2301 test_seq = content_handler_test1_alternate; 2302 else 2303 test_seq = content_handler_test1; 2304 set_expected_seq(test_seq); 2305 hr = ISAXXMLReader_parseURL(reader, testXmlW); 2306 EXPECT_HR(hr, S_OK); 2307 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE); 2308 2309 /* error handler */ 2310 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2311 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2312 test_seq = content_handler_testerror_alternate; 2313 else 2314 test_seq = content_handler_testerror; 2315 set_expected_seq(test_seq); 2316 hr = ISAXXMLReader_parseURL(reader, testXmlW); 2317 EXPECT_HR(hr, E_FAIL); 2318 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE); 2319 2320 /* callback ret values */ 2321 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2322 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2323 { 2324 test_seq = content_handler_test_callback_rets_alt; 2325 set_expected_seq(test_seq); 2326 hr = ISAXXMLReader_parseURL(reader, testXmlW); 2327 EXPECT_HR(hr, S_OK); 2328 } 2329 else 2330 { 2331 test_seq = content_handler_test_callback_rets; 2332 set_expected_seq(test_seq); 2333 hr = ISAXXMLReader_parseURL(reader, testXmlW); 2334 EXPECT_HR(hr, S_FALSE); 2335 } 2336 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE); 2337 2338 DeleteFileA(testXmlA); 2339 2340 /* parse from IXMLDOMDocument */ 2341 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, 2342 &IID_IXMLDOMDocument, (void**)&doc); 2343 EXPECT_HR(hr, S_OK); 2344 2345 str = SysAllocString(szSimpleXML); 2346 hr = IXMLDOMDocument_loadXML(doc, str, &v); 2347 EXPECT_HR(hr, S_OK); 2348 SysFreeString(str); 2349 2350 V_VT(&var) = VT_UNKNOWN; 2351 V_UNKNOWN(&var) = (IUnknown*)doc; 2352 2353 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2354 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2355 test_seq = content_handler_test2_alternate; 2356 else 2357 test_seq = content_handler_test2; 2358 2359 set_expected_seq(test_seq); 2360 hr = ISAXXMLReader_parse(reader, var); 2361 EXPECT_HR(hr, S_OK); 2362 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE); 2363 IXMLDOMDocument_Release(doc); 2364 2365 /* xml:space test */ 2366 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2367 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2368 { 2369 test_seq = xmlspaceattr_test_alternate; 2370 } 2371 else 2372 test_seq = xmlspaceattr_test; 2373 2374 set_expected_seq(test_seq); 2375 V_VT(&var) = VT_BSTR; 2376 V_BSTR(&var) = _bstr_(xmlspace_attr); 2377 hr = ISAXXMLReader_parse(reader, var); 2378 EXPECT_HR(hr, S_OK); 2379 2380 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2381 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2382 { 2383 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE); 2384 } 2385 else 2386 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE); 2387 2388 /* switch off 'namespaces' feature */ 2389 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE); 2390 EXPECT_HR(hr, S_OK); 2391 2392 stream = create_test_stream(test_attributes, -1); 2393 V_VT(&var) = VT_UNKNOWN; 2394 V_UNKNOWN(&var) = (IUnknown*)stream; 2395 2396 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2397 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2398 { 2399 test_seq = content_handler_test_attributes_alt_no_ns; 2400 } 2401 else 2402 test_seq = content_handler_test_attributes; 2403 2404 set_expected_seq(test_seq); 2405 hr = ISAXXMLReader_parse(reader, var); 2406 EXPECT_HR(hr, S_OK); 2407 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE); 2408 IStream_Release(stream); 2409 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE); 2410 EXPECT_HR(hr, S_OK); 2411 2412 /* switch off 'namespace-prefixes' feature */ 2413 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE); 2414 EXPECT_HR(hr, S_OK); 2415 2416 stream = create_test_stream(test_attributes, -1); 2417 V_VT(&var) = VT_UNKNOWN; 2418 V_UNKNOWN(&var) = (IUnknown*)stream; 2419 2420 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2421 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2422 { 2423 test_seq = content_handler_test_attributes_alt_no_prefix; 2424 } 2425 else 2426 test_seq = content_handler_test_attributes_no_prefix; 2427 2428 set_expected_seq(test_seq); 2429 hr = ISAXXMLReader_parse(reader, var); 2430 EXPECT_HR(hr, S_OK); 2431 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE); 2432 IStream_Release(stream); 2433 2434 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE); 2435 EXPECT_HR(hr, S_OK); 2436 2437 /* attribute normalization */ 2438 stream = create_test_stream(attribute_normalize, -1); 2439 V_VT(&var) = VT_UNKNOWN; 2440 V_UNKNOWN(&var) = (IUnknown*)stream; 2441 2442 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2443 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2444 { 2445 test_seq = attribute_norm_alt; 2446 } 2447 else 2448 test_seq = attribute_norm; 2449 2450 set_expected_seq(test_seq); 2451 hr = ISAXXMLReader_parse(reader, var); 2452 EXPECT_HR(hr, S_OK); 2453 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE); 2454 IStream_Release(stream); 2455 2456 resolver = (void*)0xdeadbeef; 2457 hr = ISAXXMLReader_getEntityResolver(reader, &resolver); 2458 ok(hr == S_OK, "got 0x%08x\n", hr); 2459 ok(resolver == NULL, "got %p\n", resolver); 2460 2461 hr = ISAXXMLReader_putEntityResolver(reader, NULL); 2462 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr); 2463 2464 /* CDATA sections */ 2465 init_saxlexicalhandler(&lexicalhandler, S_OK); 2466 2467 V_VT(&var) = VT_UNKNOWN; 2468 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface; 2469 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var); 2470 ok(hr == S_OK, "got 0x%08x\n", hr); 2471 2472 stream = create_test_stream(test_cdata_xml, -1); 2473 V_VT(&var) = VT_UNKNOWN; 2474 V_UNKNOWN(&var) = (IUnknown*)stream; 2475 2476 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) || 2477 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) 2478 test_seq = cdata_test_alt; 2479 else 2480 test_seq = cdata_test; 2481 2482 set_expected_seq(test_seq); 2483 hr = ISAXXMLReader_parse(reader, var); 2484 ok(hr == S_OK, "got 0x%08x\n", hr); 2485 sprintf(seqname, "%s: cdata test", table->name); 2486 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); 2487 2488 IStream_Release(stream); 2489 2490 /* 2. CDATA sections */ 2491 stream = create_test_stream(test2_cdata_xml, -1); 2492 V_VT(&var) = VT_UNKNOWN; 2493 V_UNKNOWN(&var) = (IUnknown*)stream; 2494 2495 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) || 2496 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) 2497 test_seq = cdata_test2_alt; 2498 else 2499 test_seq = cdata_test2; 2500 2501 set_expected_seq(test_seq); 2502 hr = ISAXXMLReader_parse(reader, var); 2503 ok(hr == S_OK, "got 0x%08x\n", hr); 2504 sprintf(seqname, "%s: cdata test 2", table->name); 2505 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); 2506 2507 IStream_Release(stream); 2508 2509 /* 3. CDATA sections */ 2510 stream = create_test_stream(test3_cdata_xml, -1); 2511 V_VT(&var) = VT_UNKNOWN; 2512 V_UNKNOWN(&var) = (IUnknown*)stream; 2513 2514 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) || 2515 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) 2516 test_seq = cdata_test3_alt; 2517 else 2518 test_seq = cdata_test3; 2519 2520 set_expected_seq(test_seq); 2521 hr = ISAXXMLReader_parse(reader, var); 2522 ok(hr == S_OK, "got 0x%08x\n", hr); 2523 sprintf(seqname, "%s: cdata test 3", table->name); 2524 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); 2525 2526 IStream_Release(stream); 2527 2528 ISAXXMLReader_Release(reader); 2529 table++; 2530 } 2531 2532 free_bstrs(); 2533 } 2534 2535 struct saxreader_props_test_t 2536 { 2537 const char *prop_name; 2538 IUnknown *iface; 2539 }; 2540 2541 static const struct saxreader_props_test_t props_test_data[] = { 2542 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface }, 2543 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface }, 2544 { 0 } 2545 }; 2546 2547 static void test_saxreader_properties(void) 2548 { 2549 const struct saxreader_props_test_t *ptr = props_test_data; 2550 ISAXXMLReader *reader; 2551 HRESULT hr; 2552 VARIANT v; 2553 BSTR str; 2554 2555 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER, 2556 &IID_ISAXXMLReader, (void**)&reader); 2557 EXPECT_HR(hr, S_OK); 2558 2559 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL); 2560 EXPECT_HR(hr, E_POINTER); 2561 2562 while (ptr->prop_name) 2563 { 2564 VARIANT varref; 2565 LONG ref; 2566 2567 init_saxlexicalhandler(&lexicalhandler, S_OK); 2568 init_saxdeclhandler(&declhandler, S_OK); 2569 2570 V_VT(&v) = VT_EMPTY; 2571 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2572 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2573 EXPECT_HR(hr, S_OK); 2574 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2575 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v)); 2576 2577 /* VT_UNKNOWN */ 2578 V_VT(&v) = VT_UNKNOWN; 2579 V_UNKNOWN(&v) = ptr->iface; 2580 ref = get_refcount(ptr->iface); 2581 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2582 EXPECT_HR(hr, S_OK); 2583 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n"); 2584 2585 /* VT_DISPATCH */ 2586 V_VT(&v) = VT_DISPATCH; 2587 V_UNKNOWN(&v) = ptr->iface; 2588 ref = get_refcount(ptr->iface); 2589 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2590 EXPECT_HR(hr, S_OK); 2591 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref); 2592 2593 /* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */ 2594 V_VT(&varref) = VT_UNKNOWN; 2595 V_UNKNOWN(&varref) = ptr->iface; 2596 2597 V_VT(&v) = VT_VARIANT|VT_BYREF; 2598 V_VARIANTREF(&v) = &varref; 2599 ref = get_refcount(ptr->iface); 2600 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2601 EXPECT_HR(hr, S_OK); 2602 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref); 2603 2604 /* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */ 2605 V_VT(&varref) = VT_DISPATCH; 2606 V_UNKNOWN(&varref) = ptr->iface; 2607 2608 V_VT(&v) = VT_VARIANT|VT_BYREF; 2609 V_VARIANTREF(&v) = &varref; 2610 ref = get_refcount(ptr->iface); 2611 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2612 EXPECT_HR(hr, S_OK); 2613 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref); 2614 2615 V_VT(&v) = VT_EMPTY; 2616 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2617 2618 ref = get_refcount(ptr->iface); 2619 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2620 EXPECT_HR(hr, S_OK); 2621 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2622 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v)); 2623 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n"); 2624 VariantClear(&v); 2625 2626 V_VT(&v) = VT_EMPTY; 2627 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2628 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2629 EXPECT_HR(hr, S_OK); 2630 2631 V_VT(&v) = VT_EMPTY; 2632 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2633 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2634 EXPECT_HR(hr, S_OK); 2635 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2636 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v)); 2637 2638 V_VT(&v) = VT_UNKNOWN; 2639 V_UNKNOWN(&v) = ptr->iface; 2640 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2641 EXPECT_HR(hr, S_OK); 2642 2643 /* only VT_EMPTY seems to be valid to reset property */ 2644 V_VT(&v) = VT_I4; 2645 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2646 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2647 EXPECT_HR(hr, E_INVALIDARG); 2648 2649 V_VT(&v) = VT_EMPTY; 2650 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2651 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2652 EXPECT_HR(hr, S_OK); 2653 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2654 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v)); 2655 VariantClear(&v); 2656 2657 V_VT(&v) = VT_UNKNOWN; 2658 V_UNKNOWN(&v) = NULL; 2659 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2660 EXPECT_HR(hr, S_OK); 2661 2662 V_VT(&v) = VT_EMPTY; 2663 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2664 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2665 EXPECT_HR(hr, S_OK); 2666 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2667 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v)); 2668 2669 /* block QueryInterface on handler riid */ 2670 V_VT(&v) = VT_UNKNOWN; 2671 V_UNKNOWN(&v) = ptr->iface; 2672 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2673 EXPECT_HR(hr, S_OK); 2674 2675 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE); 2676 init_saxdeclhandler(&declhandler, E_NOINTERFACE); 2677 2678 V_VT(&v) = VT_UNKNOWN; 2679 V_UNKNOWN(&v) = ptr->iface; 2680 EXPECT_REF(ptr->iface, 1); 2681 ref = get_refcount(ptr->iface); 2682 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2683 EXPECT_HR(hr, E_NOINTERFACE); 2684 EXPECT_REF(ptr->iface, 1); 2685 2686 V_VT(&v) = VT_EMPTY; 2687 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2688 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2689 EXPECT_HR(hr, S_OK); 2690 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2691 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v)); 2692 2693 ptr++; 2694 free_bstrs(); 2695 } 2696 2697 ISAXXMLReader_Release(reader); 2698 2699 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data)) 2700 return; 2701 2702 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, 2703 &IID_ISAXXMLReader, (void**)&reader); 2704 EXPECT_HR(hr, S_OK); 2705 2706 /* xmldecl-version property */ 2707 V_VT(&v) = VT_EMPTY; 2708 V_BSTR(&v) = (void*)0xdeadbeef; 2709 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v); 2710 EXPECT_HR(hr, S_OK); 2711 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); 2712 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v))); 2713 2714 /* stream without declaration */ 2715 V_VT(&v) = VT_BSTR; 2716 V_BSTR(&v) = _bstr_("<element></element>"); 2717 hr = ISAXXMLReader_parse(reader, v); 2718 EXPECT_HR(hr, S_OK); 2719 2720 V_VT(&v) = VT_EMPTY; 2721 V_BSTR(&v) = (void*)0xdeadbeef; 2722 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v); 2723 EXPECT_HR(hr, S_OK); 2724 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); 2725 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v))); 2726 2727 /* stream with declaration */ 2728 V_VT(&v) = VT_BSTR; 2729 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>"); 2730 hr = ISAXXMLReader_parse(reader, v); 2731 EXPECT_HR(hr, S_OK); 2732 2733 /* VT_BSTR|VT_BYREF input type */ 2734 str = _bstr_("<?xml version=\"1.0\"?><element></element>"); 2735 V_VT(&v) = VT_BSTR|VT_BYREF; 2736 V_BSTRREF(&v) = &str; 2737 hr = ISAXXMLReader_parse(reader, v); 2738 EXPECT_HR(hr, S_OK); 2739 2740 V_VT(&v) = VT_EMPTY; 2741 V_BSTR(&v) = (void*)0xdeadbeef; 2742 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v); 2743 EXPECT_HR(hr, S_OK); 2744 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); 2745 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v))); 2746 VariantClear(&v); 2747 2748 ISAXXMLReader_Release(reader); 2749 free_bstrs(); 2750 } 2751 2752 struct feature_ns_entry_t { 2753 const GUID *guid; 2754 const char *clsid; 2755 VARIANT_BOOL value; 2756 VARIANT_BOOL value2; /* feature value after feature set to 0xc */ 2757 }; 2758 2759 static const struct feature_ns_entry_t feature_ns_entry_data[] = { 2760 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE }, 2761 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE }, 2762 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE }, 2763 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE }, 2764 { 0 } 2765 }; 2766 2767 static const char *feature_names[] = { 2768 "http://xml.org/sax/features/namespaces", 2769 "http://xml.org/sax/features/namespace-prefixes", 2770 0 2771 }; 2772 2773 static void test_saxreader_features(void) 2774 { 2775 const struct feature_ns_entry_t *entry = feature_ns_entry_data; 2776 ISAXXMLReader *reader; 2777 2778 while (entry->guid) 2779 { 2780 VARIANT_BOOL value; 2781 const char **name; 2782 HRESULT hr; 2783 2784 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader); 2785 if (hr != S_OK) 2786 { 2787 win_skip("can't create %s instance\n", entry->clsid); 2788 entry++; 2789 continue; 2790 } 2791 2792 if (IsEqualGUID(entry->guid, &CLSID_SAXXMLReader40) || 2793 IsEqualGUID(entry->guid, &CLSID_SAXXMLReader60)) 2794 { 2795 value = VARIANT_TRUE; 2796 hr = ISAXXMLReader_getFeature(reader, _bstr_("exhaustive-errors"), &value); 2797 ok(hr == S_OK, "Failed to get feature value, hr %#x.\n", hr); 2798 ok(value == VARIANT_FALSE, "Unexpected default feature value.\n"); 2799 hr = ISAXXMLReader_putFeature(reader, _bstr_("exhaustive-errors"), VARIANT_FALSE); 2800 ok(hr == S_OK, "Failed to put feature value, hr %#x.\n", hr); 2801 2802 value = VARIANT_TRUE; 2803 hr = ISAXXMLReader_getFeature(reader, _bstr_("schema-validation"), &value); 2804 ok(hr == S_OK, "Failed to get feature value, hr %#x.\n", hr); 2805 ok(value == VARIANT_FALSE, "Unexpected default feature value.\n"); 2806 hr = ISAXXMLReader_putFeature(reader, _bstr_("exhaustive-errors"), VARIANT_FALSE); 2807 ok(hr == S_OK, "Failed to put feature value, hr %#x.\n", hr); 2808 } 2809 else 2810 { 2811 value = 123; 2812 hr = ISAXXMLReader_getFeature(reader, _bstr_("exhaustive-errors"), &value); 2813 ok(hr == E_INVALIDARG, "Failed to get feature value, hr %#x.\n", hr); 2814 ok(value == 123, "Unexpected value %d.\n", value); 2815 2816 value = 123; 2817 hr = ISAXXMLReader_getFeature(reader, _bstr_("schema-validation"), &value); 2818 ok(hr == E_INVALIDARG, "Failed to get feature value, hr %#x.\n", hr); 2819 ok(value == 123, "Unexpected value %d.\n", value); 2820 } 2821 2822 name = feature_names; 2823 while (*name) 2824 { 2825 value = 0xc; 2826 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value); 2827 EXPECT_HR(hr, S_OK); 2828 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value); 2829 2830 value = 0xc; 2831 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value); 2832 EXPECT_HR(hr, S_OK); 2833 2834 value = 0xd; 2835 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value); 2836 EXPECT_HR(hr, S_OK); 2837 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2); 2838 2839 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE); 2840 EXPECT_HR(hr, S_OK); 2841 value = 0xd; 2842 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value); 2843 EXPECT_HR(hr, S_OK); 2844 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value); 2845 2846 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE); 2847 EXPECT_HR(hr, S_OK); 2848 value = 0xd; 2849 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value); 2850 EXPECT_HR(hr, S_OK); 2851 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value); 2852 2853 name++; 2854 } 2855 2856 ISAXXMLReader_Release(reader); 2857 2858 entry++; 2859 } 2860 } 2861 2862 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */ 2863 static const CHAR UTF8BOMTest[] = 2864 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n" 2865 "<a></a>\n"; 2866 2867 struct enc_test_entry_t { 2868 const GUID *guid; 2869 const char *clsid; 2870 const char *data; 2871 HRESULT hr; 2872 BOOL todo; 2873 }; 2874 2875 static const struct enc_test_entry_t encoding_test_data[] = { 2876 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, TRUE }, 2877 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, TRUE }, 2878 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, FALSE }, 2879 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, FALSE }, 2880 { 0 } 2881 }; 2882 2883 static void test_saxreader_encoding(void) 2884 { 2885 const struct enc_test_entry_t *entry = encoding_test_data; 2886 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0}; 2887 static const CHAR testXmlA[] = "test.xml"; 2888 2889 while (entry->guid) 2890 { 2891 ISAXXMLReader *reader; 2892 VARIANT input; 2893 DWORD written; 2894 HANDLE file; 2895 HRESULT hr; 2896 2897 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader); 2898 if (hr != S_OK) 2899 { 2900 win_skip("can't create %s instance\n", entry->clsid); 2901 entry++; 2902 continue; 2903 } 2904 2905 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 2906 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError()); 2907 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL); 2908 CloseHandle(file); 2909 2910 hr = ISAXXMLReader_parseURL(reader, testXmlW); 2911 todo_wine_if(entry->todo) 2912 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid); 2913 2914 DeleteFileA(testXmlA); 2915 2916 /* try BSTR input with no BOM or '<?xml' instruction */ 2917 V_VT(&input) = VT_BSTR; 2918 V_BSTR(&input) = _bstr_("<element></element>"); 2919 hr = ISAXXMLReader_parse(reader, input); 2920 EXPECT_HR(hr, S_OK); 2921 2922 ISAXXMLReader_Release(reader); 2923 2924 free_bstrs(); 2925 entry++; 2926 } 2927 } 2928 2929 static void test_mxwriter_handlers(void) 2930 { 2931 IMXWriter *writer; 2932 HRESULT hr; 2933 int i; 2934 2935 static REFIID riids[] = 2936 { 2937 &IID_ISAXContentHandler, 2938 &IID_ISAXLexicalHandler, 2939 &IID_ISAXDeclHandler, 2940 &IID_ISAXDTDHandler, 2941 &IID_ISAXErrorHandler, 2942 &IID_IVBSAXDeclHandler, 2943 &IID_IVBSAXLexicalHandler, 2944 &IID_IVBSAXContentHandler, 2945 &IID_IVBSAXDTDHandler, 2946 &IID_IVBSAXErrorHandler 2947 }; 2948 2949 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 2950 &IID_IMXWriter, (void**)&writer); 2951 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 2952 2953 EXPECT_REF(writer, 1); 2954 2955 for (i = 0; i < ARRAY_SIZE(riids); i++) 2956 { 2957 IUnknown *handler; 2958 IMXWriter *writer2; 2959 2960 /* handler from IMXWriter */ 2961 hr = IMXWriter_QueryInterface(writer, riids[i], (void**)&handler); 2962 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr); 2963 EXPECT_REF(writer, 2); 2964 EXPECT_REF(handler, 2); 2965 2966 /* IMXWriter from a handler */ 2967 hr = IUnknown_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2); 2968 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr); 2969 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer); 2970 EXPECT_REF(writer, 3); 2971 IMXWriter_Release(writer2); 2972 IUnknown_Release(handler); 2973 } 2974 2975 IMXWriter_Release(writer); 2976 } 2977 2978 static struct msxmlsupported_data_t mxwriter_support_data[] = 2979 { 2980 { &CLSID_MXXMLWriter, "MXXMLWriter" }, 2981 { &CLSID_MXXMLWriter30, "MXXMLWriter30" }, 2982 { &CLSID_MXXMLWriter40, "MXXMLWriter40" }, 2983 { &CLSID_MXXMLWriter60, "MXXMLWriter60" }, 2984 { NULL } 2985 }; 2986 2987 static struct msxmlsupported_data_t mxattributes_support_data[] = 2988 { 2989 { &CLSID_SAXAttributes, "SAXAttributes" }, 2990 { &CLSID_SAXAttributes30, "SAXAttributes30" }, 2991 { &CLSID_SAXAttributes40, "SAXAttributes40" }, 2992 { &CLSID_SAXAttributes60, "SAXAttributes60" }, 2993 { NULL } 2994 }; 2995 2996 struct mxwriter_props_t 2997 { 2998 const GUID *clsid; 2999 VARIANT_BOOL bom; 3000 VARIANT_BOOL disable_escape; 3001 VARIANT_BOOL indent; 3002 VARIANT_BOOL omitdecl; 3003 VARIANT_BOOL standalone; 3004 const char *encoding; 3005 }; 3006 3007 static const struct mxwriter_props_t mxwriter_default_props[] = 3008 { 3009 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" }, 3010 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" }, 3011 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" }, 3012 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" }, 3013 { NULL } 3014 }; 3015 3016 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table) 3017 { 3018 int i = 0; 3019 3020 while (table->clsid) 3021 { 3022 IMXWriter *writer; 3023 VARIANT_BOOL b; 3024 BSTR encoding; 3025 HRESULT hr; 3026 3027 if (!is_clsid_supported(table->clsid, mxwriter_support_data)) 3028 { 3029 table++; 3030 i++; 3031 continue; 3032 } 3033 3034 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 3035 &IID_IMXWriter, (void**)&writer); 3036 EXPECT_HR(hr, S_OK); 3037 3038 b = !table->bom; 3039 hr = IMXWriter_get_byteOrderMark(writer, &b); 3040 EXPECT_HR(hr, S_OK); 3041 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom); 3042 3043 b = !table->disable_escape; 3044 hr = IMXWriter_get_disableOutputEscaping(writer, &b); 3045 EXPECT_HR(hr, S_OK); 3046 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b, 3047 table->disable_escape); 3048 3049 b = !table->indent; 3050 hr = IMXWriter_get_indent(writer, &b); 3051 EXPECT_HR(hr, S_OK); 3052 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent); 3053 3054 b = !table->omitdecl; 3055 hr = IMXWriter_get_omitXMLDeclaration(writer, &b); 3056 EXPECT_HR(hr, S_OK); 3057 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl); 3058 3059 b = !table->standalone; 3060 hr = IMXWriter_get_standalone(writer, &b); 3061 EXPECT_HR(hr, S_OK); 3062 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone); 3063 3064 hr = IMXWriter_get_encoding(writer, &encoding); 3065 EXPECT_HR(hr, S_OK); 3066 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n", 3067 i, wine_dbgstr_w(encoding), table->encoding); 3068 SysFreeString(encoding); 3069 3070 IMXWriter_Release(writer); 3071 3072 table++; 3073 i++; 3074 } 3075 } 3076 3077 static void test_mxwriter_properties(void) 3078 { 3079 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0}; 3080 static const WCHAR testW[] = {'t','e','s','t',0}; 3081 ISAXContentHandler *content; 3082 IMXWriter *writer; 3083 VARIANT_BOOL b; 3084 HRESULT hr; 3085 BSTR str, str2; 3086 VARIANT dest; 3087 3088 test_mxwriter_default_properties(mxwriter_default_props); 3089 3090 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3091 &IID_IMXWriter, (void**)&writer); 3092 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3093 3094 hr = IMXWriter_get_disableOutputEscaping(writer, NULL); 3095 ok(hr == E_POINTER, "got %08x\n", hr); 3096 3097 hr = IMXWriter_get_byteOrderMark(writer, NULL); 3098 ok(hr == E_POINTER, "got %08x\n", hr); 3099 3100 hr = IMXWriter_get_indent(writer, NULL); 3101 ok(hr == E_POINTER, "got %08x\n", hr); 3102 3103 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL); 3104 ok(hr == E_POINTER, "got %08x\n", hr); 3105 3106 hr = IMXWriter_get_standalone(writer, NULL); 3107 ok(hr == E_POINTER, "got %08x\n", hr); 3108 3109 /* set and check */ 3110 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE); 3111 ok(hr == S_OK, "got %08x\n", hr); 3112 3113 b = VARIANT_FALSE; 3114 hr = IMXWriter_get_standalone(writer, &b); 3115 ok(hr == S_OK, "got %08x\n", hr); 3116 ok(b == VARIANT_TRUE, "got %d\n", b); 3117 3118 hr = IMXWriter_get_encoding(writer, NULL); 3119 EXPECT_HR(hr, E_POINTER); 3120 3121 /* UTF-16 is a default setting apparently */ 3122 str = (void*)0xdeadbeef; 3123 hr = IMXWriter_get_encoding(writer, &str); 3124 EXPECT_HR(hr, S_OK); 3125 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str)); 3126 3127 str2 = (void*)0xdeadbeef; 3128 hr = IMXWriter_get_encoding(writer, &str2); 3129 ok(hr == S_OK, "got %08x\n", hr); 3130 ok(str != str2, "expected newly allocated, got same %p\n", str); 3131 3132 SysFreeString(str2); 3133 SysFreeString(str); 3134 3135 /* put empty string */ 3136 str = SysAllocString(emptyW); 3137 hr = IMXWriter_put_encoding(writer, str); 3138 ok(hr == E_INVALIDARG, "got %08x\n", hr); 3139 SysFreeString(str); 3140 3141 str = (void*)0xdeadbeef; 3142 hr = IMXWriter_get_encoding(writer, &str); 3143 EXPECT_HR(hr, S_OK); 3144 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str)); 3145 SysFreeString(str); 3146 3147 /* invalid encoding name */ 3148 str = SysAllocString(testW); 3149 hr = IMXWriter_put_encoding(writer, str); 3150 ok(hr == E_INVALIDARG, "got %08x\n", hr); 3151 SysFreeString(str); 3152 3153 /* test case sensivity */ 3154 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8")); 3155 EXPECT_HR(hr, S_OK); 3156 str = (void*)0xdeadbeef; 3157 hr = IMXWriter_get_encoding(writer, &str); 3158 EXPECT_HR(hr, S_OK); 3159 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str)); 3160 SysFreeString(str); 3161 3162 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16")); 3163 EXPECT_HR(hr, S_OK); 3164 str = (void*)0xdeadbeef; 3165 hr = IMXWriter_get_encoding(writer, &str); 3166 EXPECT_HR(hr, S_OK); 3167 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str)); 3168 SysFreeString(str); 3169 3170 /* how it affects document creation */ 3171 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3172 EXPECT_HR(hr, S_OK); 3173 3174 hr = ISAXContentHandler_startDocument(content); 3175 EXPECT_HR(hr, S_OK); 3176 hr = ISAXContentHandler_endDocument(content); 3177 EXPECT_HR(hr, S_OK); 3178 3179 V_VT(&dest) = VT_EMPTY; 3180 hr = IMXWriter_get_output(writer, &dest); 3181 EXPECT_HR(hr, S_OK); 3182 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3183 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"), 3184 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3185 VariantClear(&dest); 3186 ISAXContentHandler_Release(content); 3187 3188 hr = IMXWriter_get_version(writer, NULL); 3189 ok(hr == E_POINTER, "got %08x\n", hr); 3190 /* default version is 'surprisingly' 1.0 */ 3191 hr = IMXWriter_get_version(writer, &str); 3192 ok(hr == S_OK, "got %08x\n", hr); 3193 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str)); 3194 SysFreeString(str); 3195 3196 /* store version string as is */ 3197 hr = IMXWriter_put_version(writer, NULL); 3198 ok(hr == E_INVALIDARG, "got %08x\n", hr); 3199 3200 hr = IMXWriter_put_version(writer, _bstr_("1.0")); 3201 ok(hr == S_OK, "got %08x\n", hr); 3202 3203 hr = IMXWriter_put_version(writer, _bstr_("")); 3204 ok(hr == S_OK, "got %08x\n", hr); 3205 hr = IMXWriter_get_version(writer, &str); 3206 ok(hr == S_OK, "got %08x\n", hr); 3207 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str)); 3208 SysFreeString(str); 3209 3210 hr = IMXWriter_put_version(writer, _bstr_("a.b")); 3211 ok(hr == S_OK, "got %08x\n", hr); 3212 hr = IMXWriter_get_version(writer, &str); 3213 ok(hr == S_OK, "got %08x\n", hr); 3214 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str)); 3215 SysFreeString(str); 3216 3217 hr = IMXWriter_put_version(writer, _bstr_("2.0")); 3218 ok(hr == S_OK, "got %08x\n", hr); 3219 hr = IMXWriter_get_version(writer, &str); 3220 ok(hr == S_OK, "got %08x\n", hr); 3221 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str)); 3222 SysFreeString(str); 3223 3224 IMXWriter_Release(writer); 3225 free_bstrs(); 3226 } 3227 3228 static void test_mxwriter_flush(void) 3229 { 3230 ISAXContentHandler *content; 3231 IMXWriter *writer; 3232 LARGE_INTEGER pos; 3233 ULARGE_INTEGER pos2; 3234 IStream *stream; 3235 VARIANT dest; 3236 HRESULT hr; 3237 char *buff; 3238 LONG ref; 3239 int len; 3240 3241 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3242 &IID_IMXWriter, (void**)&writer); 3243 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3244 3245 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 3246 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3247 EXPECT_REF(stream, 1); 3248 3249 /* detach when nothing was attached */ 3250 V_VT(&dest) = VT_EMPTY; 3251 hr = IMXWriter_put_output(writer, dest); 3252 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3253 3254 /* attach stream */ 3255 V_VT(&dest) = VT_UNKNOWN; 3256 V_UNKNOWN(&dest) = (IUnknown*)stream; 3257 hr = IMXWriter_put_output(writer, dest); 3258 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3259 todo_wine EXPECT_REF(stream, 3); 3260 3261 /* detach setting VT_EMPTY destination */ 3262 V_VT(&dest) = VT_EMPTY; 3263 hr = IMXWriter_put_output(writer, dest); 3264 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3265 EXPECT_REF(stream, 1); 3266 3267 V_VT(&dest) = VT_UNKNOWN; 3268 V_UNKNOWN(&dest) = (IUnknown*)stream; 3269 hr = IMXWriter_put_output(writer, dest); 3270 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3271 3272 /* flush() doesn't detach a stream */ 3273 hr = IMXWriter_flush(writer); 3274 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3275 todo_wine EXPECT_REF(stream, 3); 3276 3277 pos.QuadPart = 0; 3278 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3279 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3280 ok(pos2.QuadPart == 0, "expected stream beginning\n"); 3281 3282 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3283 ok(hr == S_OK, "got %08x\n", hr); 3284 3285 hr = ISAXContentHandler_startDocument(content); 3286 ok(hr == S_OK, "got %08x\n", hr); 3287 3288 pos.QuadPart = 0; 3289 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3290 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3291 ok(pos2.QuadPart != 0, "expected stream beginning\n"); 3292 3293 /* already started */ 3294 hr = ISAXContentHandler_startDocument(content); 3295 ok(hr == S_OK, "got %08x\n", hr); 3296 3297 hr = ISAXContentHandler_endDocument(content); 3298 ok(hr == S_OK, "got %08x\n", hr); 3299 3300 /* flushed on endDocument() */ 3301 pos.QuadPart = 0; 3302 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3303 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3304 ok(pos2.QuadPart != 0, "expected stream position moved\n"); 3305 3306 IStream_Release(stream); 3307 3308 /* auto-flush feature */ 3309 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 3310 EXPECT_HR(hr, S_OK); 3311 EXPECT_REF(stream, 1); 3312 3313 V_VT(&dest) = VT_UNKNOWN; 3314 V_UNKNOWN(&dest) = (IUnknown*)stream; 3315 hr = IMXWriter_put_output(writer, dest); 3316 EXPECT_HR(hr, S_OK); 3317 3318 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE); 3319 EXPECT_HR(hr, S_OK); 3320 3321 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3322 EXPECT_HR(hr, S_OK); 3323 3324 hr = ISAXContentHandler_startDocument(content); 3325 EXPECT_HR(hr, S_OK); 3326 3327 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL); 3328 EXPECT_HR(hr, S_OK); 3329 3330 /* internal buffer is flushed automatically on certain threshold */ 3331 pos.QuadPart = 0; 3332 pos2.QuadPart = 1; 3333 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3334 EXPECT_HR(hr, S_OK); 3335 ok(pos2.QuadPart == 0, "expected stream beginning\n"); 3336 3337 len = 2048; 3338 buff = heap_alloc(len + 1); 3339 memset(buff, 'A', len); 3340 buff[len] = 0; 3341 hr = ISAXContentHandler_characters(content, _bstr_(buff), len); 3342 EXPECT_HR(hr, S_OK); 3343 3344 pos.QuadPart = 0; 3345 pos2.QuadPart = 0; 3346 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3347 EXPECT_HR(hr, S_OK); 3348 ok(pos2.QuadPart != 0, "unexpected stream beginning\n"); 3349 3350 hr = IMXWriter_get_output(writer, NULL); 3351 EXPECT_HR(hr, E_POINTER); 3352 3353 ref = get_refcount(stream); 3354 V_VT(&dest) = VT_EMPTY; 3355 hr = IMXWriter_get_output(writer, &dest); 3356 EXPECT_HR(hr, S_OK); 3357 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest)); 3358 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest)); 3359 ok(ref+1 == get_refcount(stream), "expected increased refcount\n"); 3360 VariantClear(&dest); 3361 3362 hr = ISAXContentHandler_endDocument(content); 3363 EXPECT_HR(hr, S_OK); 3364 3365 IStream_Release(stream); 3366 3367 /* test char count lower than threshold */ 3368 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 3369 EXPECT_HR(hr, S_OK); 3370 EXPECT_REF(stream, 1); 3371 3372 hr = ISAXContentHandler_startDocument(content); 3373 EXPECT_HR(hr, S_OK); 3374 3375 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL); 3376 EXPECT_HR(hr, S_OK); 3377 3378 pos.QuadPart = 0; 3379 pos2.QuadPart = 1; 3380 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3381 EXPECT_HR(hr, S_OK); 3382 ok(pos2.QuadPart == 0, "expected stream beginning\n"); 3383 3384 memset(buff, 'A', len); 3385 buff[len] = 0; 3386 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8); 3387 EXPECT_HR(hr, S_OK); 3388 3389 pos.QuadPart = 0; 3390 pos2.QuadPart = 1; 3391 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3392 EXPECT_HR(hr, S_OK); 3393 ok(pos2.QuadPart == 0, "expected stream beginning\n"); 3394 3395 hr = ISAXContentHandler_endDocument(content); 3396 EXPECT_HR(hr, S_OK); 3397 3398 /* test auto-flush function when stream is not set */ 3399 V_VT(&dest) = VT_EMPTY; 3400 hr = IMXWriter_put_output(writer, dest); 3401 EXPECT_HR(hr, S_OK); 3402 3403 hr = ISAXContentHandler_startDocument(content); 3404 EXPECT_HR(hr, S_OK); 3405 3406 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL); 3407 EXPECT_HR(hr, S_OK); 3408 3409 memset(buff, 'A', len); 3410 buff[len] = 0; 3411 hr = ISAXContentHandler_characters(content, _bstr_(buff), len); 3412 EXPECT_HR(hr, S_OK); 3413 3414 V_VT(&dest) = VT_EMPTY; 3415 hr = IMXWriter_get_output(writer, &dest); 3416 EXPECT_HR(hr, S_OK); 3417 len += strlen("<a>"); 3418 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len); 3419 VariantClear(&dest); 3420 3421 heap_free(buff); 3422 ISAXContentHandler_Release(content); 3423 IStream_Release(stream); 3424 IMXWriter_Release(writer); 3425 free_bstrs(); 3426 } 3427 3428 static void test_mxwriter_startenddocument(void) 3429 { 3430 ISAXContentHandler *content; 3431 IMXWriter *writer; 3432 VARIANT dest; 3433 HRESULT hr; 3434 3435 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3436 &IID_IMXWriter, (void**)&writer); 3437 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3438 3439 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3440 ok(hr == S_OK, "got %08x\n", hr); 3441 3442 hr = ISAXContentHandler_startDocument(content); 3443 ok(hr == S_OK, "got %08x\n", hr); 3444 3445 hr = ISAXContentHandler_endDocument(content); 3446 ok(hr == S_OK, "got %08x\n", hr); 3447 3448 V_VT(&dest) = VT_EMPTY; 3449 hr = IMXWriter_get_output(writer, &dest); 3450 ok(hr == S_OK, "got %08x\n", hr); 3451 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3452 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)), 3453 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3454 VariantClear(&dest); 3455 3456 /* now try another startDocument */ 3457 hr = ISAXContentHandler_startDocument(content); 3458 ok(hr == S_OK, "got %08x\n", hr); 3459 /* and get duplicated prolog */ 3460 V_VT(&dest) = VT_EMPTY; 3461 hr = IMXWriter_get_output(writer, &dest); 3462 ok(hr == S_OK, "got %08x\n", hr); 3463 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3464 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n" 3465 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)), 3466 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3467 VariantClear(&dest); 3468 3469 ISAXContentHandler_Release(content); 3470 IMXWriter_Release(writer); 3471 3472 /* now with omitted declaration */ 3473 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3474 &IID_IMXWriter, (void**)&writer); 3475 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3476 3477 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3478 ok(hr == S_OK, "got %08x\n", hr); 3479 3480 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3481 ok(hr == S_OK, "got %08x\n", hr); 3482 3483 hr = ISAXContentHandler_startDocument(content); 3484 ok(hr == S_OK, "got %08x\n", hr); 3485 3486 hr = ISAXContentHandler_endDocument(content); 3487 ok(hr == S_OK, "got %08x\n", hr); 3488 3489 V_VT(&dest) = VT_EMPTY; 3490 hr = IMXWriter_get_output(writer, &dest); 3491 ok(hr == S_OK, "got %08x\n", hr); 3492 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3493 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3494 VariantClear(&dest); 3495 3496 ISAXContentHandler_Release(content); 3497 IMXWriter_Release(writer); 3498 3499 free_bstrs(); 3500 } 3501 3502 enum startendtype 3503 { 3504 StartElement = 0x001, 3505 EndElement = 0x010, 3506 StartEndElement = 0x011, 3507 DisableEscaping = 0x100 3508 }; 3509 3510 struct writer_startendelement_t { 3511 const GUID *clsid; 3512 enum startendtype type; 3513 const char *uri; 3514 const char *local_name; 3515 const char *qname; 3516 const char *output; 3517 HRESULT hr; 3518 ISAXAttributes *attr; 3519 }; 3520 3521 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\'\">"; 3522 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\'\"/>"; 3523 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\'\"/>"; 3524 3525 static const struct writer_startendelement_t writer_startendelement[] = { 3526 /* 0 */ 3527 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3528 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3529 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3530 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK }, 3531 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3532 /* 5 */ 3533 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3534 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3535 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK }, 3536 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3537 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3538 /* 10 */ 3539 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3540 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK }, 3541 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3542 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3543 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3544 /* 15 */ 3545 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK }, 3546 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK }, 3547 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK }, 3548 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK }, 3549 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK }, 3550 /* 20 */ 3551 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3552 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3553 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3554 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK }, 3555 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK }, 3556 /* 25 */ 3557 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK }, 3558 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK }, 3559 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK }, 3560 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK }, 3561 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK }, 3562 /* 30 */ 3563 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK }, 3564 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK }, 3565 /* endElement tests */ 3566 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3567 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3568 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3569 /* 35 */ 3570 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK }, 3571 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3572 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3573 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3574 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK }, 3575 /* 40 */ 3576 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3577 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3578 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3579 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK }, 3580 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3581 /* 45 */ 3582 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3583 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3584 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK }, 3585 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK }, 3586 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK }, 3587 /* 50 */ 3588 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK }, 3589 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK }, 3590 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3591 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3592 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3593 /* 55 */ 3594 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK }, 3595 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK }, 3596 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK }, 3597 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK }, 3598 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK }, 3599 /* 60 */ 3600 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK }, 3601 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK }, 3602 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK }, 3603 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK }, 3604 3605 /* with attributes */ 3606 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes }, 3607 /* 65 */ 3608 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes }, 3609 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes }, 3610 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes }, 3611 /* empty elements */ 3612 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3613 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3614 /* 70 */ 3615 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3616 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3617 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK }, 3618 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK }, 3619 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK }, 3620 /* 75 */ 3621 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK }, 3622 3623 /* with disabled output escaping */ 3624 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes }, 3625 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes }, 3626 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3627 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3628 3629 { NULL } 3630 }; 3631 3632 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid) 3633 { 3634 while (table->clsid) 3635 { 3636 IUnknown *unk; 3637 HRESULT hr; 3638 3639 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk); 3640 if (hr == S_OK) IUnknown_Release(unk); 3641 3642 table->supported = hr == S_OK; 3643 if (hr != S_OK) win_skip("class %s not supported\n", table->name); 3644 3645 table++; 3646 } 3647 } 3648 3649 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table) 3650 { 3651 int i = 0; 3652 3653 while (table->clsid) 3654 { 3655 ISAXContentHandler *content; 3656 IMXWriter *writer; 3657 HRESULT hr; 3658 3659 if (!is_clsid_supported(table->clsid, mxwriter_support_data)) 3660 { 3661 table++; 3662 i++; 3663 continue; 3664 } 3665 3666 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 3667 &IID_IMXWriter, (void**)&writer); 3668 EXPECT_HR(hr, S_OK); 3669 3670 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3671 EXPECT_HR(hr, S_OK); 3672 3673 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3674 EXPECT_HR(hr, S_OK); 3675 3676 hr = ISAXContentHandler_startDocument(content); 3677 EXPECT_HR(hr, S_OK); 3678 3679 if (table->type & DisableEscaping) 3680 { 3681 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE); 3682 EXPECT_HR(hr, S_OK); 3683 } 3684 3685 if (table->type & StartElement) 3686 { 3687 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0, 3688 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname), 3689 table->qname ? strlen(table->qname) : 0, table->attr); 3690 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr); 3691 } 3692 3693 if (table->type & EndElement) 3694 { 3695 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0, 3696 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname), 3697 table->qname ? strlen(table->qname) : 0); 3698 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr); 3699 } 3700 3701 /* test output */ 3702 if (hr == S_OK) 3703 { 3704 VARIANT dest; 3705 3706 V_VT(&dest) = VT_EMPTY; 3707 hr = IMXWriter_get_output(writer, &dest); 3708 EXPECT_HR(hr, S_OK); 3709 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3710 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)), 3711 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output); 3712 VariantClear(&dest); 3713 } 3714 3715 ISAXContentHandler_Release(content); 3716 IMXWriter_Release(writer); 3717 3718 table++; 3719 i++; 3720 } 3721 3722 free_bstrs(); 3723 } 3724 3725 /* point of these test is to start/end element with different names and name lengths */ 3726 struct writer_startendelement2_t { 3727 const GUID *clsid; 3728 const char *qnamestart; 3729 int qnamestart_len; 3730 const char *qnameend; 3731 int qnameend_len; 3732 const char *output; 3733 HRESULT hr; 3734 }; 3735 3736 static const struct writer_startendelement2_t writer_startendelement2[] = { 3737 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK }, 3738 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK }, 3739 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK }, 3740 /* -1 length is not allowed for version 6 */ 3741 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG }, 3742 3743 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK }, 3744 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK }, 3745 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK }, 3746 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK }, 3747 { NULL } 3748 }; 3749 3750 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table) 3751 { 3752 int i = 0; 3753 3754 while (table->clsid) 3755 { 3756 ISAXContentHandler *content; 3757 IMXWriter *writer; 3758 HRESULT hr; 3759 3760 if (!is_clsid_supported(table->clsid, mxwriter_support_data)) 3761 { 3762 table++; 3763 i++; 3764 continue; 3765 } 3766 3767 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 3768 &IID_IMXWriter, (void**)&writer); 3769 EXPECT_HR(hr, S_OK); 3770 3771 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3772 EXPECT_HR(hr, S_OK); 3773 3774 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3775 EXPECT_HR(hr, S_OK); 3776 3777 hr = ISAXContentHandler_startDocument(content); 3778 EXPECT_HR(hr, S_OK); 3779 3780 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, 3781 _bstr_(table->qnamestart), table->qnamestart_len, NULL); 3782 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr); 3783 3784 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, 3785 _bstr_(table->qnameend), table->qnameend_len); 3786 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr); 3787 3788 /* test output */ 3789 if (hr == S_OK) 3790 { 3791 VARIANT dest; 3792 3793 V_VT(&dest) = VT_EMPTY; 3794 hr = IMXWriter_get_output(writer, &dest); 3795 EXPECT_HR(hr, S_OK); 3796 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3797 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)), 3798 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output); 3799 VariantClear(&dest); 3800 } 3801 3802 ISAXContentHandler_Release(content); 3803 IMXWriter_Release(writer); 3804 3805 table++; 3806 i++; 3807 3808 free_bstrs(); 3809 } 3810 } 3811 3812 3813 static void test_mxwriter_startendelement(void) 3814 { 3815 ISAXContentHandler *content; 3816 IMXWriter *writer; 3817 VARIANT dest; 3818 HRESULT hr; 3819 3820 test_mxwriter_startendelement_batch(writer_startendelement); 3821 test_mxwriter_startendelement_batch2(writer_startendelement2); 3822 3823 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3824 &IID_IMXWriter, (void**)&writer); 3825 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3826 3827 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3828 ok(hr == S_OK, "got %08x\n", hr); 3829 3830 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3831 ok(hr == S_OK, "got %08x\n", hr); 3832 3833 hr = ISAXContentHandler_startDocument(content); 3834 ok(hr == S_OK, "got %08x\n", hr); 3835 3836 /* all string pointers should be not null */ 3837 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL); 3838 ok(hr == S_OK, "got %08x\n", hr); 3839 3840 V_VT(&dest) = VT_EMPTY; 3841 hr = IMXWriter_get_output(writer, &dest); 3842 ok(hr == S_OK, "got %08x\n", hr); 3843 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3844 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3845 VariantClear(&dest); 3846 3847 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL); 3848 ok(hr == S_OK, "got %08x\n", hr); 3849 3850 V_VT(&dest) = VT_EMPTY; 3851 hr = IMXWriter_get_output(writer, &dest); 3852 ok(hr == S_OK, "got %08x\n", hr); 3853 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3854 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3855 VariantClear(&dest); 3856 3857 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3); 3858 EXPECT_HR(hr, E_INVALIDARG); 3859 3860 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3); 3861 EXPECT_HR(hr, E_INVALIDARG); 3862 3863 /* only local name is an error too */ 3864 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0); 3865 EXPECT_HR(hr, E_INVALIDARG); 3866 3867 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1); 3868 EXPECT_HR(hr, S_OK); 3869 3870 V_VT(&dest) = VT_EMPTY; 3871 hr = IMXWriter_get_output(writer, &dest); 3872 EXPECT_HR(hr, S_OK); 3873 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3874 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3875 VariantClear(&dest); 3876 3877 hr = ISAXContentHandler_endDocument(content); 3878 EXPECT_HR(hr, S_OK); 3879 3880 V_VT(&dest) = VT_EMPTY; 3881 hr = IMXWriter_put_output(writer, dest); 3882 EXPECT_HR(hr, S_OK); 3883 3884 V_VT(&dest) = VT_EMPTY; 3885 hr = IMXWriter_get_output(writer, &dest); 3886 EXPECT_HR(hr, S_OK); 3887 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3888 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3889 VariantClear(&dest); 3890 3891 hr = ISAXContentHandler_startDocument(content); 3892 EXPECT_HR(hr, S_OK); 3893 3894 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL); 3895 EXPECT_HR(hr, S_OK); 3896 3897 V_VT(&dest) = VT_EMPTY; 3898 hr = IMXWriter_get_output(writer, &dest); 3899 EXPECT_HR(hr, S_OK); 3900 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3901 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3902 VariantClear(&dest); 3903 3904 hr = ISAXContentHandler_endDocument(content); 3905 EXPECT_HR(hr, S_OK); 3906 IMXWriter_flush(writer); 3907 3908 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3); 3909 EXPECT_HR(hr, S_OK); 3910 V_VT(&dest) = VT_EMPTY; 3911 hr = IMXWriter_get_output(writer, &dest); 3912 EXPECT_HR(hr, S_OK); 3913 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3914 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3915 VariantClear(&dest); 3916 3917 V_VT(&dest) = VT_EMPTY; 3918 hr = IMXWriter_put_output(writer, dest); 3919 EXPECT_HR(hr, S_OK); 3920 3921 /* length -1 */ 3922 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL); 3923 EXPECT_HR(hr, S_OK); 3924 V_VT(&dest) = VT_EMPTY; 3925 hr = IMXWriter_get_output(writer, &dest); 3926 EXPECT_HR(hr, S_OK); 3927 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3928 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3929 VariantClear(&dest); 3930 3931 ISAXContentHandler_Release(content); 3932 IMXWriter_Release(writer); 3933 free_bstrs(); 3934 } 3935 3936 struct writer_characters_t { 3937 const GUID *clsid; 3938 const char *data; 3939 const char *output; 3940 }; 3941 3942 static const struct writer_characters_t writer_characters[] = { 3943 { &CLSID_MXXMLWriter, "< > & \" \'", "< > & \" \'" }, 3944 { &CLSID_MXXMLWriter30, "< > & \" \'", "< > & \" \'" }, 3945 { &CLSID_MXXMLWriter40, "< > & \" \'", "< > & \" \'" }, 3946 { &CLSID_MXXMLWriter60, "< > & \" \'", "< > & \" \'" }, 3947 { NULL } 3948 }; 3949 3950 static void test_mxwriter_characters(void) 3951 { 3952 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0}; 3953 const struct writer_characters_t *table = writer_characters; 3954 ISAXContentHandler *content; 3955 IMXWriter *writer; 3956 VARIANT dest; 3957 HRESULT hr; 3958 int i = 0; 3959 3960 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3961 &IID_IMXWriter, (void**)&writer); 3962 EXPECT_HR(hr, S_OK); 3963 3964 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3965 EXPECT_HR(hr, S_OK); 3966 3967 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3968 EXPECT_HR(hr, S_OK); 3969 3970 hr = ISAXContentHandler_startDocument(content); 3971 EXPECT_HR(hr, S_OK); 3972 3973 hr = ISAXContentHandler_characters(content, NULL, 0); 3974 EXPECT_HR(hr, E_INVALIDARG); 3975 3976 hr = ISAXContentHandler_characters(content, chardataW, 0); 3977 EXPECT_HR(hr, S_OK); 3978 3979 hr = ISAXContentHandler_characters(content, chardataW, ARRAY_SIZE(chardataW) - 1); 3980 EXPECT_HR(hr, S_OK); 3981 3982 V_VT(&dest) = VT_EMPTY; 3983 hr = IMXWriter_get_output(writer, &dest); 3984 EXPECT_HR(hr, S_OK); 3985 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3986 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3987 VariantClear(&dest); 3988 3989 hr = ISAXContentHandler_endDocument(content); 3990 EXPECT_HR(hr, S_OK); 3991 3992 ISAXContentHandler_Release(content); 3993 IMXWriter_Release(writer); 3994 3995 /* try empty characters data to see if element is closed */ 3996 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3997 &IID_IMXWriter, (void**)&writer); 3998 EXPECT_HR(hr, S_OK); 3999 4000 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4001 EXPECT_HR(hr, S_OK); 4002 4003 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4004 EXPECT_HR(hr, S_OK); 4005 4006 hr = ISAXContentHandler_startDocument(content); 4007 EXPECT_HR(hr, S_OK); 4008 4009 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL); 4010 EXPECT_HR(hr, S_OK); 4011 4012 hr = ISAXContentHandler_characters(content, chardataW, 0); 4013 EXPECT_HR(hr, S_OK); 4014 4015 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1); 4016 EXPECT_HR(hr, S_OK); 4017 4018 V_VT(&dest) = VT_EMPTY; 4019 hr = IMXWriter_get_output(writer, &dest); 4020 EXPECT_HR(hr, S_OK); 4021 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4022 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4023 VariantClear(&dest); 4024 4025 ISAXContentHandler_Release(content); 4026 IMXWriter_Release(writer); 4027 4028 /* batch tests */ 4029 while (table->clsid) 4030 { 4031 ISAXContentHandler *content; 4032 IMXWriter *writer; 4033 VARIANT dest; 4034 HRESULT hr; 4035 4036 if (!is_clsid_supported(table->clsid, mxwriter_support_data)) 4037 { 4038 table++; 4039 i++; 4040 continue; 4041 } 4042 4043 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 4044 &IID_IMXWriter, (void**)&writer); 4045 EXPECT_HR(hr, S_OK); 4046 4047 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4048 EXPECT_HR(hr, S_OK); 4049 4050 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4051 EXPECT_HR(hr, S_OK); 4052 4053 hr = ISAXContentHandler_startDocument(content); 4054 EXPECT_HR(hr, S_OK); 4055 4056 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data)); 4057 EXPECT_HR(hr, S_OK); 4058 4059 /* test output */ 4060 if (hr == S_OK) 4061 { 4062 V_VT(&dest) = VT_EMPTY; 4063 hr = IMXWriter_get_output(writer, &dest); 4064 EXPECT_HR(hr, S_OK); 4065 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4066 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)), 4067 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output); 4068 VariantClear(&dest); 4069 } 4070 4071 /* with disabled escaping */ 4072 V_VT(&dest) = VT_EMPTY; 4073 hr = IMXWriter_put_output(writer, dest); 4074 EXPECT_HR(hr, S_OK); 4075 4076 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE); 4077 EXPECT_HR(hr, S_OK); 4078 4079 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data)); 4080 EXPECT_HR(hr, S_OK); 4081 4082 /* test output */ 4083 if (hr == S_OK) 4084 { 4085 V_VT(&dest) = VT_EMPTY; 4086 hr = IMXWriter_get_output(writer, &dest); 4087 EXPECT_HR(hr, S_OK); 4088 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4089 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)), 4090 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data); 4091 VariantClear(&dest); 4092 } 4093 4094 ISAXContentHandler_Release(content); 4095 IMXWriter_Release(writer); 4096 4097 table++; 4098 i++; 4099 } 4100 4101 free_bstrs(); 4102 } 4103 4104 static const mxwriter_stream_test mxwriter_stream_tests[] = { 4105 { 4106 VARIANT_TRUE,"UTF-16", 4107 { 4108 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE}, 4109 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)}, 4110 {TRUE} 4111 } 4112 }, 4113 { 4114 VARIANT_FALSE,"UTF-16", 4115 { 4116 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)}, 4117 {TRUE} 4118 } 4119 }, 4120 { 4121 VARIANT_TRUE,"UTF-8", 4122 { 4123 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1}, 4124 /* For some reason Windows makes an empty write call when UTF-8 encoding is used 4125 * and the writer is released. 4126 */ 4127 {FALSE,NULL,0}, 4128 {TRUE} 4129 } 4130 }, 4131 { 4132 VARIANT_TRUE,"utf-8", 4133 { 4134 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1}, 4135 /* For some reason Windows makes an empty write call when UTF-8 encoding is used 4136 * and the writer is released. 4137 */ 4138 {FALSE,NULL,0}, 4139 {TRUE} 4140 } 4141 }, 4142 { 4143 VARIANT_TRUE,"UTF-16", 4144 { 4145 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE}, 4146 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)}, 4147 {TRUE} 4148 } 4149 }, 4150 { 4151 VARIANT_TRUE,"UTF-16", 4152 { 4153 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE}, 4154 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)}, 4155 {TRUE} 4156 } 4157 } 4158 }; 4159 4160 static void test_mxwriter_stream(void) 4161 { 4162 IMXWriter *writer; 4163 ISAXContentHandler *content; 4164 HRESULT hr; 4165 VARIANT dest; 4166 IStream *stream; 4167 LARGE_INTEGER pos; 4168 ULARGE_INTEGER pos2; 4169 DWORD test_count = ARRAY_SIZE(mxwriter_stream_tests); 4170 4171 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) { 4172 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index; 4173 4174 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4175 &IID_IMXWriter, (void**)&writer); 4176 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr); 4177 4178 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4179 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr); 4180 4181 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding)); 4182 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index); 4183 4184 V_VT(&dest) = VT_UNKNOWN; 4185 V_UNKNOWN(&dest) = (IUnknown*)&mxstream; 4186 hr = IMXWriter_put_output(writer, dest); 4187 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index); 4188 4189 hr = IMXWriter_put_byteOrderMark(writer, test->bom); 4190 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index); 4191 4192 current_write_test = test->expected_writes; 4193 4194 hr = ISAXContentHandler_startDocument(content); 4195 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index); 4196 4197 hr = ISAXContentHandler_endDocument(content); 4198 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index); 4199 4200 ISAXContentHandler_Release(content); 4201 IMXWriter_Release(writer); 4202 4203 ok(current_write_test->last, "The last %d write calls on test %d were missed\n", 4204 (int)(current_write_test-test->expected_writes), current_stream_test_index); 4205 } 4206 4207 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4208 &IID_IMXWriter, (void**)&writer); 4209 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr); 4210 4211 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 4212 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr); 4213 4214 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4215 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr); 4216 4217 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8")); 4218 ok(hr == S_OK, "put_encoding failed: %08x\n", hr); 4219 4220 V_VT(&dest) = VT_UNKNOWN; 4221 V_UNKNOWN(&dest) = (IUnknown*)stream; 4222 hr = IMXWriter_put_output(writer, dest); 4223 ok(hr == S_OK, "put_output failed: %08x\n", hr); 4224 4225 hr = ISAXContentHandler_startDocument(content); 4226 ok(hr == S_OK, "startDocument failed: %08x\n", hr); 4227 4228 /* Setting output of the mxwriter causes the current output to be flushed, 4229 * and the writer to start over. 4230 */ 4231 V_VT(&dest) = VT_EMPTY; 4232 hr = IMXWriter_put_output(writer, dest); 4233 ok(hr == S_OK, "put_output failed: %08x\n", hr); 4234 4235 pos.QuadPart = 0; 4236 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 4237 ok(hr == S_OK, "Seek failed: %08x\n", hr); 4238 ok(pos2.QuadPart != 0, "expected stream position moved\n"); 4239 4240 hr = ISAXContentHandler_startDocument(content); 4241 ok(hr == S_OK, "startDocument failed: %08x\n", hr); 4242 4243 hr = ISAXContentHandler_endDocument(content); 4244 ok(hr == S_OK, "endDocument failed: %08x\n", hr); 4245 4246 V_VT(&dest) = VT_EMPTY; 4247 hr = IMXWriter_get_output(writer, &dest); 4248 ok(hr == S_OK, "get_output failed: %08x\n", hr); 4249 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest)); 4250 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)), 4251 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4252 VariantClear(&dest); 4253 4254 /* test when BOM is written to output stream */ 4255 V_VT(&dest) = VT_EMPTY; 4256 hr = IMXWriter_put_output(writer, dest); 4257 EXPECT_HR(hr, S_OK); 4258 4259 pos.QuadPart = 0; 4260 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL); 4261 EXPECT_HR(hr, S_OK); 4262 4263 V_VT(&dest) = VT_UNKNOWN; 4264 V_UNKNOWN(&dest) = (IUnknown*)stream; 4265 hr = IMXWriter_put_output(writer, dest); 4266 EXPECT_HR(hr, S_OK); 4267 4268 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE); 4269 EXPECT_HR(hr, S_OK); 4270 4271 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16")); 4272 EXPECT_HR(hr, S_OK); 4273 4274 hr = ISAXContentHandler_startDocument(content); 4275 EXPECT_HR(hr, S_OK); 4276 4277 pos.QuadPart = 0; 4278 pos2.QuadPart = 0; 4279 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 4280 EXPECT_HR(hr, S_OK); 4281 ok(pos2.QuadPart == 2, "got wrong position\n"); 4282 4283 IStream_Release(stream); 4284 ISAXContentHandler_Release(content); 4285 IMXWriter_Release(writer); 4286 4287 free_bstrs(); 4288 } 4289 4290 static const char *encoding_names[] = { 4291 "iso-8859-1", 4292 "iso-8859-2", 4293 "iso-8859-3", 4294 "iso-8859-4", 4295 "iso-8859-5", 4296 "iso-8859-7", 4297 "iso-8859-9", 4298 "iso-8859-13", 4299 "iso-8859-15", 4300 NULL 4301 }; 4302 4303 static void test_mxwriter_encoding(void) 4304 { 4305 ISAXContentHandler *content; 4306 IMXWriter *writer; 4307 IStream *stream; 4308 const char *enc; 4309 VARIANT dest; 4310 HRESULT hr; 4311 HGLOBAL g; 4312 char *ptr; 4313 BSTR s; 4314 int i; 4315 4316 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4317 &IID_IMXWriter, (void**)&writer); 4318 EXPECT_HR(hr, S_OK); 4319 4320 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4321 EXPECT_HR(hr, S_OK); 4322 4323 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8")); 4324 EXPECT_HR(hr, S_OK); 4325 4326 hr = ISAXContentHandler_startDocument(content); 4327 EXPECT_HR(hr, S_OK); 4328 4329 hr = ISAXContentHandler_endDocument(content); 4330 EXPECT_HR(hr, S_OK); 4331 4332 /* The content is always re-encoded to UTF-16 when the output is 4333 * retrieved as a BSTR. 4334 */ 4335 V_VT(&dest) = VT_EMPTY; 4336 hr = IMXWriter_get_output(writer, &dest); 4337 EXPECT_HR(hr, S_OK); 4338 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest)); 4339 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)), 4340 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4341 VariantClear(&dest); 4342 4343 /* switch encoding when something is written already */ 4344 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 4345 EXPECT_HR(hr, S_OK); 4346 4347 V_VT(&dest) = VT_UNKNOWN; 4348 V_UNKNOWN(&dest) = (IUnknown*)stream; 4349 hr = IMXWriter_put_output(writer, dest); 4350 EXPECT_HR(hr, S_OK); 4351 4352 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8")); 4353 EXPECT_HR(hr, S_OK); 4354 4355 /* write empty element */ 4356 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL); 4357 EXPECT_HR(hr, S_OK); 4358 4359 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1); 4360 EXPECT_HR(hr, S_OK); 4361 4362 /* switch */ 4363 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16")); 4364 EXPECT_HR(hr, S_OK); 4365 4366 hr = IMXWriter_flush(writer); 4367 EXPECT_HR(hr, S_OK); 4368 4369 hr = GetHGlobalFromStream(stream, &g); 4370 EXPECT_HR(hr, S_OK); 4371 4372 ptr = GlobalLock(g); 4373 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]); 4374 GlobalUnlock(g); 4375 4376 /* so output is unaffected, encoding name is stored however */ 4377 hr = IMXWriter_get_encoding(writer, &s); 4378 EXPECT_HR(hr, S_OK); 4379 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s)); 4380 SysFreeString(s); 4381 4382 IStream_Release(stream); 4383 4384 i = 0; 4385 enc = encoding_names[i]; 4386 while (enc) 4387 { 4388 char expectedA[200]; 4389 4390 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 4391 EXPECT_HR(hr, S_OK); 4392 4393 V_VT(&dest) = VT_UNKNOWN; 4394 V_UNKNOWN(&dest) = (IUnknown*)stream; 4395 hr = IMXWriter_put_output(writer, dest); 4396 EXPECT_HR(hr, S_OK); 4397 4398 hr = IMXWriter_put_encoding(writer, _bstr_(enc)); 4399 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */, 4400 "%s: encoding not accepted\n", enc); 4401 if (hr != S_OK) 4402 { 4403 enc = encoding_names[++i]; 4404 IStream_Release(stream); 4405 continue; 4406 } 4407 4408 hr = ISAXContentHandler_startDocument(content); 4409 EXPECT_HR(hr, S_OK); 4410 4411 hr = ISAXContentHandler_endDocument(content); 4412 EXPECT_HR(hr, S_OK); 4413 4414 hr = IMXWriter_flush(writer); 4415 EXPECT_HR(hr, S_OK); 4416 4417 /* prepare expected string */ 4418 *expectedA = 0; 4419 strcat(expectedA, "<?xml version=\"1.0\" encoding=\""); 4420 strcat(expectedA, enc); 4421 strcat(expectedA, "\" standalone=\"no\"?>\r\n"); 4422 4423 hr = GetHGlobalFromStream(stream, &g); 4424 EXPECT_HR(hr, S_OK); 4425 4426 ptr = GlobalLock(g); 4427 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA); 4428 GlobalUnlock(g); 4429 4430 V_VT(&dest) = VT_EMPTY; 4431 hr = IMXWriter_put_output(writer, dest); 4432 EXPECT_HR(hr, S_OK); 4433 4434 IStream_Release(stream); 4435 4436 enc = encoding_names[++i]; 4437 } 4438 4439 ISAXContentHandler_Release(content); 4440 IMXWriter_Release(writer); 4441 4442 free_bstrs(); 4443 } 4444 4445 static void test_obj_dispex(IUnknown *obj) 4446 { 4447 static const WCHAR testW[] = {'t','e','s','t','p','r','o','p',0}; 4448 static const WCHAR starW[] = {'*',0}; 4449 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE; 4450 IDispatchEx *dispex; 4451 IUnknown *unk; 4452 DWORD props; 4453 UINT ticnt; 4454 HRESULT hr; 4455 BSTR name; 4456 DISPID did; 4457 4458 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex); 4459 EXPECT_HR(hr, S_OK); 4460 if (FAILED(hr)) return; 4461 4462 ticnt = 0; 4463 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt); 4464 EXPECT_HR(hr, S_OK); 4465 ok(ticnt == 1, "ticnt=%u\n", ticnt); 4466 4467 name = SysAllocString(starW); 4468 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive); 4469 EXPECT_HR(hr, E_NOTIMPL); 4470 SysFreeString(name); 4471 4472 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid); 4473 EXPECT_HR(hr, E_NOTIMPL); 4474 4475 props = 0; 4476 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props); 4477 EXPECT_HR(hr, E_NOTIMPL); 4478 ok(props == 0, "expected 0 got %d\n", props); 4479 4480 hr = IDispatchEx_GetMemberName(dispex, dispid, &name); 4481 EXPECT_HR(hr, E_NOTIMPL); 4482 if (SUCCEEDED(hr)) SysFreeString(name); 4483 4484 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid); 4485 EXPECT_HR(hr, E_NOTIMPL); 4486 4487 unk = (IUnknown*)0xdeadbeef; 4488 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk); 4489 EXPECT_HR(hr, E_NOTIMPL); 4490 ok(unk == (IUnknown*)0xdeadbeef, "got %p\n", unk); 4491 4492 name = SysAllocString(testW); 4493 hr = IDispatchEx_GetDispID(dispex, name, fdexNameEnsure, &did); 4494 ok(hr == DISP_E_UNKNOWNNAME, "got 0x%08x\n", hr); 4495 SysFreeString(name); 4496 4497 IDispatchEx_Release(dispex); 4498 } 4499 4500 static void test_saxreader_dispex(void) 4501 { 4502 IVBSAXXMLReader *vbreader; 4503 ISAXXMLReader *reader; 4504 DISPPARAMS dispparams; 4505 DISPID dispid; 4506 IUnknown *unk; 4507 VARIANT arg; 4508 HRESULT hr; 4509 4510 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER, 4511 &IID_ISAXXMLReader, (void**)&reader); 4512 EXPECT_HR(hr, S_OK); 4513 4514 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk); 4515 EXPECT_HR(hr, S_OK); 4516 test_obj_dispex(unk); 4517 IUnknown_Release(unk); 4518 4519 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader); 4520 EXPECT_HR(hr, S_OK); 4521 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk); 4522 EXPECT_HR(hr, S_OK); 4523 test_obj_dispex(unk); 4524 IUnknown_Release(unk); 4525 4526 dispid = DISPID_PROPERTYPUT; 4527 dispparams.cArgs = 1; 4528 dispparams.cNamedArgs = 1; 4529 dispparams.rgdispidNamedArgs = &dispid; 4530 dispparams.rgvarg = &arg; 4531 4532 V_VT(&arg) = VT_DISPATCH; 4533 V_DISPATCH(&arg) = NULL; 4534 4535 /* propputref is callable as PROPERTYPUT and PROPERTYPUTREF */ 4536 hr = IVBSAXXMLReader_Invoke(vbreader, 4537 DISPID_SAX_XMLREADER_CONTENTHANDLER, 4538 &IID_NULL, 4539 0, 4540 DISPATCH_PROPERTYPUT, 4541 &dispparams, 4542 NULL, 4543 NULL, 4544 NULL); 4545 ok(hr == S_OK, "got 0x%08x\n", hr); 4546 4547 hr = IVBSAXXMLReader_Invoke(vbreader, 4548 DISPID_SAX_XMLREADER_CONTENTHANDLER, 4549 &IID_NULL, 4550 0, 4551 DISPATCH_PROPERTYPUTREF, 4552 &dispparams, 4553 NULL, 4554 NULL, 4555 NULL); 4556 ok(hr == S_OK, "got 0x%08x\n", hr); 4557 4558 IVBSAXXMLReader_Release(vbreader); 4559 ISAXXMLReader_Release(reader); 4560 4561 if (is_clsid_supported(&CLSID_SAXXMLReader60, reader_support_data)) 4562 { 4563 hr = CoCreateInstance(&CLSID_SAXXMLReader60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); 4564 ok(hr == S_OK, "got 0x%08x\n", hr); 4565 test_obj_dispex(unk); 4566 IUnknown_Release(unk); 4567 } 4568 } 4569 4570 static void test_mxwriter_dispex(void) 4571 { 4572 IDispatchEx *dispex; 4573 IMXWriter *writer; 4574 IUnknown *unk; 4575 HRESULT hr; 4576 4577 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4578 &IID_IMXWriter, (void**)&writer); 4579 EXPECT_HR(hr, S_OK); 4580 4581 hr = IMXWriter_QueryInterface(writer, &IID_IDispatchEx, (void**)&dispex); 4582 EXPECT_HR(hr, S_OK); 4583 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk); 4584 test_obj_dispex(unk); 4585 IUnknown_Release(unk); 4586 IDispatchEx_Release(dispex); 4587 IMXWriter_Release(writer); 4588 4589 if (is_clsid_supported(&CLSID_MXXMLWriter60, mxwriter_support_data)) 4590 { 4591 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); 4592 ok(hr == S_OK, "got 0x%08x\n", hr); 4593 test_obj_dispex(unk); 4594 IUnknown_Release(unk); 4595 } 4596 } 4597 4598 static void test_mxwriter_comment(void) 4599 { 4600 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0}; 4601 IVBSAXLexicalHandler *vblexical; 4602 ISAXContentHandler *content; 4603 ISAXLexicalHandler *lexical; 4604 IMXWriter *writer; 4605 VARIANT dest; 4606 HRESULT hr; 4607 4608 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4609 &IID_IMXWriter, (void**)&writer); 4610 EXPECT_HR(hr, S_OK); 4611 4612 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4613 EXPECT_HR(hr, S_OK); 4614 4615 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical); 4616 EXPECT_HR(hr, S_OK); 4617 4618 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical); 4619 EXPECT_HR(hr, S_OK); 4620 4621 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4622 EXPECT_HR(hr, S_OK); 4623 4624 hr = ISAXContentHandler_startDocument(content); 4625 EXPECT_HR(hr, S_OK); 4626 4627 hr = ISAXLexicalHandler_comment(lexical, NULL, 0); 4628 EXPECT_HR(hr, E_INVALIDARG); 4629 4630 hr = IVBSAXLexicalHandler_comment(vblexical, NULL); 4631 EXPECT_HR(hr, E_POINTER); 4632 4633 hr = ISAXLexicalHandler_comment(lexical, commentW, 0); 4634 EXPECT_HR(hr, S_OK); 4635 4636 V_VT(&dest) = VT_EMPTY; 4637 hr = IMXWriter_get_output(writer, &dest); 4638 EXPECT_HR(hr, S_OK); 4639 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4640 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4641 VariantClear(&dest); 4642 4643 hr = ISAXLexicalHandler_comment(lexical, commentW, ARRAY_SIZE(commentW) - 1); 4644 EXPECT_HR(hr, S_OK); 4645 4646 V_VT(&dest) = VT_EMPTY; 4647 hr = IMXWriter_get_output(writer, &dest); 4648 EXPECT_HR(hr, S_OK); 4649 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4650 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4651 VariantClear(&dest); 4652 4653 ISAXContentHandler_Release(content); 4654 ISAXLexicalHandler_Release(lexical); 4655 IVBSAXLexicalHandler_Release(vblexical); 4656 IMXWriter_Release(writer); 4657 free_bstrs(); 4658 } 4659 4660 static void test_mxwriter_cdata(void) 4661 { 4662 IVBSAXLexicalHandler *vblexical; 4663 ISAXContentHandler *content; 4664 ISAXLexicalHandler *lexical; 4665 IMXWriter *writer; 4666 VARIANT dest; 4667 HRESULT hr; 4668 4669 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4670 &IID_IMXWriter, (void**)&writer); 4671 EXPECT_HR(hr, S_OK); 4672 4673 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4674 EXPECT_HR(hr, S_OK); 4675 4676 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical); 4677 EXPECT_HR(hr, S_OK); 4678 4679 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical); 4680 EXPECT_HR(hr, S_OK); 4681 4682 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4683 EXPECT_HR(hr, S_OK); 4684 4685 hr = ISAXContentHandler_startDocument(content); 4686 EXPECT_HR(hr, S_OK); 4687 4688 hr = ISAXLexicalHandler_startCDATA(lexical); 4689 EXPECT_HR(hr, S_OK); 4690 4691 V_VT(&dest) = VT_EMPTY; 4692 hr = IMXWriter_get_output(writer, &dest); 4693 EXPECT_HR(hr, S_OK); 4694 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4695 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4696 VariantClear(&dest); 4697 4698 hr = IVBSAXLexicalHandler_startCDATA(vblexical); 4699 EXPECT_HR(hr, S_OK); 4700 4701 /* all these are escaped for text nodes */ 4702 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7); 4703 EXPECT_HR(hr, S_OK); 4704 4705 hr = ISAXLexicalHandler_endCDATA(lexical); 4706 EXPECT_HR(hr, S_OK); 4707 4708 V_VT(&dest) = VT_EMPTY; 4709 hr = IMXWriter_get_output(writer, &dest); 4710 EXPECT_HR(hr, S_OK); 4711 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4712 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4713 VariantClear(&dest); 4714 4715 ISAXContentHandler_Release(content); 4716 ISAXLexicalHandler_Release(lexical); 4717 IVBSAXLexicalHandler_Release(vblexical); 4718 IMXWriter_Release(writer); 4719 free_bstrs(); 4720 } 4721 4722 static void test_mxwriter_pi(void) 4723 { 4724 static const WCHAR targetW[] = {'t','a','r','g','e','t',0}; 4725 static const WCHAR dataW[] = {'d','a','t','a',0}; 4726 ISAXContentHandler *content; 4727 IMXWriter *writer; 4728 VARIANT dest; 4729 HRESULT hr; 4730 4731 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4732 &IID_IMXWriter, (void**)&writer); 4733 EXPECT_HR(hr, S_OK); 4734 4735 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4736 EXPECT_HR(hr, S_OK); 4737 4738 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0); 4739 EXPECT_HR(hr, E_INVALIDARG); 4740 4741 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0); 4742 EXPECT_HR(hr, S_OK); 4743 4744 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0); 4745 EXPECT_HR(hr, S_OK); 4746 4747 V_VT(&dest) = VT_EMPTY; 4748 hr = IMXWriter_get_output(writer, &dest); 4749 EXPECT_HR(hr, S_OK); 4750 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4751 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4752 VariantClear(&dest); 4753 4754 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4); 4755 EXPECT_HR(hr, S_OK); 4756 4757 V_VT(&dest) = VT_EMPTY; 4758 hr = IMXWriter_get_output(writer, &dest); 4759 EXPECT_HR(hr, S_OK); 4760 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4761 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n<?targ data?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4762 VariantClear(&dest); 4763 4764 V_VT(&dest) = VT_EMPTY; 4765 hr = IMXWriter_put_output(writer, dest); 4766 EXPECT_HR(hr, S_OK); 4767 4768 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0); 4769 EXPECT_HR(hr, S_OK); 4770 4771 V_VT(&dest) = VT_EMPTY; 4772 hr = IMXWriter_get_output(writer, &dest); 4773 EXPECT_HR(hr, S_OK); 4774 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4775 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4776 VariantClear(&dest); 4777 4778 4779 ISAXContentHandler_Release(content); 4780 IMXWriter_Release(writer); 4781 } 4782 4783 static void test_mxwriter_ignorablespaces(void) 4784 { 4785 static const WCHAR dataW[] = {'d','a','t','a',0}; 4786 ISAXContentHandler *content; 4787 IMXWriter *writer; 4788 VARIANT dest; 4789 HRESULT hr; 4790 4791 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4792 &IID_IMXWriter, (void**)&writer); 4793 EXPECT_HR(hr, S_OK); 4794 4795 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4796 EXPECT_HR(hr, S_OK); 4797 4798 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0); 4799 EXPECT_HR(hr, E_INVALIDARG); 4800 4801 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0); 4802 EXPECT_HR(hr, S_OK); 4803 4804 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4); 4805 EXPECT_HR(hr, S_OK); 4806 4807 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1); 4808 EXPECT_HR(hr, S_OK); 4809 4810 V_VT(&dest) = VT_EMPTY; 4811 hr = IMXWriter_get_output(writer, &dest); 4812 EXPECT_HR(hr, S_OK); 4813 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4814 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4815 VariantClear(&dest); 4816 4817 ISAXContentHandler_Release(content); 4818 IMXWriter_Release(writer); 4819 } 4820 4821 static void test_mxwriter_dtd(void) 4822 { 4823 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'}; 4824 static const WCHAR nameW[] = {'n','a','m','e'}; 4825 static const WCHAR pubW[] = {'p','u','b'}; 4826 static const WCHAR sysW[] = {'s','y','s'}; 4827 IVBSAXLexicalHandler *vblexical; 4828 ISAXContentHandler *content; 4829 ISAXLexicalHandler *lexical; 4830 IVBSAXDeclHandler *vbdecl; 4831 ISAXDeclHandler *decl; 4832 ISAXDTDHandler *dtd; 4833 IMXWriter *writer; 4834 VARIANT dest; 4835 HRESULT hr; 4836 4837 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4838 &IID_IMXWriter, (void**)&writer); 4839 EXPECT_HR(hr, S_OK); 4840 4841 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4842 EXPECT_HR(hr, S_OK); 4843 4844 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical); 4845 EXPECT_HR(hr, S_OK); 4846 4847 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl); 4848 EXPECT_HR(hr, S_OK); 4849 4850 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXDeclHandler, (void**)&vbdecl); 4851 EXPECT_HR(hr, S_OK); 4852 4853 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical); 4854 EXPECT_HR(hr, S_OK); 4855 4856 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4857 EXPECT_HR(hr, S_OK); 4858 4859 hr = ISAXContentHandler_startDocument(content); 4860 EXPECT_HR(hr, S_OK); 4861 4862 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0); 4863 EXPECT_HR(hr, E_INVALIDARG); 4864 4865 hr = IVBSAXLexicalHandler_startDTD(vblexical, NULL, NULL, NULL); 4866 EXPECT_HR(hr, E_POINTER); 4867 4868 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, ARRAY_SIZE(pubW), NULL, 0); 4869 EXPECT_HR(hr, E_INVALIDARG); 4870 4871 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, ARRAY_SIZE(sysW)); 4872 EXPECT_HR(hr, E_INVALIDARG); 4873 4874 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, ARRAY_SIZE(pubW), sysW, ARRAY_SIZE(sysW)); 4875 EXPECT_HR(hr, E_INVALIDARG); 4876 4877 hr = ISAXLexicalHandler_startDTD(lexical, nameW, ARRAY_SIZE(nameW), NULL, 0, NULL, 0); 4878 EXPECT_HR(hr, S_OK); 4879 4880 V_VT(&dest) = VT_EMPTY; 4881 hr = IMXWriter_get_output(writer, &dest); 4882 EXPECT_HR(hr, S_OK); 4883 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4884 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4885 VariantClear(&dest); 4886 4887 /* system id is required if public is present */ 4888 hr = ISAXLexicalHandler_startDTD(lexical, nameW, ARRAY_SIZE(nameW), pubW, ARRAY_SIZE(pubW), NULL, 0); 4889 EXPECT_HR(hr, E_INVALIDARG); 4890 4891 hr = ISAXLexicalHandler_startDTD(lexical, nameW, ARRAY_SIZE(nameW), 4892 pubW, ARRAY_SIZE(pubW), sysW, ARRAY_SIZE(sysW)); 4893 EXPECT_HR(hr, S_OK); 4894 4895 V_VT(&dest) = VT_EMPTY; 4896 hr = IMXWriter_get_output(writer, &dest); 4897 EXPECT_HR(hr, S_OK); 4898 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4899 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\"" 4900 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4901 VariantClear(&dest); 4902 4903 hr = ISAXLexicalHandler_endDTD(lexical); 4904 EXPECT_HR(hr, S_OK); 4905 4906 hr = IVBSAXLexicalHandler_endDTD(vblexical); 4907 EXPECT_HR(hr, S_OK); 4908 4909 V_VT(&dest) = VT_EMPTY; 4910 hr = IMXWriter_get_output(writer, &dest); 4911 EXPECT_HR(hr, S_OK); 4912 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4913 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\"" 4914 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"), 4915 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4916 VariantClear(&dest); 4917 4918 /* element declaration */ 4919 V_VT(&dest) = VT_EMPTY; 4920 hr = IMXWriter_put_output(writer, dest); 4921 EXPECT_HR(hr, S_OK); 4922 4923 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0); 4924 EXPECT_HR(hr, E_INVALIDARG); 4925 4926 hr = IVBSAXDeclHandler_elementDecl(vbdecl, NULL, NULL); 4927 EXPECT_HR(hr, E_POINTER); 4928 4929 hr = ISAXDeclHandler_elementDecl(decl, nameW, ARRAY_SIZE(nameW), NULL, 0); 4930 EXPECT_HR(hr, E_INVALIDARG); 4931 4932 hr = ISAXDeclHandler_elementDecl(decl, nameW, ARRAY_SIZE(nameW), contentW, ARRAY_SIZE(contentW)); 4933 EXPECT_HR(hr, S_OK); 4934 4935 V_VT(&dest) = VT_EMPTY; 4936 hr = IMXWriter_get_output(writer, &dest); 4937 EXPECT_HR(hr, S_OK); 4938 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4939 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"), 4940 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4941 VariantClear(&dest); 4942 4943 V_VT(&dest) = VT_EMPTY; 4944 hr = IMXWriter_put_output(writer, dest); 4945 EXPECT_HR(hr, S_OK); 4946 4947 hr = ISAXDeclHandler_elementDecl(decl, nameW, ARRAY_SIZE(nameW), contentW, 0); 4948 EXPECT_HR(hr, S_OK); 4949 4950 V_VT(&dest) = VT_EMPTY; 4951 hr = IMXWriter_get_output(writer, &dest); 4952 EXPECT_HR(hr, S_OK); 4953 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4954 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"), 4955 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4956 VariantClear(&dest); 4957 4958 /* attribute declaration */ 4959 V_VT(&dest) = VT_EMPTY; 4960 hr = IMXWriter_put_output(writer, dest); 4961 EXPECT_HR(hr, S_OK); 4962 4963 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"), 4964 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"), 4965 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value")); 4966 EXPECT_HR(hr, S_OK); 4967 4968 V_VT(&dest) = VT_EMPTY; 4969 hr = IMXWriter_get_output(writer, &dest); 4970 EXPECT_HR(hr, S_OK); 4971 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4972 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"), 4973 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4974 VariantClear(&dest); 4975 4976 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"), 4977 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"), 4978 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2")); 4979 EXPECT_HR(hr, S_OK); 4980 4981 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"), 4982 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"), 4983 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3")); 4984 EXPECT_HR(hr, S_OK); 4985 4986 V_VT(&dest) = VT_EMPTY; 4987 hr = IMXWriter_get_output(writer, &dest); 4988 EXPECT_HR(hr, S_OK); 4989 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4990 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n" 4991 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n" 4992 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"), 4993 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4994 VariantClear(&dest); 4995 4996 /* internal entities */ 4997 V_VT(&dest) = VT_EMPTY; 4998 hr = IMXWriter_put_output(writer, dest); 4999 EXPECT_HR(hr, S_OK); 5000 5001 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0); 5002 EXPECT_HR(hr, E_INVALIDARG); 5003 5004 hr = IVBSAXDeclHandler_internalEntityDecl(vbdecl, NULL, NULL); 5005 EXPECT_HR(hr, E_POINTER); 5006 5007 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0); 5008 EXPECT_HR(hr, E_INVALIDARG); 5009 5010 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value")); 5011 EXPECT_HR(hr, S_OK); 5012 5013 V_VT(&dest) = VT_EMPTY; 5014 hr = IMXWriter_get_output(writer, &dest); 5015 EXPECT_HR(hr, S_OK); 5016 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5017 ok(!lstrcmpW(_bstr_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5018 VariantClear(&dest); 5019 5020 /* external entities */ 5021 V_VT(&dest) = VT_EMPTY; 5022 hr = IMXWriter_put_output(writer, dest); 5023 ok(hr == S_OK, "got 0x%08x\n", hr); 5024 5025 hr = ISAXDeclHandler_externalEntityDecl(decl, NULL, 0, NULL, 0, NULL, 0); 5026 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5027 5028 hr = IVBSAXDeclHandler_externalEntityDecl(vbdecl, NULL, NULL, NULL); 5029 ok(hr == E_POINTER, "got 0x%08x\n", hr); 5030 5031 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), 0, NULL, 0, NULL, 0); 5032 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5033 5034 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), -1, NULL, 0, NULL, 0); 5035 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5036 5037 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"), 5038 _bstr_("sysid"), strlen("sysid")); 5039 ok(hr == S_OK, "got 0x%08x\n", hr); 5040 5041 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), NULL, 0, _bstr_("sysid"), strlen("sysid")); 5042 ok(hr == S_OK, "got 0x%08x\n", hr); 5043 5044 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"), 5045 NULL, 0); 5046 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5047 5048 V_VT(&dest) = VT_EMPTY; 5049 hr = IMXWriter_get_output(writer, &dest); 5050 ok(hr == S_OK, "got 0x%08x\n", hr); 5051 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5052 ok(!lstrcmpW(_bstr_( 5053 "<!ENTITY name PUBLIC \"pubid\" \"sysid\">\r\n" 5054 "<!ENTITY name SYSTEM \"sysid\">\r\n"), 5055 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5056 5057 VariantClear(&dest); 5058 5059 /* notation declaration */ 5060 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDTDHandler, (void**)&dtd); 5061 ok(hr == S_OK, "got 0x%08x\n", hr); 5062 5063 V_VT(&dest) = VT_EMPTY; 5064 hr = IMXWriter_put_output(writer, dest); 5065 ok(hr == S_OK, "got 0x%08x\n", hr); 5066 5067 hr = ISAXDTDHandler_notationDecl(dtd, NULL, 0, NULL, 0, NULL, 0); 5068 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5069 5070 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), NULL, 0, NULL, 0); 5071 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5072 5073 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"), NULL, 0); 5074 ok(hr == S_OK, "got 0x%08x\n", hr); 5075 5076 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"), _bstr_("sysid"), strlen("sysid")); 5077 ok(hr == S_OK, "got 0x%08x\n", hr); 5078 5079 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), NULL, 0, _bstr_("sysid"), strlen("sysid")); 5080 ok(hr == S_OK, "got 0x%08x\n", hr); 5081 5082 hr = IMXWriter_get_output(writer, &dest); 5083 ok(hr == S_OK, "got 0x%08x\n", hr); 5084 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5085 ok(!lstrcmpW(_bstr_( 5086 "<!NOTATION name" 5087 "<!NOTATION name PUBLIC \"pubid\">\r\n" 5088 "<!NOTATION name PUBLIC \"pubid\" \"sysid\">\r\n" 5089 "<!NOTATION name SYSTEM \"sysid\">\r\n"), 5090 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5091 5092 VariantClear(&dest); 5093 5094 ISAXDTDHandler_Release(dtd); 5095 5096 ISAXContentHandler_Release(content); 5097 ISAXLexicalHandler_Release(lexical); 5098 IVBSAXLexicalHandler_Release(vblexical); 5099 IVBSAXDeclHandler_Release(vbdecl); 5100 ISAXDeclHandler_Release(decl); 5101 IMXWriter_Release(writer); 5102 free_bstrs(); 5103 } 5104 5105 typedef struct { 5106 const CLSID *clsid; 5107 const char *uri; 5108 const char *local; 5109 const char *qname; 5110 const char *type; 5111 const char *value; 5112 HRESULT hr; 5113 } addattribute_test_t; 5114 5115 static const addattribute_test_t addattribute_data[] = { 5116 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG }, 5117 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG }, 5118 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG }, 5119 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK }, 5120 5121 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5122 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5123 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5124 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK }, 5125 5126 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5127 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5128 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5129 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK }, 5130 5131 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK }, 5132 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK }, 5133 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK }, 5134 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK }, 5135 5136 { NULL } 5137 }; 5138 5139 static void test_mxattr_addAttribute(void) 5140 { 5141 const addattribute_test_t *table = addattribute_data; 5142 int i = 0; 5143 5144 while (table->clsid) 5145 { 5146 ISAXAttributes *saxattr; 5147 IMXAttributes *mxattr; 5148 const WCHAR *value; 5149 int len, index; 5150 HRESULT hr; 5151 5152 if (!is_clsid_supported(table->clsid, mxattributes_support_data)) 5153 { 5154 table++; 5155 i++; 5156 continue; 5157 } 5158 5159 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 5160 &IID_IMXAttributes, (void**)&mxattr); 5161 EXPECT_HR(hr, S_OK); 5162 5163 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr); 5164 EXPECT_HR(hr, S_OK); 5165 5166 /* SAXAttributes40 and SAXAttributes60 both crash on this test */ 5167 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) || 5168 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30)) 5169 { 5170 hr = ISAXAttributes_getLength(saxattr, NULL); 5171 EXPECT_HR(hr, E_POINTER); 5172 } 5173 5174 len = -1; 5175 hr = ISAXAttributes_getLength(saxattr, &len); 5176 EXPECT_HR(hr, S_OK); 5177 ok(len == 0, "got %d\n", len); 5178 5179 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len); 5180 EXPECT_HR(hr, E_INVALIDARG); 5181 5182 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len); 5183 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5184 5185 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL); 5186 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5187 5188 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL); 5189 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5190 5191 hr = ISAXAttributes_getType(saxattr, 0, &value, &len); 5192 EXPECT_HR(hr, E_INVALIDARG); 5193 5194 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len); 5195 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5196 5197 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL); 5198 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5199 5200 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL); 5201 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5202 5203 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local), 5204 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value)); 5205 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr); 5206 5207 if (hr == S_OK) 5208 { 5209 /* SAXAttributes40 and SAXAttributes60 both crash on this test */ 5210 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) || 5211 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30)) 5212 { 5213 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len); 5214 EXPECT_HR(hr, E_POINTER); 5215 5216 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL); 5217 EXPECT_HR(hr, E_POINTER); 5218 5219 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL); 5220 EXPECT_HR(hr, E_POINTER); 5221 5222 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len); 5223 EXPECT_HR(hr, E_POINTER); 5224 5225 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL); 5226 EXPECT_HR(hr, E_POINTER); 5227 5228 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL); 5229 EXPECT_HR(hr, E_POINTER); 5230 } 5231 5232 len = -1; 5233 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len); 5234 EXPECT_HR(hr, S_OK); 5235 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value), 5236 table->value); 5237 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len); 5238 5239 len = -1; 5240 value = (void*)0xdeadbeef; 5241 hr = ISAXAttributes_getType(saxattr, 0, &value, &len); 5242 EXPECT_HR(hr, S_OK); 5243 5244 if (table->type) 5245 { 5246 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value), 5247 table->type); 5248 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len); 5249 } 5250 else 5251 { 5252 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value)); 5253 ok(len == 0, "%d: got wrong type value length %d\n", i, len); 5254 } 5255 5256 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL); 5257 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) || 5258 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30)) 5259 { 5260 EXPECT_HR(hr, E_POINTER); 5261 } 5262 else 5263 EXPECT_HR(hr, E_INVALIDARG); 5264 5265 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index); 5266 EXPECT_HR(hr, E_INVALIDARG); 5267 5268 index = -1; 5269 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index); 5270 EXPECT_HR(hr, E_INVALIDARG); 5271 ok(index == -1, "%d: got wrong index %d\n", i, index); 5272 5273 index = -1; 5274 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index); 5275 EXPECT_HR(hr, E_INVALIDARG); 5276 ok(index == -1, "%d: got wrong index %d\n", i, index); 5277 5278 index = -1; 5279 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index); 5280 EXPECT_HR(hr, S_OK); 5281 ok(index == 0, "%d: got wrong index %d\n", i, index); 5282 5283 index = -1; 5284 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index); 5285 EXPECT_HR(hr, E_INVALIDARG); 5286 ok(index == -1, "%d: got wrong index %d\n", i, index); 5287 5288 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) || 5289 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60)) 5290 { 5291 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL); 5292 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5293 5294 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL); 5295 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5296 5297 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL); 5298 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5299 5300 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL); 5301 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5302 5303 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL); 5304 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5305 5306 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL); 5307 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5308 } 5309 else 5310 { 5311 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL); 5312 EXPECT_HR(hr, E_POINTER); 5313 5314 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL); 5315 EXPECT_HR(hr, E_POINTER); 5316 5317 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL); 5318 EXPECT_HR(hr, E_POINTER); 5319 5320 /* versions 4 and 6 crash */ 5321 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL); 5322 EXPECT_HR(hr, E_POINTER); 5323 5324 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len); 5325 EXPECT_HR(hr, E_POINTER); 5326 5327 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL); 5328 EXPECT_HR(hr, E_POINTER); 5329 5330 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL); 5331 EXPECT_HR(hr, E_POINTER); 5332 5333 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL); 5334 EXPECT_HR(hr, E_POINTER); 5335 5336 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL); 5337 EXPECT_HR(hr, E_POINTER); 5338 5339 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len); 5340 EXPECT_HR(hr, E_POINTER); 5341 5342 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local), 5343 strlen(table->local), NULL, NULL); 5344 EXPECT_HR(hr, E_POINTER); 5345 } 5346 5347 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len); 5348 EXPECT_HR(hr, S_OK); 5349 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value), 5350 table->value); 5351 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len); 5352 5353 if (table->uri) { 5354 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), 5355 _bstr_(table->local), strlen(table->local), &value, &len); 5356 EXPECT_HR(hr, S_OK); 5357 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value), 5358 table->value); 5359 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len); 5360 } 5361 } 5362 5363 len = -1; 5364 hr = ISAXAttributes_getLength(saxattr, &len); 5365 EXPECT_HR(hr, S_OK); 5366 if (table->hr == S_OK) 5367 ok(len == 1, "%d: got %d length, expected 1\n", i, len); 5368 else 5369 ok(len == 0, "%d: got %d length, expected 0\n", i, len); 5370 5371 ISAXAttributes_Release(saxattr); 5372 IMXAttributes_Release(mxattr); 5373 5374 table++; 5375 i++; 5376 } 5377 5378 free_bstrs(); 5379 } 5380 5381 static void test_mxattr_clear(void) 5382 { 5383 ISAXAttributes *saxattr; 5384 IMXAttributes *mxattr; 5385 const WCHAR *ptr; 5386 HRESULT hr; 5387 int len; 5388 5389 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER, 5390 &IID_IMXAttributes, (void**)&mxattr); 5391 EXPECT_HR(hr, S_OK); 5392 5393 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr); 5394 EXPECT_HR(hr, S_OK); 5395 5396 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL); 5397 EXPECT_HR(hr, E_INVALIDARG); 5398 5399 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len); 5400 EXPECT_HR(hr, E_INVALIDARG); 5401 5402 hr = IMXAttributes_clear(mxattr); 5403 EXPECT_HR(hr, S_OK); 5404 5405 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"), 5406 _bstr_("qname"), _bstr_("type"), _bstr_("value")); 5407 EXPECT_HR(hr, S_OK); 5408 5409 len = -1; 5410 hr = ISAXAttributes_getLength(saxattr, &len); 5411 EXPECT_HR(hr, S_OK); 5412 ok(len == 1, "got %d\n", len); 5413 5414 len = -1; 5415 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len); 5416 EXPECT_HR(hr, E_POINTER); 5417 ok(len == -1, "got %d\n", len); 5418 5419 ptr = (void*)0xdeadbeef; 5420 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL); 5421 EXPECT_HR(hr, E_POINTER); 5422 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr); 5423 5424 len = 0; 5425 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len); 5426 EXPECT_HR(hr, S_OK); 5427 ok(len == 5, "got %d\n", len); 5428 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr)); 5429 5430 hr = IMXAttributes_clear(mxattr); 5431 EXPECT_HR(hr, S_OK); 5432 5433 len = -1; 5434 hr = ISAXAttributes_getLength(saxattr, &len); 5435 EXPECT_HR(hr, S_OK); 5436 ok(len == 0, "got %d\n", len); 5437 5438 len = -1; 5439 ptr = (void*)0xdeadbeef; 5440 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len); 5441 EXPECT_HR(hr, E_INVALIDARG); 5442 ok(len == -1, "got %d\n", len); 5443 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr); 5444 5445 IMXAttributes_Release(mxattr); 5446 ISAXAttributes_Release(saxattr); 5447 free_bstrs(); 5448 } 5449 5450 static void test_mxattr_dispex(void) 5451 { 5452 IMXAttributes *mxattr; 5453 IDispatchEx *dispex; 5454 IUnknown *unk; 5455 HRESULT hr; 5456 5457 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER, 5458 &IID_IMXAttributes, (void**)&mxattr); 5459 EXPECT_HR(hr, S_OK); 5460 5461 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex); 5462 EXPECT_HR(hr, S_OK); 5463 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk); 5464 test_obj_dispex(unk); 5465 IUnknown_Release(unk); 5466 IDispatchEx_Release(dispex); 5467 5468 IMXAttributes_Release(mxattr); 5469 } 5470 5471 static void test_mxattr_qi(void) 5472 { 5473 IVBSAXAttributes *vbsaxattr, *vbsaxattr2; 5474 ISAXAttributes *saxattr; 5475 IMXAttributes *mxattr; 5476 HRESULT hr; 5477 5478 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER, 5479 &IID_IMXAttributes, (void**)&mxattr); 5480 EXPECT_HR(hr, S_OK); 5481 5482 EXPECT_REF(mxattr, 1); 5483 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr); 5484 EXPECT_HR(hr, S_OK); 5485 5486 EXPECT_REF(mxattr, 2); 5487 EXPECT_REF(saxattr, 2); 5488 5489 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr); 5490 EXPECT_HR(hr, S_OK); 5491 5492 EXPECT_REF(vbsaxattr, 3); 5493 EXPECT_REF(mxattr, 3); 5494 EXPECT_REF(saxattr, 3); 5495 5496 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2); 5497 EXPECT_HR(hr, S_OK); 5498 5499 EXPECT_REF(vbsaxattr, 4); 5500 EXPECT_REF(mxattr, 4); 5501 EXPECT_REF(saxattr, 4); 5502 5503 IMXAttributes_Release(mxattr); 5504 ISAXAttributes_Release(saxattr); 5505 IVBSAXAttributes_Release(vbsaxattr); 5506 IVBSAXAttributes_Release(vbsaxattr2); 5507 } 5508 5509 static struct msxmlsupported_data_t saxattr_support_data[] = 5510 { 5511 { &CLSID_SAXAttributes, "SAXAttributes" }, 5512 { &CLSID_SAXAttributes30, "SAXAttributes30" }, 5513 { &CLSID_SAXAttributes40, "SAXAttributes40" }, 5514 { &CLSID_SAXAttributes60, "SAXAttributes60" }, 5515 { NULL } 5516 }; 5517 5518 static void test_mxattr_localname(void) 5519 { 5520 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0}; 5521 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0}; 5522 static const WCHAR uri1W[] = {'u','r','i','1',0}; 5523 static const WCHAR uriW[] = {'u','r','i',0}; 5524 5525 const struct msxmlsupported_data_t *table = saxattr_support_data; 5526 5527 while (table->clsid) 5528 { 5529 ISAXAttributes *saxattr; 5530 IMXAttributes *mxattr; 5531 HRESULT hr; 5532 int index; 5533 5534 if (!is_clsid_supported(table->clsid, mxattributes_support_data)) 5535 { 5536 table++; 5537 continue; 5538 } 5539 5540 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 5541 &IID_IMXAttributes, (void**)&mxattr); 5542 EXPECT_HR(hr, S_OK); 5543 5544 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr); 5545 EXPECT_HR(hr, S_OK); 5546 5547 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index); 5548 EXPECT_HR(hr, E_INVALIDARG); 5549 5550 /* add some ambiguos attribute names */ 5551 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"), 5552 _bstr_("a:localname"), _bstr_(""), _bstr_("value")); 5553 EXPECT_HR(hr, S_OK); 5554 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"), 5555 _bstr_("b:localname"), _bstr_(""), _bstr_("value")); 5556 EXPECT_HR(hr, S_OK); 5557 5558 index = -1; 5559 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index); 5560 EXPECT_HR(hr, S_OK); 5561 ok(index == 0, "%s: got index %d\n", table->name, index); 5562 5563 index = -1; 5564 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index); 5565 EXPECT_HR(hr, E_INVALIDARG); 5566 ok(index == -1, "%s: got index %d\n", table->name, index); 5567 5568 index = -1; 5569 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index); 5570 EXPECT_HR(hr, E_INVALIDARG); 5571 ok(index == -1, "%s: got index %d\n", table->name, index); 5572 5573 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) || 5574 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30)) 5575 { 5576 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL); 5577 EXPECT_HR(hr, E_POINTER); 5578 5579 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL); 5580 EXPECT_HR(hr, E_POINTER); 5581 } 5582 else 5583 { 5584 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL); 5585 EXPECT_HR(hr, E_INVALIDARG); 5586 5587 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL); 5588 EXPECT_HR(hr, E_INVALIDARG); 5589 } 5590 5591 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index); 5592 EXPECT_HR(hr, E_INVALIDARG); 5593 5594 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index); 5595 EXPECT_HR(hr, E_INVALIDARG); 5596 5597 table++; 5598 5599 ISAXAttributes_Release(saxattr); 5600 IMXAttributes_Release(mxattr); 5601 free_bstrs(); 5602 } 5603 } 5604 5605 static void test_mxwriter_indent(void) 5606 { 5607 ISAXContentHandler *content; 5608 IMXWriter *writer; 5609 VARIANT dest; 5610 HRESULT hr; 5611 5612 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void**)&writer); 5613 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 5614 5615 hr = IMXWriter_put_indent(writer, VARIANT_TRUE); 5616 ok(hr == S_OK, "got %08x\n", hr); 5617 5618 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 5619 ok(hr == S_OK, "got %08x\n", hr); 5620 5621 hr = ISAXContentHandler_startDocument(content); 5622 ok(hr == S_OK, "got %08x\n", hr); 5623 5624 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL); 5625 ok(hr == S_OK, "got %08x\n", hr); 5626 5627 hr = ISAXContentHandler_characters(content, _bstr_(""), 0); 5628 ok(hr == S_OK, "got %08x\n", hr); 5629 5630 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1, NULL); 5631 ok(hr == S_OK, "got %08x\n", hr); 5632 5633 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1, NULL); 5634 ok(hr == S_OK, "got %08x\n", hr); 5635 5636 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1); 5637 ok(hr == S_OK, "got %08x\n", hr); 5638 5639 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1); 5640 ok(hr == S_OK, "got %08x\n", hr); 5641 5642 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1); 5643 ok(hr == S_OK, "got %08x\n", hr); 5644 5645 hr = ISAXContentHandler_endDocument(content); 5646 ok(hr == S_OK, "got %08x\n", hr); 5647 5648 V_VT(&dest) = VT_EMPTY; 5649 hr = IMXWriter_get_output(writer, &dest); 5650 ok(hr == S_OK, "got %08x\n", hr); 5651 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5652 ok(!lstrcmpW(_bstr_("<?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)), 5653 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5654 VariantClear(&dest); 5655 5656 ISAXContentHandler_Release(content); 5657 IMXWriter_Release(writer); 5658 5659 free_bstrs(); 5660 } 5661 5662 START_TEST(saxreader) 5663 { 5664 ISAXXMLReader *reader; 5665 HRESULT hr; 5666 5667 hr = CoInitialize(NULL); 5668 ok(hr == S_OK, "failed to init com\n"); 5669 5670 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER, 5671 &IID_ISAXXMLReader, (void**)&reader); 5672 5673 if(FAILED(hr)) 5674 { 5675 win_skip("Failed to create SAXXMLReader instance\n"); 5676 CoUninitialize(); 5677 return; 5678 } 5679 ISAXXMLReader_Release(reader); 5680 5681 init_call_sequences(sequences, NUM_CALL_SEQUENCES); 5682 5683 get_class_support_data(reader_support_data, &IID_ISAXXMLReader); 5684 5685 test_saxreader(); 5686 test_saxreader_properties(); 5687 test_saxreader_features(); 5688 test_saxreader_encoding(); 5689 test_saxreader_dispex(); 5690 5691 /* MXXMLWriter tests */ 5692 get_class_support_data(mxwriter_support_data, &IID_IMXWriter); 5693 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data)) 5694 { 5695 test_mxwriter_handlers(); 5696 test_mxwriter_startenddocument(); 5697 test_mxwriter_startendelement(); 5698 test_mxwriter_characters(); 5699 test_mxwriter_comment(); 5700 test_mxwriter_cdata(); 5701 test_mxwriter_pi(); 5702 test_mxwriter_ignorablespaces(); 5703 test_mxwriter_dtd(); 5704 test_mxwriter_properties(); 5705 test_mxwriter_flush(); 5706 test_mxwriter_stream(); 5707 test_mxwriter_encoding(); 5708 test_mxwriter_dispex(); 5709 test_mxwriter_indent(); 5710 } 5711 else 5712 win_skip("MXXMLWriter not supported\n"); 5713 5714 /* SAXAttributes tests */ 5715 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes); 5716 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data)) 5717 { 5718 test_mxattr_qi(); 5719 test_mxattr_addAttribute(); 5720 test_mxattr_clear(); 5721 test_mxattr_localname(); 5722 test_mxattr_dispex(); 5723 } 5724 else 5725 win_skip("SAXAttributes not supported\n"); 5726 5727 CoUninitialize(); 5728 } 5729