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 ok(prefix != NULL, "prefix == NULL\n"); 1166 ok(uri != NULL, "uri == NULL\n"); 1167 1168 init_call_entry(locator, &call); 1169 call.id = CH_STARTPREFIXMAPPING; 1170 call.arg1W = SysAllocStringLen(prefix, prefix_len); 1171 call.arg2W = SysAllocStringLen(uri, uri_len); 1172 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1173 1174 return get_expected_ret(); 1175 } 1176 1177 static HRESULT WINAPI contentHandler_endPrefixMapping( 1178 ISAXContentHandler* iface, 1179 const WCHAR *prefix, int len) 1180 { 1181 struct call_entry call; 1182 1183 ok(prefix != NULL, "prefix == NULL\n"); 1184 1185 init_call_entry(locator, &call); 1186 call.id = CH_ENDPREFIXMAPPING; 1187 call.arg1W = SysAllocStringLen(prefix, len); 1188 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1189 1190 return get_expected_ret(); 1191 } 1192 1193 static HRESULT WINAPI contentHandler_startElement( 1194 ISAXContentHandler* iface, 1195 const WCHAR *uri, int uri_len, 1196 const WCHAR *localname, int local_len, 1197 const WCHAR *qname, int qname_len, 1198 ISAXAttributes *saxattr) 1199 { 1200 struct call_entry call; 1201 IMXAttributes *mxattr; 1202 HRESULT hr; 1203 int len; 1204 1205 ok(uri != NULL, "uri == NULL\n"); 1206 ok(localname != NULL, "localname == NULL\n"); 1207 ok(qname != NULL, "qname == NULL\n"); 1208 1209 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IMXAttributes, (void**)&mxattr); 1210 EXPECT_HR(hr, E_NOINTERFACE); 1211 1212 init_call_entry(locator, &call); 1213 call.id = CH_STARTELEMENT; 1214 call.arg1W = SysAllocStringLen(uri, uri_len); 1215 call.arg2W = SysAllocStringLen(localname, local_len); 1216 call.arg3W = SysAllocStringLen(qname, qname_len); 1217 1218 if(!test_attr_ptr) 1219 test_attr_ptr = saxattr; 1220 ok(test_attr_ptr == saxattr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, saxattr); 1221 1222 /* store actual attributes */ 1223 len = 0; 1224 hr = ISAXAttributes_getLength(saxattr, &len); 1225 EXPECT_HR(hr, S_OK); 1226 1227 if (len) 1228 { 1229 VARIANT_BOOL v; 1230 int i; 1231 1232 struct attribute_entry *attr; 1233 attr = heap_alloc_zero(len * sizeof(*attr)); 1234 1235 v = VARIANT_TRUE; 1236 hr = ISAXXMLReader_getFeature(g_reader, _bstr_("http://xml.org/sax/features/namespaces"), &v); 1237 EXPECT_HR(hr, S_OK); 1238 1239 for (i = 0; i < len; i++) 1240 { 1241 const WCHAR *value; 1242 int value_len; 1243 1244 hr = ISAXAttributes_getName(saxattr, i, &uri, &uri_len, 1245 &localname, &local_len, &qname, &qname_len); 1246 EXPECT_HR(hr, S_OK); 1247 1248 hr = ISAXAttributes_getValue(saxattr, i, &value, &value_len); 1249 EXPECT_HR(hr, S_OK); 1250 1251 /* if 'namespaces' switched off uri and local name contains garbage */ 1252 if (v == VARIANT_FALSE && msxml_version > 0) 1253 { 1254 attr[i].uriW = SysAllocStringLen(NULL, 0); 1255 attr[i].localW = SysAllocStringLen(NULL, 0); 1256 } 1257 else 1258 { 1259 attr[i].uriW = SysAllocStringLen(uri, uri_len); 1260 attr[i].localW = SysAllocStringLen(localname, local_len); 1261 } 1262 1263 attr[i].qnameW = SysAllocStringLen(qname, qname_len); 1264 attr[i].valueW = SysAllocStringLen(value, value_len); 1265 } 1266 1267 call.attributes = attr; 1268 call.attr_count = len; 1269 } 1270 1271 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1272 1273 return get_expected_ret(); 1274 } 1275 1276 static HRESULT WINAPI contentHandler_endElement( 1277 ISAXContentHandler* iface, 1278 const WCHAR *uri, int uri_len, 1279 const WCHAR *localname, int local_len, 1280 const WCHAR *qname, int qname_len) 1281 { 1282 struct call_entry call; 1283 1284 ok(uri != NULL, "uri == NULL\n"); 1285 ok(localname != NULL, "localname == NULL\n"); 1286 ok(qname != NULL, "qname == NULL\n"); 1287 1288 init_call_entry(locator, &call); 1289 call.id = CH_ENDELEMENT; 1290 call.arg1W = SysAllocStringLen(uri, uri_len); 1291 call.arg2W = SysAllocStringLen(localname, local_len); 1292 call.arg3W = SysAllocStringLen(qname, qname_len); 1293 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1294 1295 return get_expected_ret(); 1296 } 1297 1298 static HRESULT WINAPI contentHandler_characters( 1299 ISAXContentHandler* iface, 1300 const WCHAR *chars, 1301 int len) 1302 { 1303 struct call_entry call; 1304 1305 ok(chars != NULL, "chars == NULL\n"); 1306 1307 init_call_entry(locator, &call); 1308 call.id = CH_CHARACTERS; 1309 call.arg1W = SysAllocStringLen(chars, len); 1310 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1311 1312 return get_expected_ret(); 1313 } 1314 1315 static HRESULT WINAPI contentHandler_ignorableWhitespace( 1316 ISAXContentHandler* iface, 1317 const WCHAR *chars, int len) 1318 { 1319 struct call_entry call; 1320 1321 ok(chars != NULL, "chars == NULL\n"); 1322 1323 init_call_entry(locator, &call); 1324 call.id = CH_IGNORABLEWHITESPACE; 1325 call.arg1W = SysAllocStringLen(chars, len); 1326 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1327 1328 return get_expected_ret(); 1329 } 1330 1331 static HRESULT WINAPI contentHandler_processingInstruction( 1332 ISAXContentHandler* iface, 1333 const WCHAR *target, int target_len, 1334 const WCHAR *data, int data_len) 1335 { 1336 struct call_entry call; 1337 1338 ok(target != NULL, "target == NULL\n"); 1339 ok(data != NULL, "data == NULL\n"); 1340 1341 init_call_entry(locator, &call); 1342 call.id = CH_PROCESSINGINSTRUCTION; 1343 call.arg1W = SysAllocStringLen(target, target_len); 1344 call.arg2W = SysAllocStringLen(data, data_len); 1345 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1346 1347 return get_expected_ret(); 1348 } 1349 1350 static HRESULT WINAPI contentHandler_skippedEntity( 1351 ISAXContentHandler* iface, 1352 const WCHAR *name, int len) 1353 { 1354 struct call_entry call; 1355 1356 ok(name != NULL, "name == NULL\n"); 1357 1358 init_call_entry(locator, &call); 1359 call.id = CH_SKIPPEDENTITY; 1360 call.arg1W = SysAllocStringLen(name, len); 1361 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1362 1363 return get_expected_ret(); 1364 } 1365 1366 static const ISAXContentHandlerVtbl contentHandlerVtbl = 1367 { 1368 contentHandler_QueryInterface, 1369 contentHandler_AddRef, 1370 contentHandler_Release, 1371 contentHandler_putDocumentLocator, 1372 contentHandler_startDocument, 1373 contentHandler_endDocument, 1374 contentHandler_startPrefixMapping, 1375 contentHandler_endPrefixMapping, 1376 contentHandler_startElement, 1377 contentHandler_endElement, 1378 contentHandler_characters, 1379 contentHandler_ignorableWhitespace, 1380 contentHandler_processingInstruction, 1381 contentHandler_skippedEntity 1382 }; 1383 1384 static ISAXContentHandler contentHandler = { &contentHandlerVtbl }; 1385 1386 static HRESULT WINAPI isaxerrorHandler_QueryInterface( 1387 ISAXErrorHandler* iface, 1388 REFIID riid, 1389 void **ppvObject) 1390 { 1391 *ppvObject = NULL; 1392 1393 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler)) 1394 { 1395 *ppvObject = iface; 1396 } 1397 else 1398 { 1399 return E_NOINTERFACE; 1400 } 1401 1402 return S_OK; 1403 } 1404 1405 static ULONG WINAPI isaxerrorHandler_AddRef( 1406 ISAXErrorHandler* iface) 1407 { 1408 return 2; 1409 } 1410 1411 static ULONG WINAPI isaxerrorHandler_Release( 1412 ISAXErrorHandler* iface) 1413 { 1414 return 1; 1415 } 1416 1417 static HRESULT WINAPI isaxerrorHandler_error( 1418 ISAXErrorHandler* iface, 1419 ISAXLocator *pLocator, 1420 const WCHAR *pErrorMessage, 1421 HRESULT hrErrorCode) 1422 { 1423 ok(0, "unexpected call\n"); 1424 return S_OK; 1425 } 1426 1427 static HRESULT WINAPI isaxerrorHandler_fatalError( 1428 ISAXErrorHandler* iface, 1429 ISAXLocator *pLocator, 1430 const WCHAR *message, 1431 HRESULT hr) 1432 { 1433 struct call_entry call; 1434 1435 init_call_entry(locator, &call); 1436 call.id = EH_FATALERROR; 1437 call.ret = hr; 1438 1439 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1440 1441 get_expected_ret(); 1442 return S_OK; 1443 } 1444 1445 static HRESULT WINAPI isaxerrorHandler_ignorableWarning( 1446 ISAXErrorHandler* iface, 1447 ISAXLocator *pLocator, 1448 const WCHAR *pErrorMessage, 1449 HRESULT hrErrorCode) 1450 { 1451 ok(0, "unexpected call\n"); 1452 return S_OK; 1453 } 1454 1455 static const ISAXErrorHandlerVtbl errorHandlerVtbl = 1456 { 1457 isaxerrorHandler_QueryInterface, 1458 isaxerrorHandler_AddRef, 1459 isaxerrorHandler_Release, 1460 isaxerrorHandler_error, 1461 isaxerrorHandler_fatalError, 1462 isaxerrorHandler_ignorableWarning 1463 }; 1464 1465 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl }; 1466 1467 static HRESULT WINAPI isaxattributes_QueryInterface( 1468 ISAXAttributes* iface, 1469 REFIID riid, 1470 void **ppvObject) 1471 { 1472 *ppvObject = NULL; 1473 1474 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes)) 1475 { 1476 *ppvObject = iface; 1477 } 1478 else 1479 { 1480 return E_NOINTERFACE; 1481 } 1482 1483 return S_OK; 1484 } 1485 1486 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface) 1487 { 1488 return 2; 1489 } 1490 1491 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface) 1492 { 1493 return 1; 1494 } 1495 1496 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length) 1497 { 1498 *length = 3; 1499 return S_OK; 1500 } 1501 1502 static HRESULT WINAPI isaxattributes_getURI( 1503 ISAXAttributes* iface, 1504 int nIndex, 1505 const WCHAR **pUrl, 1506 int *pUriSize) 1507 { 1508 ok(0, "unexpected call\n"); 1509 return E_NOTIMPL; 1510 } 1511 1512 static HRESULT WINAPI isaxattributes_getLocalName( 1513 ISAXAttributes* iface, 1514 int nIndex, 1515 const WCHAR **pLocalName, 1516 int *pLocalNameLength) 1517 { 1518 ok(0, "unexpected call\n"); 1519 return E_NOTIMPL; 1520 } 1521 1522 static HRESULT WINAPI isaxattributes_getQName( 1523 ISAXAttributes* iface, 1524 int index, 1525 const WCHAR **QName, 1526 int *QNameLength) 1527 { 1528 static const WCHAR attrqnamesW[][15] = {{'a',':','a','t','t','r','1','j','u','n','k',0}, 1529 {'a','t','t','r','2','j','u','n','k',0}, 1530 {'a','t','t','r','3',0}}; 1531 static const int attrqnamelen[] = {7, 5, 5}; 1532 1533 ok(index >= 0 && index <= 2, "invalid index received %d\n", index); 1534 1535 if (index >= 0 && index <= 2) { 1536 *QName = attrqnamesW[index]; 1537 *QNameLength = attrqnamelen[index]; 1538 } else { 1539 *QName = NULL; 1540 *QNameLength = 0; 1541 } 1542 1543 return S_OK; 1544 } 1545 1546 static HRESULT WINAPI isaxattributes_getName( 1547 ISAXAttributes* iface, 1548 int nIndex, 1549 const WCHAR **pUri, 1550 int * pUriLength, 1551 const WCHAR ** pLocalName, 1552 int * pLocalNameSize, 1553 const WCHAR ** pQName, 1554 int * pQNameLength) 1555 { 1556 ok(0, "unexpected call\n"); 1557 return E_NOTIMPL; 1558 } 1559 1560 static HRESULT WINAPI isaxattributes_getIndexFromName( 1561 ISAXAttributes* iface, 1562 const WCHAR * pUri, 1563 int cUriLength, 1564 const WCHAR * pLocalName, 1565 int cocalNameLength, 1566 int * index) 1567 { 1568 ok(0, "unexpected call\n"); 1569 return E_NOTIMPL; 1570 } 1571 1572 static HRESULT WINAPI isaxattributes_getIndexFromQName( 1573 ISAXAttributes* iface, 1574 const WCHAR * pQName, 1575 int nQNameLength, 1576 int * index) 1577 { 1578 ok(0, "unexpected call\n"); 1579 return E_NOTIMPL; 1580 } 1581 1582 static HRESULT WINAPI isaxattributes_getType( 1583 ISAXAttributes* iface, 1584 int nIndex, 1585 const WCHAR ** pType, 1586 int * pTypeLength) 1587 { 1588 ok(0, "unexpected call\n"); 1589 return E_NOTIMPL; 1590 } 1591 1592 static HRESULT WINAPI isaxattributes_getTypeFromName( 1593 ISAXAttributes* iface, 1594 const WCHAR * pUri, 1595 int nUri, 1596 const WCHAR * pLocalName, 1597 int nLocalName, 1598 const WCHAR ** pType, 1599 int * nType) 1600 { 1601 ok(0, "unexpected call\n"); 1602 return E_NOTIMPL; 1603 } 1604 1605 static HRESULT WINAPI isaxattributes_getTypeFromQName( 1606 ISAXAttributes* iface, 1607 const WCHAR * pQName, 1608 int nQName, 1609 const WCHAR ** pType, 1610 int * nType) 1611 { 1612 ok(0, "unexpected call\n"); 1613 return E_NOTIMPL; 1614 } 1615 1616 static HRESULT WINAPI isaxattributes_getValue(ISAXAttributes* iface, int index, 1617 const WCHAR **value, int *nValue) 1618 { 1619 static const WCHAR attrvaluesW[][10] = {{'a','1','j','u','n','k',0}, 1620 {'a','2','j','u','n','k',0}, 1621 {'<','&','"','>','\'',0}}; 1622 static const int attrvalueslen[] = {2, 2, 5}; 1623 1624 ok(index >= 0 && index <= 2, "invalid index received %d\n", index); 1625 1626 if (index >= 0 && index <= 2) { 1627 *value = attrvaluesW[index]; 1628 *nValue = attrvalueslen[index]; 1629 } else { 1630 *value = NULL; 1631 *nValue = 0; 1632 } 1633 1634 return S_OK; 1635 } 1636 1637 static HRESULT WINAPI isaxattributes_getValueFromName( 1638 ISAXAttributes* iface, 1639 const WCHAR * pUri, 1640 int nUri, 1641 const WCHAR * pLocalName, 1642 int nLocalName, 1643 const WCHAR ** pValue, 1644 int * nValue) 1645 { 1646 ok(0, "unexpected call\n"); 1647 return E_NOTIMPL; 1648 } 1649 1650 static HRESULT WINAPI isaxattributes_getValueFromQName( 1651 ISAXAttributes* iface, 1652 const WCHAR * pQName, 1653 int nQName, 1654 const WCHAR ** pValue, 1655 int * nValue) 1656 { 1657 ok(0, "unexpected call\n"); 1658 return E_NOTIMPL; 1659 } 1660 1661 static const ISAXAttributesVtbl SAXAttributesVtbl = 1662 { 1663 isaxattributes_QueryInterface, 1664 isaxattributes_AddRef, 1665 isaxattributes_Release, 1666 isaxattributes_getLength, 1667 isaxattributes_getURI, 1668 isaxattributes_getLocalName, 1669 isaxattributes_getQName, 1670 isaxattributes_getName, 1671 isaxattributes_getIndexFromName, 1672 isaxattributes_getIndexFromQName, 1673 isaxattributes_getType, 1674 isaxattributes_getTypeFromName, 1675 isaxattributes_getTypeFromQName, 1676 isaxattributes_getValue, 1677 isaxattributes_getValueFromName, 1678 isaxattributes_getValueFromQName 1679 }; 1680 1681 static ISAXAttributes saxattributes = { &SAXAttributesVtbl }; 1682 1683 struct saxlexicalhandler 1684 { 1685 ISAXLexicalHandler ISAXLexicalHandler_iface; 1686 LONG ref; 1687 1688 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */ 1689 }; 1690 1691 static inline struct saxlexicalhandler *impl_from_ISAXLexicalHandler( ISAXLexicalHandler *iface ) 1692 { 1693 return CONTAINING_RECORD(iface, struct saxlexicalhandler, ISAXLexicalHandler_iface); 1694 } 1695 1696 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **out) 1697 { 1698 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface); 1699 1700 *out = NULL; 1701 1702 if (IsEqualGUID(riid, &IID_IUnknown)) 1703 { 1704 *out = iface; 1705 ok(0, "got unexpected IID_IUnknown query\n"); 1706 } 1707 else if (IsEqualGUID(riid, &IID_ISAXLexicalHandler)) 1708 { 1709 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr; 1710 *out = iface; 1711 } 1712 1713 if (*out) 1714 ISAXLexicalHandler_AddRef(iface); 1715 else 1716 return E_NOINTERFACE; 1717 1718 return S_OK; 1719 } 1720 1721 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface) 1722 { 1723 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface); 1724 return InterlockedIncrement(&handler->ref); 1725 } 1726 1727 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface) 1728 { 1729 struct saxlexicalhandler *handler = impl_from_ISAXLexicalHandler(iface); 1730 return InterlockedDecrement(&handler->ref); 1731 } 1732 1733 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface, 1734 const WCHAR * pName, int nName, const WCHAR * pPublicId, 1735 int nPublicId, const WCHAR * pSystemId, int nSystemId) 1736 { 1737 ok(0, "call not expected\n"); 1738 return E_NOTIMPL; 1739 } 1740 1741 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface) 1742 { 1743 ok(0, "call not expected\n"); 1744 return E_NOTIMPL; 1745 } 1746 1747 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface, 1748 const WCHAR * pName, int nName) 1749 { 1750 ok(0, "call not expected\n"); 1751 return E_NOTIMPL; 1752 } 1753 1754 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface, 1755 const WCHAR * pName, int nName) 1756 { 1757 ok(0, "call not expected\n"); 1758 return E_NOTIMPL; 1759 } 1760 1761 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface) 1762 { 1763 struct call_entry call; 1764 1765 init_call_entry(locator, &call); 1766 call.id = LH_STARTCDATA; 1767 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1768 1769 return get_expected_ret(); 1770 } 1771 1772 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface) 1773 { 1774 struct call_entry call; 1775 1776 init_call_entry(locator, &call); 1777 call.id = LH_ENDCDATA; 1778 add_call(sequences, CONTENT_HANDLER_INDEX, &call); 1779 1780 return get_expected_ret(); 1781 } 1782 1783 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface, 1784 const WCHAR * pChars, int nChars) 1785 { 1786 ok(0, "call not expected\n"); 1787 return E_NOTIMPL; 1788 } 1789 1790 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl = 1791 { 1792 isaxlexical_QueryInterface, 1793 isaxlexical_AddRef, 1794 isaxlexical_Release, 1795 isaxlexical_startDTD, 1796 isaxlexical_endDTD, 1797 isaxlexical_startEntity, 1798 isaxlexical_endEntity, 1799 isaxlexical_startCDATA, 1800 isaxlexical_endCDATA, 1801 isaxlexical_comment 1802 }; 1803 1804 static void init_saxlexicalhandler(struct saxlexicalhandler *handler, HRESULT hr) 1805 { 1806 handler->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl; 1807 handler->ref = 1; 1808 handler->qi_hr = hr; 1809 } 1810 1811 struct saxdeclhandler 1812 { 1813 ISAXDeclHandler ISAXDeclHandler_iface; 1814 LONG ref; 1815 1816 HRESULT qi_hr; /* ret value for QueryInterface for handler riid */ 1817 }; 1818 1819 static inline struct saxdeclhandler *impl_from_ISAXDeclHandler( ISAXDeclHandler *iface ) 1820 { 1821 return CONTAINING_RECORD(iface, struct saxdeclhandler, ISAXDeclHandler_iface); 1822 } 1823 1824 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **out) 1825 { 1826 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface); 1827 1828 *out = NULL; 1829 1830 if (IsEqualGUID(riid, &IID_IUnknown)) 1831 { 1832 *out = iface; 1833 ok(0, "got unexpected IID_IUnknown query\n"); 1834 } 1835 else if (IsEqualGUID(riid, &IID_ISAXDeclHandler)) 1836 { 1837 if (handler->qi_hr == E_NOINTERFACE) return handler->qi_hr; 1838 *out = iface; 1839 } 1840 1841 if (*out) 1842 ISAXDeclHandler_AddRef(iface); 1843 else 1844 return E_NOINTERFACE; 1845 1846 return S_OK; 1847 } 1848 1849 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface) 1850 { 1851 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface); 1852 return InterlockedIncrement(&handler->ref); 1853 } 1854 1855 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface) 1856 { 1857 struct saxdeclhandler *handler = impl_from_ISAXDeclHandler(iface); 1858 return InterlockedDecrement(&handler->ref); 1859 } 1860 1861 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface, 1862 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel) 1863 { 1864 ok(0, "call not expected\n"); 1865 return E_NOTIMPL; 1866 } 1867 1868 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface, 1869 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName, 1870 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault, 1871 int nValueDefault, const WCHAR * pValue, int nValue) 1872 { 1873 ok(0, "call not expected\n"); 1874 return E_NOTIMPL; 1875 } 1876 1877 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface, 1878 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue) 1879 { 1880 ok(0, "call not expected\n"); 1881 return E_NOTIMPL; 1882 } 1883 1884 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface, 1885 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId, 1886 const WCHAR * pSystemId, int nSystemId) 1887 { 1888 ok(0, "call not expected\n"); 1889 return E_NOTIMPL; 1890 } 1891 1892 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl = 1893 { 1894 isaxdecl_QueryInterface, 1895 isaxdecl_AddRef, 1896 isaxdecl_Release, 1897 isaxdecl_elementDecl, 1898 isaxdecl_attributeDecl, 1899 isaxdecl_internalEntityDecl, 1900 isaxdecl_externalEntityDecl 1901 }; 1902 1903 static void init_saxdeclhandler(struct saxdeclhandler *handler, HRESULT hr) 1904 { 1905 handler->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl; 1906 handler->ref = 1; 1907 handler->qi_hr = hr; 1908 } 1909 1910 typedef struct mxwriter_write_test_t { 1911 BOOL last; 1912 const BYTE *data; 1913 DWORD cb; 1914 BOOL null_written; 1915 BOOL fail_write; 1916 } mxwriter_write_test; 1917 1918 typedef struct mxwriter_stream_test_t { 1919 VARIANT_BOOL bom; 1920 const char *encoding; 1921 mxwriter_write_test expected_writes[4]; 1922 } mxwriter_stream_test; 1923 1924 static const mxwriter_write_test *current_write_test; 1925 static DWORD current_stream_test_index; 1926 1927 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject) 1928 { 1929 *ppvObject = NULL; 1930 1931 ok(!IsEqualGUID(riid, &IID_IPersistStream), "Did not expect QI for IPersistStream\n"); 1932 1933 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown)) 1934 *ppvObject = iface; 1935 else 1936 return E_NOINTERFACE; 1937 1938 return S_OK; 1939 } 1940 1941 static ULONG WINAPI istream_AddRef(IStream *iface) 1942 { 1943 return 2; 1944 } 1945 1946 static ULONG WINAPI istream_Release(IStream *iface) 1947 { 1948 return 1; 1949 } 1950 1951 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead) 1952 { 1953 ok(0, "unexpected call\n"); 1954 return E_NOTIMPL; 1955 } 1956 1957 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten) 1958 { 1959 ok(0, "unexpected call\n"); 1960 return E_NOTIMPL; 1961 } 1962 1963 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, 1964 ULARGE_INTEGER *plibNewPosition) 1965 { 1966 ok(0, "unexpected call\n"); 1967 return E_NOTIMPL; 1968 } 1969 1970 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize) 1971 { 1972 ok(0, "unexpected call\n"); 1973 return E_NOTIMPL; 1974 } 1975 1976 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb, 1977 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten) 1978 { 1979 ok(0, "unexpected call\n"); 1980 return E_NOTIMPL; 1981 } 1982 1983 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags) 1984 { 1985 ok(0, "unexpected call\n"); 1986 return E_NOTIMPL; 1987 } 1988 1989 static HRESULT WINAPI istream_Revert(IStream *iface) 1990 { 1991 ok(0, "unexpected call\n"); 1992 return E_NOTIMPL; 1993 } 1994 1995 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, 1996 ULARGE_INTEGER cb, DWORD dwLockType) 1997 { 1998 ok(0, "unexpected call\n"); 1999 return E_NOTIMPL; 2000 } 2001 2002 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, 2003 ULARGE_INTEGER cb, DWORD dwLockType) 2004 { 2005 ok(0, "unexpected call\n"); 2006 return E_NOTIMPL; 2007 } 2008 2009 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag) 2010 { 2011 return E_NOTIMPL; 2012 } 2013 2014 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm) 2015 { 2016 ok(0, "unexpected call\n"); 2017 return E_NOTIMPL; 2018 } 2019 2020 static HRESULT WINAPI mxstream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten) 2021 { 2022 BOOL fail = FALSE; 2023 2024 ok(pv != NULL, "pv == NULL\n"); 2025 2026 if(current_write_test->last) { 2027 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index); 2028 return E_FAIL; 2029 } 2030 2031 fail = current_write_test->fail_write; 2032 2033 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n", 2034 current_write_test->cb, cb, current_stream_test_index); 2035 2036 if(!pcbWritten) 2037 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index); 2038 else 2039 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index); 2040 2041 ++current_write_test; 2042 2043 if(pcbWritten) 2044 *pcbWritten = cb; 2045 2046 return fail ? E_FAIL : S_OK; 2047 } 2048 2049 static const IStreamVtbl mxstreamVtbl = { 2050 istream_QueryInterface, 2051 istream_AddRef, 2052 istream_Release, 2053 istream_Read, 2054 mxstream_Write, 2055 istream_Seek, 2056 istream_SetSize, 2057 istream_CopyTo, 2058 istream_Commit, 2059 istream_Revert, 2060 istream_LockRegion, 2061 istream_UnlockRegion, 2062 istream_Stat, 2063 istream_Clone 2064 }; 2065 2066 static IStream mxstream = { &mxstreamVtbl }; 2067 2068 static int read_cnt; 2069 2070 static HRESULT WINAPI instream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead) 2071 { 2072 static const char *ret_str; 2073 2074 if(!read_cnt) 2075 ret_str = "<?xml version=\"1.0\" ?>\n<rootelem>"; 2076 else if(read_cnt < 5) 2077 ret_str = "<elem attr=\"val\">text</elem>"; 2078 else if(read_cnt == 5) 2079 ret_str = "</rootelem>\n"; 2080 else 2081 ret_str = ""; 2082 2083 read_cnt++; 2084 strcpy(pv, ret_str); 2085 *pcbRead = strlen(ret_str); 2086 return S_OK; 2087 } 2088 2089 static const IStreamVtbl instreamVtbl = { 2090 istream_QueryInterface, 2091 istream_AddRef, 2092 istream_Release, 2093 instream_Read, 2094 istream_Write, 2095 istream_Seek, 2096 istream_SetSize, 2097 istream_CopyTo, 2098 istream_Commit, 2099 istream_Revert, 2100 istream_LockRegion, 2101 istream_UnlockRegion, 2102 istream_Stat, 2103 istream_Clone 2104 }; 2105 2106 static IStream instream = { &instreamVtbl }; 2107 2108 static struct msxmlsupported_data_t reader_support_data[] = 2109 { 2110 { &CLSID_SAXXMLReader, "SAXReader" }, 2111 { &CLSID_SAXXMLReader30, "SAXReader30" }, 2112 { &CLSID_SAXXMLReader40, "SAXReader40" }, 2113 { &CLSID_SAXXMLReader60, "SAXReader60" }, 2114 { NULL } 2115 }; 2116 2117 static struct saxlexicalhandler lexicalhandler; 2118 static struct saxdeclhandler declhandler; 2119 2120 static IStream *create_test_stream(const char *data, int len) 2121 { 2122 ULARGE_INTEGER size; 2123 LARGE_INTEGER pos; 2124 IStream *stream; 2125 ULONG written; 2126 2127 if (len == -1) len = strlen(data); 2128 CreateStreamOnHGlobal(NULL, TRUE, &stream); 2129 size.QuadPart = len; 2130 IStream_SetSize(stream, size); 2131 IStream_Write(stream, data, len, &written); 2132 pos.QuadPart = 0; 2133 IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL); 2134 2135 return stream; 2136 } 2137 2138 static void test_saxreader(void) 2139 { 2140 const struct msxmlsupported_data_t *table = reader_support_data; 2141 HRESULT hr; 2142 ISAXXMLReader *reader = NULL; 2143 VARIANT var; 2144 ISAXContentHandler *content; 2145 ISAXErrorHandler *lpErrorHandler; 2146 SAFEARRAY *sa; 2147 SAFEARRAYBOUND SADim[1]; 2148 char *ptr = NULL; 2149 IStream *stream; 2150 ULONG written; 2151 HANDLE file; 2152 static const CHAR testXmlA[] = "test.xml"; 2153 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0}; 2154 IXMLDOMDocument *doc; 2155 char seqname[50]; 2156 VARIANT_BOOL v; 2157 2158 while (table->clsid) 2159 { 2160 struct call_entry *test_seq; 2161 ISAXEntityResolver *resolver; 2162 BSTR str; 2163 2164 if (!is_clsid_supported(table->clsid, reader_support_data)) 2165 { 2166 table++; 2167 continue; 2168 } 2169 2170 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader); 2171 EXPECT_HR(hr, S_OK); 2172 g_reader = reader; 2173 2174 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) 2175 msxml_version = 4; 2176 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2177 msxml_version = 6; 2178 else 2179 msxml_version = 0; 2180 2181 /* crashes on old versions */ 2182 if (!IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) && 2183 !IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2184 { 2185 hr = ISAXXMLReader_getContentHandler(reader, NULL); 2186 EXPECT_HR(hr, E_POINTER); 2187 2188 hr = ISAXXMLReader_getErrorHandler(reader, NULL); 2189 EXPECT_HR(hr, E_POINTER); 2190 } 2191 2192 hr = ISAXXMLReader_getContentHandler(reader, &content); 2193 EXPECT_HR(hr, S_OK); 2194 ok(content == NULL, "Expected %p, got %p\n", NULL, content); 2195 2196 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler); 2197 EXPECT_HR(hr, S_OK); 2198 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler); 2199 2200 hr = ISAXXMLReader_putContentHandler(reader, NULL); 2201 EXPECT_HR(hr, S_OK); 2202 2203 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler); 2204 EXPECT_HR(hr, S_OK); 2205 2206 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler); 2207 EXPECT_HR(hr, S_OK); 2208 2209 hr = ISAXXMLReader_getContentHandler(reader, &content); 2210 EXPECT_HR(hr, S_OK); 2211 ok(content == &contentHandler, "Expected %p, got %p\n", &contentHandler, content); 2212 2213 V_VT(&var) = VT_BSTR; 2214 V_BSTR(&var) = SysAllocString(szSimpleXML); 2215 2216 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2217 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2218 test_seq = content_handler_test1_alternate; 2219 else 2220 test_seq = content_handler_test1; 2221 set_expected_seq(test_seq); 2222 hr = ISAXXMLReader_parse(reader, var); 2223 EXPECT_HR(hr, S_OK); 2224 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1", FALSE); 2225 2226 VariantClear(&var); 2227 2228 SADim[0].lLbound = 0; 2229 SADim[0].cElements = sizeof(testXML)-1; 2230 sa = SafeArrayCreate(VT_UI1, 1, SADim); 2231 SafeArrayAccessData(sa, (void**)&ptr); 2232 memcpy(ptr, testXML, sizeof(testXML)-1); 2233 SafeArrayUnaccessData(sa); 2234 V_VT(&var) = VT_ARRAY|VT_UI1; 2235 V_ARRAY(&var) = sa; 2236 2237 set_expected_seq(test_seq); 2238 hr = ISAXXMLReader_parse(reader, var); 2239 EXPECT_HR(hr, S_OK); 2240 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from safe array", FALSE); 2241 2242 SafeArrayDestroy(sa); 2243 2244 V_VT(&var) = VT_UNKNOWN; 2245 V_UNKNOWN(&var) = NULL; 2246 hr = ISAXXMLReader_parse(reader, var); 2247 ok(hr == E_INVALIDARG, "got %#x\n", hr); 2248 2249 V_VT(&var) = VT_DISPATCH; 2250 V_DISPATCH(&var) = NULL; 2251 hr = ISAXXMLReader_parse(reader, var); 2252 ok(hr == E_INVALIDARG, "got %#x\n", hr); 2253 2254 stream = create_test_stream(testXML, -1); 2255 V_VT(&var) = VT_UNKNOWN; 2256 V_UNKNOWN(&var) = (IUnknown*)stream; 2257 2258 set_expected_seq(test_seq); 2259 hr = ISAXXMLReader_parse(reader, var); 2260 EXPECT_HR(hr, S_OK); 2261 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from stream", FALSE); 2262 2263 IStream_Release(stream); 2264 2265 stream = create_test_stream(test_attributes, -1); 2266 V_VT(&var) = VT_UNKNOWN; 2267 V_UNKNOWN(&var) = (IUnknown*)stream; 2268 2269 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) 2270 test_seq = content_handler_test_attributes_alternate_4; 2271 else if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2272 test_seq = content_handler_test_attributes_alternate_6; 2273 else 2274 test_seq = content_handler_test_attributes; 2275 2276 set_expected_seq(test_seq); 2277 hr = ISAXXMLReader_parse(reader, var); 2278 EXPECT_HR(hr, S_OK); 2279 2280 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2281 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2282 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", FALSE); 2283 else 2284 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE); 2285 2286 IStream_Release(stream); 2287 2288 V_VT(&var) = VT_UNKNOWN; 2289 V_UNKNOWN(&var) = (IUnknown*)&instream; 2290 2291 test_seq = read_test_seq; 2292 read_cnt = 0; 2293 set_expected_seq(test_seq); 2294 hr = ISAXXMLReader_parse(reader, var); 2295 EXPECT_HR(hr, S_OK); 2296 ok(read_cnt == 7, "read_cnt = %d\n", read_cnt); 2297 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "Read call test", FALSE); 2298 2299 V_VT(&var) = VT_BSTR; 2300 V_BSTR(&var) = SysAllocString(carriage_ret_test); 2301 2302 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2303 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2304 test_seq = content_handler_test2_alternate; 2305 else 2306 test_seq = content_handler_test2; 2307 2308 set_expected_seq(test_seq); 2309 hr = ISAXXMLReader_parse(reader, var); 2310 EXPECT_HR(hr, S_OK); 2311 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 2", FALSE); 2312 2313 VariantClear(&var); 2314 2315 /* from file url */ 2316 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 2317 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError()); 2318 WriteFile(file, testXML, sizeof(testXML)-1, &written, NULL); 2319 CloseHandle(file); 2320 2321 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2322 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2323 test_seq = content_handler_test1_alternate; 2324 else 2325 test_seq = content_handler_test1; 2326 set_expected_seq(test_seq); 2327 hr = ISAXXMLReader_parseURL(reader, testXmlW); 2328 EXPECT_HR(hr, S_OK); 2329 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test 1: from file url", FALSE); 2330 2331 /* error handler */ 2332 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2333 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2334 test_seq = content_handler_testerror_alternate; 2335 else 2336 test_seq = content_handler_testerror; 2337 set_expected_seq(test_seq); 2338 hr = ISAXXMLReader_parseURL(reader, testXmlW); 2339 EXPECT_HR(hr, E_FAIL); 2340 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test error", FALSE); 2341 2342 /* callback ret values */ 2343 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2344 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2345 { 2346 test_seq = content_handler_test_callback_rets_alt; 2347 set_expected_seq(test_seq); 2348 hr = ISAXXMLReader_parseURL(reader, testXmlW); 2349 EXPECT_HR(hr, S_OK); 2350 } 2351 else 2352 { 2353 test_seq = content_handler_test_callback_rets; 2354 set_expected_seq(test_seq); 2355 hr = ISAXXMLReader_parseURL(reader, testXmlW); 2356 EXPECT_HR(hr, S_FALSE); 2357 } 2358 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content callback ret values", FALSE); 2359 2360 DeleteFileA(testXmlA); 2361 2362 /* parse from IXMLDOMDocument */ 2363 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, 2364 &IID_IXMLDOMDocument, (void**)&doc); 2365 EXPECT_HR(hr, S_OK); 2366 2367 str = SysAllocString(szSimpleXML); 2368 hr = IXMLDOMDocument_loadXML(doc, str, &v); 2369 EXPECT_HR(hr, S_OK); 2370 SysFreeString(str); 2371 2372 V_VT(&var) = VT_UNKNOWN; 2373 V_UNKNOWN(&var) = (IUnknown*)doc; 2374 2375 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2376 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2377 test_seq = content_handler_test2_alternate; 2378 else 2379 test_seq = content_handler_test2; 2380 2381 set_expected_seq(test_seq); 2382 hr = ISAXXMLReader_parse(reader, var); 2383 EXPECT_HR(hr, S_OK); 2384 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "parse from IXMLDOMDocument", FALSE); 2385 IXMLDOMDocument_Release(doc); 2386 2387 /* xml:space test */ 2388 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2389 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2390 { 2391 test_seq = xmlspaceattr_test_alternate; 2392 } 2393 else 2394 test_seq = xmlspaceattr_test; 2395 2396 set_expected_seq(test_seq); 2397 V_VT(&var) = VT_BSTR; 2398 V_BSTR(&var) = _bstr_(xmlspace_attr); 2399 hr = ISAXXMLReader_parse(reader, var); 2400 EXPECT_HR(hr, S_OK); 2401 2402 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2403 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2404 { 2405 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", TRUE); 2406 } 2407 else 2408 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "xml:space handling", FALSE); 2409 2410 /* switch off 'namespaces' feature */ 2411 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_FALSE); 2412 EXPECT_HR(hr, S_OK); 2413 2414 stream = create_test_stream(test_attributes, -1); 2415 V_VT(&var) = VT_UNKNOWN; 2416 V_UNKNOWN(&var) = (IUnknown*)stream; 2417 2418 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2419 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2420 { 2421 test_seq = content_handler_test_attributes_alt_no_ns; 2422 } 2423 else 2424 test_seq = content_handler_test_attributes; 2425 2426 set_expected_seq(test_seq); 2427 hr = ISAXXMLReader_parse(reader, var); 2428 EXPECT_HR(hr, S_OK); 2429 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "content test attributes", TRUE); 2430 IStream_Release(stream); 2431 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), VARIANT_TRUE); 2432 EXPECT_HR(hr, S_OK); 2433 2434 /* switch off 'namespace-prefixes' feature */ 2435 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_FALSE); 2436 EXPECT_HR(hr, S_OK); 2437 2438 stream = create_test_stream(test_attributes, -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 = content_handler_test_attributes_alt_no_prefix; 2446 } 2447 else 2448 test_seq = content_handler_test_attributes_no_prefix; 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, "content test attributes", FALSE); 2454 IStream_Release(stream); 2455 2456 hr = ISAXXMLReader_putFeature(reader, _bstr_("http://xml.org/sax/features/namespace-prefixes"), VARIANT_TRUE); 2457 EXPECT_HR(hr, S_OK); 2458 2459 /* attribute normalization */ 2460 stream = create_test_stream(attribute_normalize, -1); 2461 V_VT(&var) = VT_UNKNOWN; 2462 V_UNKNOWN(&var) = (IUnknown*)stream; 2463 2464 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40) || 2465 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60)) 2466 { 2467 test_seq = attribute_norm_alt; 2468 } 2469 else 2470 test_seq = attribute_norm; 2471 2472 set_expected_seq(test_seq); 2473 hr = ISAXXMLReader_parse(reader, var); 2474 EXPECT_HR(hr, S_OK); 2475 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, "attribute value normalization", TRUE); 2476 IStream_Release(stream); 2477 2478 resolver = (void*)0xdeadbeef; 2479 hr = ISAXXMLReader_getEntityResolver(reader, &resolver); 2480 ok(hr == S_OK, "got 0x%08x\n", hr); 2481 ok(resolver == NULL, "got %p\n", resolver); 2482 2483 hr = ISAXXMLReader_putEntityResolver(reader, NULL); 2484 ok(hr == S_OK || broken(hr == E_FAIL), "got 0x%08x\n", hr); 2485 2486 /* CDATA sections */ 2487 init_saxlexicalhandler(&lexicalhandler, S_OK); 2488 2489 V_VT(&var) = VT_UNKNOWN; 2490 V_UNKNOWN(&var) = (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface; 2491 hr = ISAXXMLReader_putProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), var); 2492 ok(hr == S_OK, "got 0x%08x\n", hr); 2493 2494 stream = create_test_stream(test_cdata_xml, -1); 2495 V_VT(&var) = VT_UNKNOWN; 2496 V_UNKNOWN(&var) = (IUnknown*)stream; 2497 2498 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) || 2499 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) 2500 test_seq = cdata_test_alt; 2501 else 2502 test_seq = cdata_test; 2503 2504 set_expected_seq(test_seq); 2505 hr = ISAXXMLReader_parse(reader, var); 2506 ok(hr == S_OK, "got 0x%08x\n", hr); 2507 sprintf(seqname, "%s: cdata test", table->name); 2508 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); 2509 2510 IStream_Release(stream); 2511 2512 /* 2. CDATA sections */ 2513 stream = create_test_stream(test2_cdata_xml, -1); 2514 V_VT(&var) = VT_UNKNOWN; 2515 V_UNKNOWN(&var) = (IUnknown*)stream; 2516 2517 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) || 2518 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) 2519 test_seq = cdata_test2_alt; 2520 else 2521 test_seq = cdata_test2; 2522 2523 set_expected_seq(test_seq); 2524 hr = ISAXXMLReader_parse(reader, var); 2525 ok(hr == S_OK, "got 0x%08x\n", hr); 2526 sprintf(seqname, "%s: cdata test 2", table->name); 2527 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); 2528 2529 IStream_Release(stream); 2530 2531 /* 3. CDATA sections */ 2532 stream = create_test_stream(test3_cdata_xml, -1); 2533 V_VT(&var) = VT_UNKNOWN; 2534 V_UNKNOWN(&var) = (IUnknown*)stream; 2535 2536 if (IsEqualGUID(table->clsid, &CLSID_SAXXMLReader60) || 2537 IsEqualGUID(table->clsid, &CLSID_SAXXMLReader40)) 2538 test_seq = cdata_test3_alt; 2539 else 2540 test_seq = cdata_test3; 2541 2542 set_expected_seq(test_seq); 2543 hr = ISAXXMLReader_parse(reader, var); 2544 ok(hr == S_OK, "got 0x%08x\n", hr); 2545 sprintf(seqname, "%s: cdata test 3", table->name); 2546 ok_sequence(sequences, CONTENT_HANDLER_INDEX, test_seq, seqname, TRUE); 2547 2548 IStream_Release(stream); 2549 2550 ISAXXMLReader_Release(reader); 2551 table++; 2552 } 2553 2554 free_bstrs(); 2555 } 2556 2557 struct saxreader_props_test_t 2558 { 2559 const char *prop_name; 2560 IUnknown *iface; 2561 }; 2562 2563 static const struct saxreader_props_test_t props_test_data[] = { 2564 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&lexicalhandler.ISAXLexicalHandler_iface }, 2565 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&declhandler.ISAXDeclHandler_iface }, 2566 { 0 } 2567 }; 2568 2569 static void test_saxreader_properties(void) 2570 { 2571 const struct saxreader_props_test_t *ptr = props_test_data; 2572 ISAXXMLReader *reader; 2573 HRESULT hr; 2574 VARIANT v; 2575 BSTR str; 2576 2577 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER, 2578 &IID_ISAXXMLReader, (void**)&reader); 2579 EXPECT_HR(hr, S_OK); 2580 2581 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL); 2582 EXPECT_HR(hr, E_POINTER); 2583 2584 while (ptr->prop_name) 2585 { 2586 VARIANT varref; 2587 LONG ref; 2588 2589 init_saxlexicalhandler(&lexicalhandler, S_OK); 2590 init_saxdeclhandler(&declhandler, S_OK); 2591 2592 V_VT(&v) = VT_EMPTY; 2593 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2594 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2595 EXPECT_HR(hr, S_OK); 2596 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2597 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v)); 2598 2599 /* VT_UNKNOWN */ 2600 V_VT(&v) = VT_UNKNOWN; 2601 V_UNKNOWN(&v) = ptr->iface; 2602 ref = get_refcount(ptr->iface); 2603 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2604 EXPECT_HR(hr, S_OK); 2605 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n"); 2606 2607 /* VT_DISPATCH */ 2608 V_VT(&v) = VT_DISPATCH; 2609 V_UNKNOWN(&v) = ptr->iface; 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 /* VT_VARIANT|VT_BYREF with VT_UNKNOWN in referenced variant */ 2616 V_VT(&varref) = VT_UNKNOWN; 2617 V_UNKNOWN(&varref) = ptr->iface; 2618 2619 V_VT(&v) = VT_VARIANT|VT_BYREF; 2620 V_VARIANTREF(&v) = &varref; 2621 ref = get_refcount(ptr->iface); 2622 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2623 EXPECT_HR(hr, S_OK); 2624 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref); 2625 2626 /* VT_VARIANT|VT_BYREF with VT_DISPATCH in referenced variant */ 2627 V_VT(&varref) = VT_DISPATCH; 2628 V_UNKNOWN(&varref) = ptr->iface; 2629 2630 V_VT(&v) = VT_VARIANT|VT_BYREF; 2631 V_VARIANTREF(&v) = &varref; 2632 ref = get_refcount(ptr->iface); 2633 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2634 EXPECT_HR(hr, S_OK); 2635 ok(ref == get_refcount(ptr->iface), "got wrong refcount %d, expected %d\n", get_refcount(ptr->iface), ref); 2636 2637 V_VT(&v) = VT_EMPTY; 2638 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2639 2640 ref = get_refcount(ptr->iface); 2641 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2642 EXPECT_HR(hr, S_OK); 2643 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2644 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v)); 2645 ok(ref < get_refcount(ptr->iface), "expected inreased refcount\n"); 2646 VariantClear(&v); 2647 2648 V_VT(&v) = VT_EMPTY; 2649 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2650 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2651 EXPECT_HR(hr, S_OK); 2652 2653 V_VT(&v) = VT_EMPTY; 2654 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2655 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2656 EXPECT_HR(hr, S_OK); 2657 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2658 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v)); 2659 2660 V_VT(&v) = VT_UNKNOWN; 2661 V_UNKNOWN(&v) = ptr->iface; 2662 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2663 EXPECT_HR(hr, S_OK); 2664 2665 /* only VT_EMPTY seems to be valid to reset property */ 2666 V_VT(&v) = VT_I4; 2667 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2668 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2669 EXPECT_HR(hr, E_INVALIDARG); 2670 2671 V_VT(&v) = VT_EMPTY; 2672 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2673 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2674 EXPECT_HR(hr, S_OK); 2675 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2676 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v)); 2677 VariantClear(&v); 2678 2679 V_VT(&v) = VT_UNKNOWN; 2680 V_UNKNOWN(&v) = NULL; 2681 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2682 EXPECT_HR(hr, S_OK); 2683 2684 V_VT(&v) = VT_EMPTY; 2685 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2686 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2687 EXPECT_HR(hr, S_OK); 2688 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2689 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v)); 2690 2691 /* block QueryInterface on handler riid */ 2692 V_VT(&v) = VT_UNKNOWN; 2693 V_UNKNOWN(&v) = ptr->iface; 2694 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2695 EXPECT_HR(hr, S_OK); 2696 2697 init_saxlexicalhandler(&lexicalhandler, E_NOINTERFACE); 2698 init_saxdeclhandler(&declhandler, E_NOINTERFACE); 2699 2700 V_VT(&v) = VT_UNKNOWN; 2701 V_UNKNOWN(&v) = ptr->iface; 2702 EXPECT_REF(ptr->iface, 1); 2703 ref = get_refcount(ptr->iface); 2704 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v); 2705 EXPECT_HR(hr, E_NOINTERFACE); 2706 EXPECT_REF(ptr->iface, 1); 2707 2708 V_VT(&v) = VT_EMPTY; 2709 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef; 2710 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v); 2711 EXPECT_HR(hr, S_OK); 2712 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v)); 2713 ok(V_UNKNOWN(&v) != NULL, "got %p\n", V_UNKNOWN(&v)); 2714 2715 ptr++; 2716 free_bstrs(); 2717 } 2718 2719 ISAXXMLReader_Release(reader); 2720 2721 if (!is_clsid_supported(&CLSID_SAXXMLReader40, reader_support_data)) 2722 return; 2723 2724 hr = CoCreateInstance(&CLSID_SAXXMLReader40, NULL, CLSCTX_INPROC_SERVER, 2725 &IID_ISAXXMLReader, (void**)&reader); 2726 EXPECT_HR(hr, S_OK); 2727 2728 /* xmldecl-version property */ 2729 V_VT(&v) = VT_EMPTY; 2730 V_BSTR(&v) = (void*)0xdeadbeef; 2731 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v); 2732 EXPECT_HR(hr, S_OK); 2733 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); 2734 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v))); 2735 2736 /* stream without declaration */ 2737 V_VT(&v) = VT_BSTR; 2738 V_BSTR(&v) = _bstr_("<element></element>"); 2739 hr = ISAXXMLReader_parse(reader, v); 2740 EXPECT_HR(hr, S_OK); 2741 2742 V_VT(&v) = VT_EMPTY; 2743 V_BSTR(&v) = (void*)0xdeadbeef; 2744 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v); 2745 EXPECT_HR(hr, S_OK); 2746 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); 2747 ok(V_BSTR(&v) == NULL, "got %s\n", wine_dbgstr_w(V_BSTR(&v))); 2748 2749 /* stream with declaration */ 2750 V_VT(&v) = VT_BSTR; 2751 V_BSTR(&v) = _bstr_("<?xml version=\"1.0\"?><element></element>"); 2752 hr = ISAXXMLReader_parse(reader, v); 2753 EXPECT_HR(hr, S_OK); 2754 2755 /* VT_BSTR|VT_BYREF input type */ 2756 str = _bstr_("<?xml version=\"1.0\"?><element></element>"); 2757 V_VT(&v) = VT_BSTR|VT_BYREF; 2758 V_BSTRREF(&v) = &str; 2759 hr = ISAXXMLReader_parse(reader, v); 2760 EXPECT_HR(hr, S_OK); 2761 2762 V_VT(&v) = VT_EMPTY; 2763 V_BSTR(&v) = (void*)0xdeadbeef; 2764 hr = ISAXXMLReader_getProperty(reader, _bstr_("xmldecl-version"), &v); 2765 EXPECT_HR(hr, S_OK); 2766 ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v)); 2767 ok(!lstrcmpW(V_BSTR(&v), _bstr_("1.0")), "got %s\n", wine_dbgstr_w(V_BSTR(&v))); 2768 VariantClear(&v); 2769 2770 ISAXXMLReader_Release(reader); 2771 free_bstrs(); 2772 } 2773 2774 struct feature_ns_entry_t { 2775 const GUID *guid; 2776 const char *clsid; 2777 VARIANT_BOOL value; 2778 VARIANT_BOOL value2; /* feature value after feature set to 0xc */ 2779 }; 2780 2781 static const struct feature_ns_entry_t feature_ns_entry_data[] = { 2782 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE, VARIANT_FALSE }, 2783 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE, VARIANT_FALSE }, 2784 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE, VARIANT_TRUE }, 2785 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE, VARIANT_TRUE }, 2786 { 0 } 2787 }; 2788 2789 static const char *feature_names[] = { 2790 "http://xml.org/sax/features/namespaces", 2791 "http://xml.org/sax/features/namespace-prefixes", 2792 0 2793 }; 2794 2795 static void test_saxreader_features(void) 2796 { 2797 const struct feature_ns_entry_t *entry = feature_ns_entry_data; 2798 ISAXXMLReader *reader; 2799 2800 while (entry->guid) 2801 { 2802 VARIANT_BOOL value; 2803 const char **name; 2804 HRESULT hr; 2805 2806 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader); 2807 if (hr != S_OK) 2808 { 2809 win_skip("can't create %s instance\n", entry->clsid); 2810 entry++; 2811 continue; 2812 } 2813 2814 if (IsEqualGUID(entry->guid, &CLSID_SAXXMLReader40) || 2815 IsEqualGUID(entry->guid, &CLSID_SAXXMLReader60)) 2816 { 2817 value = VARIANT_TRUE; 2818 hr = ISAXXMLReader_getFeature(reader, _bstr_("exhaustive-errors"), &value); 2819 ok(hr == S_OK, "Failed to get feature value, hr %#x.\n", hr); 2820 ok(value == VARIANT_FALSE, "Unexpected default feature value.\n"); 2821 hr = ISAXXMLReader_putFeature(reader, _bstr_("exhaustive-errors"), VARIANT_FALSE); 2822 ok(hr == S_OK, "Failed to put feature value, hr %#x.\n", hr); 2823 2824 value = VARIANT_TRUE; 2825 hr = ISAXXMLReader_getFeature(reader, _bstr_("schema-validation"), &value); 2826 ok(hr == S_OK, "Failed to get feature value, hr %#x.\n", hr); 2827 ok(value == VARIANT_FALSE, "Unexpected default feature value.\n"); 2828 hr = ISAXXMLReader_putFeature(reader, _bstr_("exhaustive-errors"), VARIANT_FALSE); 2829 ok(hr == S_OK, "Failed to put feature value, hr %#x.\n", hr); 2830 } 2831 else 2832 { 2833 value = 123; 2834 hr = ISAXXMLReader_getFeature(reader, _bstr_("exhaustive-errors"), &value); 2835 ok(hr == E_INVALIDARG, "Failed to get feature value, hr %#x.\n", hr); 2836 ok(value == 123, "Unexpected value %d.\n", value); 2837 2838 value = 123; 2839 hr = ISAXXMLReader_getFeature(reader, _bstr_("schema-validation"), &value); 2840 ok(hr == E_INVALIDARG, "Failed to get feature value, hr %#x.\n", hr); 2841 ok(value == 123, "Unexpected value %d.\n", value); 2842 } 2843 2844 name = feature_names; 2845 while (*name) 2846 { 2847 value = 0xc; 2848 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value); 2849 EXPECT_HR(hr, S_OK); 2850 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value); 2851 2852 value = 0xc; 2853 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), value); 2854 EXPECT_HR(hr, S_OK); 2855 2856 value = 0xd; 2857 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value); 2858 EXPECT_HR(hr, S_OK); 2859 ok(entry->value2 == value, "%s: got wrong value %x, expected %x\n", entry->clsid, value, entry->value2); 2860 2861 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_FALSE); 2862 EXPECT_HR(hr, S_OK); 2863 value = 0xd; 2864 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value); 2865 EXPECT_HR(hr, S_OK); 2866 ok(value == VARIANT_FALSE, "%s: got wrong value %x, expected VARIANT_FALSE\n", entry->clsid, value); 2867 2868 hr = ISAXXMLReader_putFeature(reader, _bstr_(*name), VARIANT_TRUE); 2869 EXPECT_HR(hr, S_OK); 2870 value = 0xd; 2871 hr = ISAXXMLReader_getFeature(reader, _bstr_(*name), &value); 2872 EXPECT_HR(hr, S_OK); 2873 ok(value == VARIANT_TRUE, "%s: got wrong value %x, expected VARIANT_TRUE\n", entry->clsid, value); 2874 2875 name++; 2876 } 2877 2878 ISAXXMLReader_Release(reader); 2879 2880 entry++; 2881 } 2882 } 2883 2884 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */ 2885 static const CHAR UTF8BOMTest[] = 2886 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n" 2887 "<a></a>\n"; 2888 2889 struct enc_test_entry_t { 2890 const GUID *guid; 2891 const char *clsid; 2892 const char *data; 2893 HRESULT hr; 2894 BOOL todo; 2895 }; 2896 2897 static const struct enc_test_entry_t encoding_test_data[] = { 2898 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, TRUE }, 2899 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, TRUE }, 2900 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, FALSE }, 2901 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, FALSE }, 2902 { 0 } 2903 }; 2904 2905 static void test_saxreader_encoding(void) 2906 { 2907 const struct enc_test_entry_t *entry = encoding_test_data; 2908 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0}; 2909 static const CHAR testXmlA[] = "test.xml"; 2910 2911 while (entry->guid) 2912 { 2913 ISAXXMLReader *reader; 2914 VARIANT input; 2915 DWORD written; 2916 HANDLE file; 2917 HRESULT hr; 2918 2919 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader); 2920 if (hr != S_OK) 2921 { 2922 win_skip("can't create %s instance\n", entry->clsid); 2923 entry++; 2924 continue; 2925 } 2926 2927 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 2928 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError()); 2929 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL); 2930 CloseHandle(file); 2931 2932 hr = ISAXXMLReader_parseURL(reader, testXmlW); 2933 todo_wine_if(entry->todo) 2934 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid); 2935 2936 DeleteFileA(testXmlA); 2937 2938 /* try BSTR input with no BOM or '<?xml' instruction */ 2939 V_VT(&input) = VT_BSTR; 2940 V_BSTR(&input) = _bstr_("<element></element>"); 2941 hr = ISAXXMLReader_parse(reader, input); 2942 EXPECT_HR(hr, S_OK); 2943 2944 ISAXXMLReader_Release(reader); 2945 2946 free_bstrs(); 2947 entry++; 2948 } 2949 } 2950 2951 static void test_mxwriter_handlers(void) 2952 { 2953 IMXWriter *writer; 2954 HRESULT hr; 2955 int i; 2956 2957 static REFIID riids[] = 2958 { 2959 &IID_ISAXContentHandler, 2960 &IID_ISAXLexicalHandler, 2961 &IID_ISAXDeclHandler, 2962 &IID_ISAXDTDHandler, 2963 &IID_ISAXErrorHandler, 2964 &IID_IVBSAXDeclHandler, 2965 &IID_IVBSAXLexicalHandler, 2966 &IID_IVBSAXContentHandler, 2967 &IID_IVBSAXDTDHandler, 2968 &IID_IVBSAXErrorHandler 2969 }; 2970 2971 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 2972 &IID_IMXWriter, (void**)&writer); 2973 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 2974 2975 EXPECT_REF(writer, 1); 2976 2977 for (i = 0; i < ARRAY_SIZE(riids); i++) 2978 { 2979 IUnknown *handler; 2980 IMXWriter *writer2; 2981 2982 /* handler from IMXWriter */ 2983 hr = IMXWriter_QueryInterface(writer, riids[i], (void**)&handler); 2984 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr); 2985 EXPECT_REF(writer, 2); 2986 EXPECT_REF(handler, 2); 2987 2988 /* IMXWriter from a handler */ 2989 hr = IUnknown_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2); 2990 ok(hr == S_OK, "%s, expected S_OK, got %08x\n", wine_dbgstr_guid(riids[i]), hr); 2991 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer); 2992 EXPECT_REF(writer, 3); 2993 IMXWriter_Release(writer2); 2994 IUnknown_Release(handler); 2995 } 2996 2997 IMXWriter_Release(writer); 2998 } 2999 3000 static struct msxmlsupported_data_t mxwriter_support_data[] = 3001 { 3002 { &CLSID_MXXMLWriter, "MXXMLWriter" }, 3003 { &CLSID_MXXMLWriter30, "MXXMLWriter30" }, 3004 { &CLSID_MXXMLWriter40, "MXXMLWriter40" }, 3005 { &CLSID_MXXMLWriter60, "MXXMLWriter60" }, 3006 { NULL } 3007 }; 3008 3009 static struct msxmlsupported_data_t mxattributes_support_data[] = 3010 { 3011 { &CLSID_SAXAttributes, "SAXAttributes" }, 3012 { &CLSID_SAXAttributes30, "SAXAttributes30" }, 3013 { &CLSID_SAXAttributes40, "SAXAttributes40" }, 3014 { &CLSID_SAXAttributes60, "SAXAttributes60" }, 3015 { NULL } 3016 }; 3017 3018 struct mxwriter_props_t 3019 { 3020 const GUID *clsid; 3021 VARIANT_BOOL bom; 3022 VARIANT_BOOL disable_escape; 3023 VARIANT_BOOL indent; 3024 VARIANT_BOOL omitdecl; 3025 VARIANT_BOOL standalone; 3026 const char *encoding; 3027 }; 3028 3029 static const struct mxwriter_props_t mxwriter_default_props[] = 3030 { 3031 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" }, 3032 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" }, 3033 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" }, 3034 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" }, 3035 { NULL } 3036 }; 3037 3038 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table) 3039 { 3040 int i = 0; 3041 3042 while (table->clsid) 3043 { 3044 IMXWriter *writer; 3045 VARIANT_BOOL b; 3046 BSTR encoding; 3047 HRESULT hr; 3048 3049 if (!is_clsid_supported(table->clsid, mxwriter_support_data)) 3050 { 3051 table++; 3052 i++; 3053 continue; 3054 } 3055 3056 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 3057 &IID_IMXWriter, (void**)&writer); 3058 EXPECT_HR(hr, S_OK); 3059 3060 b = !table->bom; 3061 hr = IMXWriter_get_byteOrderMark(writer, &b); 3062 EXPECT_HR(hr, S_OK); 3063 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom); 3064 3065 b = !table->disable_escape; 3066 hr = IMXWriter_get_disableOutputEscaping(writer, &b); 3067 EXPECT_HR(hr, S_OK); 3068 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b, 3069 table->disable_escape); 3070 3071 b = !table->indent; 3072 hr = IMXWriter_get_indent(writer, &b); 3073 EXPECT_HR(hr, S_OK); 3074 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent); 3075 3076 b = !table->omitdecl; 3077 hr = IMXWriter_get_omitXMLDeclaration(writer, &b); 3078 EXPECT_HR(hr, S_OK); 3079 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl); 3080 3081 b = !table->standalone; 3082 hr = IMXWriter_get_standalone(writer, &b); 3083 EXPECT_HR(hr, S_OK); 3084 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone); 3085 3086 hr = IMXWriter_get_encoding(writer, &encoding); 3087 EXPECT_HR(hr, S_OK); 3088 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n", 3089 i, wine_dbgstr_w(encoding), table->encoding); 3090 SysFreeString(encoding); 3091 3092 IMXWriter_Release(writer); 3093 3094 table++; 3095 i++; 3096 } 3097 } 3098 3099 static void test_mxwriter_properties(void) 3100 { 3101 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0}; 3102 static const WCHAR testW[] = {'t','e','s','t',0}; 3103 ISAXContentHandler *content; 3104 IMXWriter *writer; 3105 VARIANT_BOOL b; 3106 HRESULT hr; 3107 BSTR str, str2; 3108 VARIANT dest; 3109 3110 test_mxwriter_default_properties(mxwriter_default_props); 3111 3112 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3113 &IID_IMXWriter, (void**)&writer); 3114 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3115 3116 hr = IMXWriter_get_disableOutputEscaping(writer, NULL); 3117 ok(hr == E_POINTER, "got %08x\n", hr); 3118 3119 hr = IMXWriter_get_byteOrderMark(writer, NULL); 3120 ok(hr == E_POINTER, "got %08x\n", hr); 3121 3122 hr = IMXWriter_get_indent(writer, NULL); 3123 ok(hr == E_POINTER, "got %08x\n", hr); 3124 3125 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL); 3126 ok(hr == E_POINTER, "got %08x\n", hr); 3127 3128 hr = IMXWriter_get_standalone(writer, NULL); 3129 ok(hr == E_POINTER, "got %08x\n", hr); 3130 3131 /* set and check */ 3132 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE); 3133 ok(hr == S_OK, "got %08x\n", hr); 3134 3135 b = VARIANT_FALSE; 3136 hr = IMXWriter_get_standalone(writer, &b); 3137 ok(hr == S_OK, "got %08x\n", hr); 3138 ok(b == VARIANT_TRUE, "got %d\n", b); 3139 3140 hr = IMXWriter_get_encoding(writer, NULL); 3141 EXPECT_HR(hr, E_POINTER); 3142 3143 /* UTF-16 is a default setting apparently */ 3144 str = (void*)0xdeadbeef; 3145 hr = IMXWriter_get_encoding(writer, &str); 3146 EXPECT_HR(hr, S_OK); 3147 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str)); 3148 3149 str2 = (void*)0xdeadbeef; 3150 hr = IMXWriter_get_encoding(writer, &str2); 3151 ok(hr == S_OK, "got %08x\n", hr); 3152 ok(str != str2, "expected newly allocated, got same %p\n", str); 3153 3154 SysFreeString(str2); 3155 SysFreeString(str); 3156 3157 /* put empty string */ 3158 str = SysAllocString(emptyW); 3159 hr = IMXWriter_put_encoding(writer, str); 3160 ok(hr == E_INVALIDARG, "got %08x\n", hr); 3161 SysFreeString(str); 3162 3163 str = (void*)0xdeadbeef; 3164 hr = IMXWriter_get_encoding(writer, &str); 3165 EXPECT_HR(hr, S_OK); 3166 ok(!lstrcmpW(str, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(str)); 3167 SysFreeString(str); 3168 3169 /* invalid encoding name */ 3170 str = SysAllocString(testW); 3171 hr = IMXWriter_put_encoding(writer, str); 3172 ok(hr == E_INVALIDARG, "got %08x\n", hr); 3173 SysFreeString(str); 3174 3175 /* test case sensivity */ 3176 hr = IMXWriter_put_encoding(writer, _bstr_("utf-8")); 3177 EXPECT_HR(hr, S_OK); 3178 str = (void*)0xdeadbeef; 3179 hr = IMXWriter_get_encoding(writer, &str); 3180 EXPECT_HR(hr, S_OK); 3181 ok(!lstrcmpW(str, _bstr_("utf-8")), "got %s\n", wine_dbgstr_w(str)); 3182 SysFreeString(str); 3183 3184 hr = IMXWriter_put_encoding(writer, _bstr_("uTf-16")); 3185 EXPECT_HR(hr, S_OK); 3186 str = (void*)0xdeadbeef; 3187 hr = IMXWriter_get_encoding(writer, &str); 3188 EXPECT_HR(hr, S_OK); 3189 ok(!lstrcmpW(str, _bstr_("uTf-16")), "got %s\n", wine_dbgstr_w(str)); 3190 SysFreeString(str); 3191 3192 /* how it affects document creation */ 3193 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3194 EXPECT_HR(hr, S_OK); 3195 3196 hr = ISAXContentHandler_startDocument(content); 3197 EXPECT_HR(hr, S_OK); 3198 hr = ISAXContentHandler_endDocument(content); 3199 EXPECT_HR(hr, S_OK); 3200 3201 V_VT(&dest) = VT_EMPTY; 3202 hr = IMXWriter_get_output(writer, &dest); 3203 EXPECT_HR(hr, S_OK); 3204 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3205 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>\r\n"), 3206 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3207 VariantClear(&dest); 3208 ISAXContentHandler_Release(content); 3209 3210 hr = IMXWriter_get_version(writer, NULL); 3211 ok(hr == E_POINTER, "got %08x\n", hr); 3212 /* default version is 'surprisingly' 1.0 */ 3213 hr = IMXWriter_get_version(writer, &str); 3214 ok(hr == S_OK, "got %08x\n", hr); 3215 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str)); 3216 SysFreeString(str); 3217 3218 /* store version string as is */ 3219 hr = IMXWriter_put_version(writer, NULL); 3220 ok(hr == E_INVALIDARG, "got %08x\n", hr); 3221 3222 hr = IMXWriter_put_version(writer, _bstr_("1.0")); 3223 ok(hr == S_OK, "got %08x\n", hr); 3224 3225 hr = IMXWriter_put_version(writer, _bstr_("")); 3226 ok(hr == S_OK, "got %08x\n", hr); 3227 hr = IMXWriter_get_version(writer, &str); 3228 ok(hr == S_OK, "got %08x\n", hr); 3229 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str)); 3230 SysFreeString(str); 3231 3232 hr = IMXWriter_put_version(writer, _bstr_("a.b")); 3233 ok(hr == S_OK, "got %08x\n", hr); 3234 hr = IMXWriter_get_version(writer, &str); 3235 ok(hr == S_OK, "got %08x\n", hr); 3236 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str)); 3237 SysFreeString(str); 3238 3239 hr = IMXWriter_put_version(writer, _bstr_("2.0")); 3240 ok(hr == S_OK, "got %08x\n", hr); 3241 hr = IMXWriter_get_version(writer, &str); 3242 ok(hr == S_OK, "got %08x\n", hr); 3243 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str)); 3244 SysFreeString(str); 3245 3246 IMXWriter_Release(writer); 3247 free_bstrs(); 3248 } 3249 3250 static void test_mxwriter_flush(void) 3251 { 3252 ISAXContentHandler *content; 3253 IMXWriter *writer; 3254 LARGE_INTEGER pos; 3255 ULARGE_INTEGER pos2; 3256 IStream *stream; 3257 VARIANT dest; 3258 HRESULT hr; 3259 char *buff; 3260 LONG ref; 3261 int len; 3262 3263 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3264 &IID_IMXWriter, (void**)&writer); 3265 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3266 3267 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 3268 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3269 EXPECT_REF(stream, 1); 3270 3271 /* detach when nothing was attached */ 3272 V_VT(&dest) = VT_EMPTY; 3273 hr = IMXWriter_put_output(writer, dest); 3274 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3275 3276 /* attach stream */ 3277 V_VT(&dest) = VT_UNKNOWN; 3278 V_UNKNOWN(&dest) = (IUnknown*)stream; 3279 hr = IMXWriter_put_output(writer, dest); 3280 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3281 todo_wine EXPECT_REF(stream, 3); 3282 3283 /* detach setting VT_EMPTY destination */ 3284 V_VT(&dest) = VT_EMPTY; 3285 hr = IMXWriter_put_output(writer, dest); 3286 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3287 EXPECT_REF(stream, 1); 3288 3289 V_VT(&dest) = VT_UNKNOWN; 3290 V_UNKNOWN(&dest) = (IUnknown*)stream; 3291 hr = IMXWriter_put_output(writer, dest); 3292 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3293 3294 /* flush() doesn't detach a stream */ 3295 hr = IMXWriter_flush(writer); 3296 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3297 todo_wine EXPECT_REF(stream, 3); 3298 3299 pos.QuadPart = 0; 3300 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3301 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3302 ok(pos2.QuadPart == 0, "expected stream beginning\n"); 3303 3304 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3305 ok(hr == S_OK, "got %08x\n", hr); 3306 3307 hr = ISAXContentHandler_startDocument(content); 3308 ok(hr == S_OK, "got %08x\n", hr); 3309 3310 pos.QuadPart = 0; 3311 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3312 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3313 ok(pos2.QuadPart != 0, "expected stream beginning\n"); 3314 3315 /* already started */ 3316 hr = ISAXContentHandler_startDocument(content); 3317 ok(hr == S_OK, "got %08x\n", hr); 3318 3319 hr = ISAXContentHandler_endDocument(content); 3320 ok(hr == S_OK, "got %08x\n", hr); 3321 3322 /* flushed on endDocument() */ 3323 pos.QuadPart = 0; 3324 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3325 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3326 ok(pos2.QuadPart != 0, "expected stream position moved\n"); 3327 3328 IStream_Release(stream); 3329 3330 /* auto-flush feature */ 3331 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 3332 EXPECT_HR(hr, S_OK); 3333 EXPECT_REF(stream, 1); 3334 3335 V_VT(&dest) = VT_UNKNOWN; 3336 V_UNKNOWN(&dest) = (IUnknown*)stream; 3337 hr = IMXWriter_put_output(writer, dest); 3338 EXPECT_HR(hr, S_OK); 3339 3340 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_FALSE); 3341 EXPECT_HR(hr, S_OK); 3342 3343 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3344 EXPECT_HR(hr, S_OK); 3345 3346 hr = ISAXContentHandler_startDocument(content); 3347 EXPECT_HR(hr, S_OK); 3348 3349 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL); 3350 EXPECT_HR(hr, S_OK); 3351 3352 /* internal buffer is flushed automatically on certain threshold */ 3353 pos.QuadPart = 0; 3354 pos2.QuadPart = 1; 3355 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3356 EXPECT_HR(hr, S_OK); 3357 ok(pos2.QuadPart == 0, "expected stream beginning\n"); 3358 3359 len = 2048; 3360 buff = heap_alloc(len + 1); 3361 memset(buff, 'A', len); 3362 buff[len] = 0; 3363 hr = ISAXContentHandler_characters(content, _bstr_(buff), len); 3364 EXPECT_HR(hr, S_OK); 3365 3366 pos.QuadPart = 0; 3367 pos2.QuadPart = 0; 3368 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3369 EXPECT_HR(hr, S_OK); 3370 ok(pos2.QuadPart != 0, "unexpected stream beginning\n"); 3371 3372 hr = IMXWriter_get_output(writer, NULL); 3373 EXPECT_HR(hr, E_POINTER); 3374 3375 ref = get_refcount(stream); 3376 V_VT(&dest) = VT_EMPTY; 3377 hr = IMXWriter_get_output(writer, &dest); 3378 EXPECT_HR(hr, S_OK); 3379 ok(V_VT(&dest) == VT_UNKNOWN, "got vt type %d\n", V_VT(&dest)); 3380 ok(V_UNKNOWN(&dest) == (IUnknown*)stream, "got pointer %p\n", V_UNKNOWN(&dest)); 3381 ok(ref+1 == get_refcount(stream), "expected increased refcount\n"); 3382 VariantClear(&dest); 3383 3384 hr = ISAXContentHandler_endDocument(content); 3385 EXPECT_HR(hr, S_OK); 3386 3387 IStream_Release(stream); 3388 3389 /* test char count lower than threshold */ 3390 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 3391 EXPECT_HR(hr, S_OK); 3392 EXPECT_REF(stream, 1); 3393 3394 hr = ISAXContentHandler_startDocument(content); 3395 EXPECT_HR(hr, S_OK); 3396 3397 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL); 3398 EXPECT_HR(hr, S_OK); 3399 3400 pos.QuadPart = 0; 3401 pos2.QuadPart = 1; 3402 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3403 EXPECT_HR(hr, S_OK); 3404 ok(pos2.QuadPart == 0, "expected stream beginning\n"); 3405 3406 memset(buff, 'A', len); 3407 buff[len] = 0; 3408 hr = ISAXContentHandler_characters(content, _bstr_(buff), len - 8); 3409 EXPECT_HR(hr, S_OK); 3410 3411 pos.QuadPart = 0; 3412 pos2.QuadPart = 1; 3413 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 3414 EXPECT_HR(hr, S_OK); 3415 ok(pos2.QuadPart == 0, "expected stream beginning\n"); 3416 3417 hr = ISAXContentHandler_endDocument(content); 3418 EXPECT_HR(hr, S_OK); 3419 3420 /* test auto-flush function when stream is not set */ 3421 V_VT(&dest) = VT_EMPTY; 3422 hr = IMXWriter_put_output(writer, dest); 3423 EXPECT_HR(hr, S_OK); 3424 3425 hr = ISAXContentHandler_startDocument(content); 3426 EXPECT_HR(hr, S_OK); 3427 3428 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL); 3429 EXPECT_HR(hr, S_OK); 3430 3431 memset(buff, 'A', len); 3432 buff[len] = 0; 3433 hr = ISAXContentHandler_characters(content, _bstr_(buff), len); 3434 EXPECT_HR(hr, S_OK); 3435 3436 V_VT(&dest) = VT_EMPTY; 3437 hr = IMXWriter_get_output(writer, &dest); 3438 EXPECT_HR(hr, S_OK); 3439 len += strlen("<a>"); 3440 ok(SysStringLen(V_BSTR(&dest)) == len, "got len=%d, expected %d\n", SysStringLen(V_BSTR(&dest)), len); 3441 VariantClear(&dest); 3442 3443 heap_free(buff); 3444 ISAXContentHandler_Release(content); 3445 IStream_Release(stream); 3446 IMXWriter_Release(writer); 3447 free_bstrs(); 3448 } 3449 3450 static void test_mxwriter_startenddocument(void) 3451 { 3452 ISAXContentHandler *content; 3453 IMXWriter *writer; 3454 VARIANT dest; 3455 HRESULT hr; 3456 3457 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3458 &IID_IMXWriter, (void**)&writer); 3459 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3460 3461 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3462 ok(hr == S_OK, "got %08x\n", hr); 3463 3464 hr = ISAXContentHandler_startDocument(content); 3465 ok(hr == S_OK, "got %08x\n", hr); 3466 3467 hr = ISAXContentHandler_endDocument(content); 3468 ok(hr == S_OK, "got %08x\n", hr); 3469 3470 V_VT(&dest) = VT_EMPTY; 3471 hr = IMXWriter_get_output(writer, &dest); 3472 ok(hr == S_OK, "got %08x\n", hr); 3473 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3474 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)), 3475 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3476 VariantClear(&dest); 3477 3478 /* now try another startDocument */ 3479 hr = ISAXContentHandler_startDocument(content); 3480 ok(hr == S_OK, "got %08x\n", hr); 3481 /* and get duplicated prolog */ 3482 V_VT(&dest) = VT_EMPTY; 3483 hr = IMXWriter_get_output(writer, &dest); 3484 ok(hr == S_OK, "got %08x\n", hr); 3485 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3486 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n" 3487 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)), 3488 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3489 VariantClear(&dest); 3490 3491 ISAXContentHandler_Release(content); 3492 IMXWriter_Release(writer); 3493 3494 /* now with omitted declaration */ 3495 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3496 &IID_IMXWriter, (void**)&writer); 3497 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3498 3499 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3500 ok(hr == S_OK, "got %08x\n", hr); 3501 3502 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3503 ok(hr == S_OK, "got %08x\n", hr); 3504 3505 hr = ISAXContentHandler_startDocument(content); 3506 ok(hr == S_OK, "got %08x\n", hr); 3507 3508 hr = ISAXContentHandler_endDocument(content); 3509 ok(hr == S_OK, "got %08x\n", hr); 3510 3511 V_VT(&dest) = VT_EMPTY; 3512 hr = IMXWriter_get_output(writer, &dest); 3513 ok(hr == S_OK, "got %08x\n", hr); 3514 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3515 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3516 VariantClear(&dest); 3517 3518 ISAXContentHandler_Release(content); 3519 IMXWriter_Release(writer); 3520 3521 free_bstrs(); 3522 } 3523 3524 enum startendtype 3525 { 3526 StartElement = 0x001, 3527 EndElement = 0x010, 3528 StartEndElement = 0x011, 3529 DisableEscaping = 0x100 3530 }; 3531 3532 struct writer_startendelement_t { 3533 const GUID *clsid; 3534 enum startendtype type; 3535 const char *uri; 3536 const char *local_name; 3537 const char *qname; 3538 const char *output; 3539 HRESULT hr; 3540 ISAXAttributes *attr; 3541 }; 3542 3543 static const char startelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\'\">"; 3544 static const char startendelement_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&">\'\"/>"; 3545 static const char startendelement_noescape_xml[] = "<uri:local a:attr1=\"a1\" attr2=\"a2\" attr3=\"<&\">\'\"/>"; 3546 3547 static const struct writer_startendelement_t writer_startendelement[] = { 3548 /* 0 */ 3549 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3550 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3551 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3552 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK }, 3553 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3554 /* 5 */ 3555 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3556 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3557 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK }, 3558 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3559 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3560 /* 10 */ 3561 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3562 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK }, 3563 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3564 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3565 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3566 /* 15 */ 3567 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK }, 3568 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK }, 3569 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK }, 3570 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK }, 3571 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK }, 3572 /* 20 */ 3573 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3574 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3575 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3576 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK }, 3577 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK }, 3578 /* 25 */ 3579 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK }, 3580 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK }, 3581 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK }, 3582 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK }, 3583 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK }, 3584 /* 30 */ 3585 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK }, 3586 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK }, 3587 /* endElement tests */ 3588 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3589 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3590 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG }, 3591 /* 35 */ 3592 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK }, 3593 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3594 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3595 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG }, 3596 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK }, 3597 /* 40 */ 3598 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3599 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3600 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG }, 3601 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK }, 3602 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3603 /* 45 */ 3604 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3605 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG }, 3606 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK }, 3607 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK }, 3608 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK }, 3609 /* 50 */ 3610 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK }, 3611 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK }, 3612 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3613 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3614 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG }, 3615 /* 55 */ 3616 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK }, 3617 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK }, 3618 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK }, 3619 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK }, 3620 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK }, 3621 /* 60 */ 3622 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK }, 3623 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK }, 3624 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK }, 3625 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK }, 3626 3627 /* with attributes */ 3628 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes }, 3629 /* 65 */ 3630 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes }, 3631 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes }, 3632 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", startelement_xml, S_OK, &saxattributes }, 3633 /* empty elements */ 3634 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3635 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3636 /* 70 */ 3637 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3638 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3639 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK }, 3640 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK }, 3641 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK }, 3642 /* 75 */ 3643 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK }, 3644 3645 /* with disabled output escaping */ 3646 { &CLSID_MXXMLWriter, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes }, 3647 { &CLSID_MXXMLWriter30, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_noescape_xml, S_OK, &saxattributes }, 3648 { &CLSID_MXXMLWriter40, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3649 { &CLSID_MXXMLWriter60, StartEndElement | DisableEscaping, "uri", "local", "uri:local", startendelement_xml, S_OK, &saxattributes }, 3650 3651 { NULL } 3652 }; 3653 3654 static void get_class_support_data(struct msxmlsupported_data_t *table, REFIID riid) 3655 { 3656 while (table->clsid) 3657 { 3658 IUnknown *unk; 3659 HRESULT hr; 3660 3661 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&unk); 3662 if (hr == S_OK) IUnknown_Release(unk); 3663 3664 table->supported = hr == S_OK; 3665 if (hr != S_OK) win_skip("class %s not supported\n", table->name); 3666 3667 table++; 3668 } 3669 } 3670 3671 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table) 3672 { 3673 int i = 0; 3674 3675 while (table->clsid) 3676 { 3677 ISAXContentHandler *content; 3678 IMXWriter *writer; 3679 HRESULT hr; 3680 3681 if (!is_clsid_supported(table->clsid, mxwriter_support_data)) 3682 { 3683 table++; 3684 i++; 3685 continue; 3686 } 3687 3688 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 3689 &IID_IMXWriter, (void**)&writer); 3690 EXPECT_HR(hr, S_OK); 3691 3692 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3693 EXPECT_HR(hr, S_OK); 3694 3695 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3696 EXPECT_HR(hr, S_OK); 3697 3698 hr = ISAXContentHandler_startDocument(content); 3699 EXPECT_HR(hr, S_OK); 3700 3701 if (table->type & DisableEscaping) 3702 { 3703 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE); 3704 EXPECT_HR(hr, S_OK); 3705 } 3706 3707 if (table->type & StartElement) 3708 { 3709 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0, 3710 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname), 3711 table->qname ? strlen(table->qname) : 0, table->attr); 3712 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr); 3713 } 3714 3715 if (table->type & EndElement) 3716 { 3717 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), table->uri ? strlen(table->uri) : 0, 3718 _bstr_(table->local_name), table->local_name ? strlen(table->local_name) : 0, _bstr_(table->qname), 3719 table->qname ? strlen(table->qname) : 0); 3720 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr); 3721 } 3722 3723 /* test output */ 3724 if (hr == S_OK) 3725 { 3726 VARIANT dest; 3727 3728 V_VT(&dest) = VT_EMPTY; 3729 hr = IMXWriter_get_output(writer, &dest); 3730 EXPECT_HR(hr, S_OK); 3731 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3732 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)), 3733 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output); 3734 VariantClear(&dest); 3735 } 3736 3737 ISAXContentHandler_Release(content); 3738 IMXWriter_Release(writer); 3739 3740 table++; 3741 i++; 3742 } 3743 3744 free_bstrs(); 3745 } 3746 3747 /* point of these test is to start/end element with different names and name lengths */ 3748 struct writer_startendelement2_t { 3749 const GUID *clsid; 3750 const char *qnamestart; 3751 int qnamestart_len; 3752 const char *qnameend; 3753 int qnameend_len; 3754 const char *output; 3755 HRESULT hr; 3756 }; 3757 3758 static const struct writer_startendelement2_t writer_startendelement2[] = { 3759 { &CLSID_MXXMLWriter, "a", -1, "b", -1, "<a/>", S_OK }, 3760 { &CLSID_MXXMLWriter30, "a", -1, "b", -1, "<a/>", S_OK }, 3761 { &CLSID_MXXMLWriter40, "a", -1, "b", -1, "<a/>", S_OK }, 3762 /* -1 length is not allowed for version 6 */ 3763 { &CLSID_MXXMLWriter60, "a", -1, "b", -1, "<a/>", E_INVALIDARG }, 3764 3765 { &CLSID_MXXMLWriter, "a", 1, "b", 1, "<a/>", S_OK }, 3766 { &CLSID_MXXMLWriter30, "a", 1, "b", 1, "<a/>", S_OK }, 3767 { &CLSID_MXXMLWriter40, "a", 1, "b", 1, "<a/>", S_OK }, 3768 { &CLSID_MXXMLWriter60, "a", 1, "b", 1, "<a/>", S_OK }, 3769 { NULL } 3770 }; 3771 3772 static void test_mxwriter_startendelement_batch2(const struct writer_startendelement2_t *table) 3773 { 3774 int i = 0; 3775 3776 while (table->clsid) 3777 { 3778 ISAXContentHandler *content; 3779 IMXWriter *writer; 3780 HRESULT hr; 3781 3782 if (!is_clsid_supported(table->clsid, mxwriter_support_data)) 3783 { 3784 table++; 3785 i++; 3786 continue; 3787 } 3788 3789 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 3790 &IID_IMXWriter, (void**)&writer); 3791 EXPECT_HR(hr, S_OK); 3792 3793 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3794 EXPECT_HR(hr, S_OK); 3795 3796 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3797 EXPECT_HR(hr, S_OK); 3798 3799 hr = ISAXContentHandler_startDocument(content); 3800 EXPECT_HR(hr, S_OK); 3801 3802 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, 3803 _bstr_(table->qnamestart), table->qnamestart_len, NULL); 3804 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr); 3805 3806 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, 3807 _bstr_(table->qnameend), table->qnameend_len); 3808 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr); 3809 3810 /* test output */ 3811 if (hr == S_OK) 3812 { 3813 VARIANT dest; 3814 3815 V_VT(&dest) = VT_EMPTY; 3816 hr = IMXWriter_get_output(writer, &dest); 3817 EXPECT_HR(hr, S_OK); 3818 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3819 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)), 3820 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output); 3821 VariantClear(&dest); 3822 } 3823 3824 ISAXContentHandler_Release(content); 3825 IMXWriter_Release(writer); 3826 3827 table++; 3828 i++; 3829 3830 free_bstrs(); 3831 } 3832 } 3833 3834 3835 static void test_mxwriter_startendelement(void) 3836 { 3837 ISAXContentHandler *content; 3838 IMXWriter *writer; 3839 VARIANT dest; 3840 HRESULT hr; 3841 3842 test_mxwriter_startendelement_batch(writer_startendelement); 3843 test_mxwriter_startendelement_batch2(writer_startendelement2); 3844 3845 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3846 &IID_IMXWriter, (void**)&writer); 3847 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 3848 3849 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3850 ok(hr == S_OK, "got %08x\n", hr); 3851 3852 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3853 ok(hr == S_OK, "got %08x\n", hr); 3854 3855 hr = ISAXContentHandler_startDocument(content); 3856 ok(hr == S_OK, "got %08x\n", hr); 3857 3858 /* all string pointers should be not null */ 3859 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL); 3860 ok(hr == S_OK, "got %08x\n", hr); 3861 3862 V_VT(&dest) = VT_EMPTY; 3863 hr = IMXWriter_get_output(writer, &dest); 3864 ok(hr == S_OK, "got %08x\n", hr); 3865 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3866 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3867 VariantClear(&dest); 3868 3869 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL); 3870 ok(hr == S_OK, "got %08x\n", hr); 3871 3872 V_VT(&dest) = VT_EMPTY; 3873 hr = IMXWriter_get_output(writer, &dest); 3874 ok(hr == S_OK, "got %08x\n", hr); 3875 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3876 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3877 VariantClear(&dest); 3878 3879 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3); 3880 EXPECT_HR(hr, E_INVALIDARG); 3881 3882 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3); 3883 EXPECT_HR(hr, E_INVALIDARG); 3884 3885 /* only local name is an error too */ 3886 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0); 3887 EXPECT_HR(hr, E_INVALIDARG); 3888 3889 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1); 3890 EXPECT_HR(hr, S_OK); 3891 3892 V_VT(&dest) = VT_EMPTY; 3893 hr = IMXWriter_get_output(writer, &dest); 3894 EXPECT_HR(hr, S_OK); 3895 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3896 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3897 VariantClear(&dest); 3898 3899 hr = ISAXContentHandler_endDocument(content); 3900 EXPECT_HR(hr, S_OK); 3901 3902 V_VT(&dest) = VT_EMPTY; 3903 hr = IMXWriter_put_output(writer, dest); 3904 EXPECT_HR(hr, S_OK); 3905 3906 V_VT(&dest) = VT_EMPTY; 3907 hr = IMXWriter_get_output(writer, &dest); 3908 EXPECT_HR(hr, S_OK); 3909 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3910 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3911 VariantClear(&dest); 3912 3913 hr = ISAXContentHandler_startDocument(content); 3914 EXPECT_HR(hr, S_OK); 3915 3916 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL); 3917 EXPECT_HR(hr, S_OK); 3918 3919 V_VT(&dest) = VT_EMPTY; 3920 hr = IMXWriter_get_output(writer, &dest); 3921 EXPECT_HR(hr, S_OK); 3922 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3923 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3924 VariantClear(&dest); 3925 3926 hr = ISAXContentHandler_endDocument(content); 3927 EXPECT_HR(hr, S_OK); 3928 IMXWriter_flush(writer); 3929 3930 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3); 3931 EXPECT_HR(hr, S_OK); 3932 V_VT(&dest) = VT_EMPTY; 3933 hr = IMXWriter_get_output(writer, &dest); 3934 EXPECT_HR(hr, S_OK); 3935 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3936 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3937 VariantClear(&dest); 3938 3939 V_VT(&dest) = VT_EMPTY; 3940 hr = IMXWriter_put_output(writer, dest); 3941 EXPECT_HR(hr, S_OK); 3942 3943 /* length -1 */ 3944 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), -1, NULL); 3945 EXPECT_HR(hr, S_OK); 3946 V_VT(&dest) = VT_EMPTY; 3947 hr = IMXWriter_get_output(writer, &dest); 3948 EXPECT_HR(hr, S_OK); 3949 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 3950 ok(!lstrcmpW(_bstr_("<a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 3951 VariantClear(&dest); 3952 3953 ISAXContentHandler_Release(content); 3954 IMXWriter_Release(writer); 3955 free_bstrs(); 3956 } 3957 3958 struct writer_characters_t { 3959 const GUID *clsid; 3960 const char *data; 3961 const char *output; 3962 }; 3963 3964 static const struct writer_characters_t writer_characters[] = { 3965 { &CLSID_MXXMLWriter, "< > & \" \'", "< > & \" \'" }, 3966 { &CLSID_MXXMLWriter30, "< > & \" \'", "< > & \" \'" }, 3967 { &CLSID_MXXMLWriter40, "< > & \" \'", "< > & \" \'" }, 3968 { &CLSID_MXXMLWriter60, "< > & \" \'", "< > & \" \'" }, 3969 { NULL } 3970 }; 3971 3972 static void test_mxwriter_characters(void) 3973 { 3974 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0}; 3975 static const WCHAR embedded_nullbytes[] = {'a',0,'b',0,0,0,'c',0}; 3976 const struct writer_characters_t *table = writer_characters; 3977 IVBSAXContentHandler *vb_content; 3978 ISAXContentHandler *content; 3979 IMXWriter *writer; 3980 VARIANT dest; 3981 BSTR str; 3982 HRESULT hr; 3983 int i = 0; 3984 3985 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 3986 &IID_IMXWriter, (void**)&writer); 3987 EXPECT_HR(hr, S_OK); 3988 3989 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 3990 EXPECT_HR(hr, S_OK); 3991 3992 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXContentHandler, (void**)&vb_content); 3993 EXPECT_HR(hr, S_OK); 3994 3995 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 3996 EXPECT_HR(hr, S_OK); 3997 3998 hr = ISAXContentHandler_startDocument(content); 3999 EXPECT_HR(hr, S_OK); 4000 4001 hr = ISAXContentHandler_characters(content, NULL, 0); 4002 EXPECT_HR(hr, E_INVALIDARG); 4003 4004 hr = ISAXContentHandler_characters(content, chardataW, 0); 4005 EXPECT_HR(hr, S_OK); 4006 4007 str = _bstr_("VbChars"); 4008 hr = IVBSAXContentHandler_characters(vb_content, &str); 4009 EXPECT_HR(hr, S_OK); 4010 4011 hr = ISAXContentHandler_characters(content, chardataW, ARRAY_SIZE(chardataW) - 1); 4012 EXPECT_HR(hr, S_OK); 4013 4014 V_VT(&dest) = VT_EMPTY; 4015 hr = IMXWriter_get_output(writer, &dest); 4016 EXPECT_HR(hr, S_OK); 4017 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4018 ok(!lstrcmpW(_bstr_("VbCharsTESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4019 VariantClear(&dest); 4020 4021 hr = ISAXContentHandler_endDocument(content); 4022 EXPECT_HR(hr, S_OK); 4023 4024 ISAXContentHandler_Release(content); 4025 IVBSAXContentHandler_Release(vb_content); 4026 IMXWriter_Release(writer); 4027 4028 /* try empty characters data to see if element is closed */ 4029 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4030 &IID_IMXWriter, (void**)&writer); 4031 EXPECT_HR(hr, S_OK); 4032 4033 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4034 EXPECT_HR(hr, S_OK); 4035 4036 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4037 EXPECT_HR(hr, S_OK); 4038 4039 hr = ISAXContentHandler_startDocument(content); 4040 EXPECT_HR(hr, S_OK); 4041 4042 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL); 4043 EXPECT_HR(hr, S_OK); 4044 4045 hr = ISAXContentHandler_characters(content, chardataW, 0); 4046 EXPECT_HR(hr, S_OK); 4047 4048 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1); 4049 EXPECT_HR(hr, S_OK); 4050 4051 V_VT(&dest) = VT_EMPTY; 4052 hr = IMXWriter_get_output(writer, &dest); 4053 EXPECT_HR(hr, S_OK); 4054 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4055 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4056 VariantClear(&dest); 4057 4058 ISAXContentHandler_Release(content); 4059 IMXWriter_Release(writer); 4060 4061 /* test embedded null bytes */ 4062 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4063 &IID_IMXWriter, (void**)&writer); 4064 EXPECT_HR(hr, S_OK); 4065 4066 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4067 EXPECT_HR(hr, S_OK); 4068 4069 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4070 EXPECT_HR(hr, S_OK); 4071 4072 hr = ISAXContentHandler_startDocument(content); 4073 EXPECT_HR(hr, S_OK); 4074 4075 hr = ISAXContentHandler_characters(content, embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes)); 4076 EXPECT_HR(hr, S_OK); 4077 4078 V_VT(&dest) = VT_EMPTY; 4079 hr = IMXWriter_get_output(writer, &dest); 4080 EXPECT_HR(hr, S_OK); 4081 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4082 ok(SysStringLen(V_BSTR(&dest)) == ARRAY_SIZE(embedded_nullbytes), "unexpected len %d\n", SysStringLen(V_BSTR(&dest))); 4083 ok(!memcmp(V_BSTR(&dest), embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes)), 4084 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4085 VariantClear(&dest); 4086 4087 ISAXContentHandler_Release(content); 4088 IMXWriter_Release(writer); 4089 4090 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4091 &IID_IMXWriter, (void**)&writer); 4092 EXPECT_HR(hr, S_OK); 4093 4094 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXContentHandler, (void**)&vb_content); 4095 EXPECT_HR(hr, S_OK); 4096 4097 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4098 EXPECT_HR(hr, S_OK); 4099 4100 hr = IVBSAXContentHandler_startDocument(vb_content); 4101 EXPECT_HR(hr, S_OK); 4102 4103 str = SysAllocStringLen(embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes)); 4104 hr = IVBSAXContentHandler_characters(vb_content, &str); 4105 EXPECT_HR(hr, S_OK); 4106 SysFreeString(str); 4107 4108 V_VT(&dest) = VT_EMPTY; 4109 hr = IMXWriter_get_output(writer, &dest); 4110 EXPECT_HR(hr, S_OK); 4111 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4112 ok(SysStringLen(V_BSTR(&dest)) == ARRAY_SIZE(embedded_nullbytes), "unexpected len %d\n", SysStringLen(V_BSTR(&dest))); 4113 ok(!memcmp(V_BSTR(&dest), embedded_nullbytes, ARRAY_SIZE(embedded_nullbytes)), 4114 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4115 VariantClear(&dest); 4116 4117 IVBSAXContentHandler_Release(vb_content); 4118 IMXWriter_Release(writer); 4119 4120 /* batch tests */ 4121 while (table->clsid) 4122 { 4123 ISAXContentHandler *content; 4124 IMXWriter *writer; 4125 VARIANT dest; 4126 HRESULT hr; 4127 4128 if (!is_clsid_supported(table->clsid, mxwriter_support_data)) 4129 { 4130 table++; 4131 i++; 4132 continue; 4133 } 4134 4135 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 4136 &IID_IMXWriter, (void**)&writer); 4137 EXPECT_HR(hr, S_OK); 4138 4139 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4140 EXPECT_HR(hr, S_OK); 4141 4142 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4143 EXPECT_HR(hr, S_OK); 4144 4145 hr = ISAXContentHandler_startDocument(content); 4146 EXPECT_HR(hr, S_OK); 4147 4148 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data)); 4149 EXPECT_HR(hr, S_OK); 4150 4151 /* test output */ 4152 if (hr == S_OK) 4153 { 4154 V_VT(&dest) = VT_EMPTY; 4155 hr = IMXWriter_get_output(writer, &dest); 4156 EXPECT_HR(hr, S_OK); 4157 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4158 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)), 4159 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output); 4160 VariantClear(&dest); 4161 } 4162 4163 /* with disabled escaping */ 4164 V_VT(&dest) = VT_EMPTY; 4165 hr = IMXWriter_put_output(writer, dest); 4166 EXPECT_HR(hr, S_OK); 4167 4168 hr = IMXWriter_put_disableOutputEscaping(writer, VARIANT_TRUE); 4169 EXPECT_HR(hr, S_OK); 4170 4171 hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data)); 4172 EXPECT_HR(hr, S_OK); 4173 4174 /* test output */ 4175 if (hr == S_OK) 4176 { 4177 V_VT(&dest) = VT_EMPTY; 4178 hr = IMXWriter_get_output(writer, &dest); 4179 EXPECT_HR(hr, S_OK); 4180 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4181 ok(!lstrcmpW(_bstr_(table->data), V_BSTR(&dest)), 4182 "test %d: got wrong content %s, expected \"%s\"\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->data); 4183 VariantClear(&dest); 4184 } 4185 4186 ISAXContentHandler_Release(content); 4187 IMXWriter_Release(writer); 4188 4189 table++; 4190 i++; 4191 } 4192 4193 free_bstrs(); 4194 } 4195 4196 static const mxwriter_stream_test mxwriter_stream_tests[] = { 4197 { 4198 VARIANT_TRUE,"UTF-16", 4199 { 4200 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE}, 4201 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)}, 4202 {TRUE} 4203 } 4204 }, 4205 { 4206 VARIANT_FALSE,"UTF-16", 4207 { 4208 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)}, 4209 {TRUE} 4210 } 4211 }, 4212 { 4213 VARIANT_TRUE,"UTF-8", 4214 { 4215 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1}, 4216 /* For some reason Windows makes an empty write call when UTF-8 encoding is used 4217 * and the writer is released. 4218 */ 4219 {FALSE,NULL,0}, 4220 {TRUE} 4221 } 4222 }, 4223 { 4224 VARIANT_TRUE,"utf-8", 4225 { 4226 {FALSE,(const BYTE*)utf8xml2,sizeof(utf8xml2)-1}, 4227 /* For some reason Windows makes an empty write call when UTF-8 encoding is used 4228 * and the writer is released. 4229 */ 4230 {FALSE,NULL,0}, 4231 {TRUE} 4232 } 4233 }, 4234 { 4235 VARIANT_TRUE,"UTF-16", 4236 { 4237 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE}, 4238 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)}, 4239 {TRUE} 4240 } 4241 }, 4242 { 4243 VARIANT_TRUE,"UTF-16", 4244 { 4245 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE}, 4246 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)}, 4247 {TRUE} 4248 } 4249 } 4250 }; 4251 4252 static void test_mxwriter_stream(void) 4253 { 4254 IMXWriter *writer; 4255 ISAXContentHandler *content; 4256 HRESULT hr; 4257 VARIANT dest; 4258 IStream *stream; 4259 LARGE_INTEGER pos; 4260 ULARGE_INTEGER pos2; 4261 DWORD test_count = ARRAY_SIZE(mxwriter_stream_tests); 4262 4263 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) { 4264 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index; 4265 4266 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4267 &IID_IMXWriter, (void**)&writer); 4268 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr); 4269 4270 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4271 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr); 4272 4273 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding)); 4274 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index); 4275 4276 V_VT(&dest) = VT_UNKNOWN; 4277 V_UNKNOWN(&dest) = (IUnknown*)&mxstream; 4278 hr = IMXWriter_put_output(writer, dest); 4279 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index); 4280 4281 hr = IMXWriter_put_byteOrderMark(writer, test->bom); 4282 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index); 4283 4284 current_write_test = test->expected_writes; 4285 4286 hr = ISAXContentHandler_startDocument(content); 4287 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index); 4288 4289 hr = ISAXContentHandler_endDocument(content); 4290 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index); 4291 4292 ISAXContentHandler_Release(content); 4293 IMXWriter_Release(writer); 4294 4295 ok(current_write_test->last, "The last %d write calls on test %d were missed\n", 4296 (int)(current_write_test-test->expected_writes), current_stream_test_index); 4297 } 4298 4299 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4300 &IID_IMXWriter, (void**)&writer); 4301 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr); 4302 4303 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 4304 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr); 4305 4306 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4307 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr); 4308 4309 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8")); 4310 ok(hr == S_OK, "put_encoding failed: %08x\n", hr); 4311 4312 V_VT(&dest) = VT_UNKNOWN; 4313 V_UNKNOWN(&dest) = (IUnknown*)stream; 4314 hr = IMXWriter_put_output(writer, dest); 4315 ok(hr == S_OK, "put_output failed: %08x\n", hr); 4316 4317 hr = ISAXContentHandler_startDocument(content); 4318 ok(hr == S_OK, "startDocument failed: %08x\n", hr); 4319 4320 /* Setting output of the mxwriter causes the current output to be flushed, 4321 * and the writer to start over. 4322 */ 4323 V_VT(&dest) = VT_EMPTY; 4324 hr = IMXWriter_put_output(writer, dest); 4325 ok(hr == S_OK, "put_output failed: %08x\n", hr); 4326 4327 pos.QuadPart = 0; 4328 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 4329 ok(hr == S_OK, "Seek failed: %08x\n", hr); 4330 ok(pos2.QuadPart != 0, "expected stream position moved\n"); 4331 4332 hr = ISAXContentHandler_startDocument(content); 4333 ok(hr == S_OK, "startDocument failed: %08x\n", hr); 4334 4335 hr = ISAXContentHandler_endDocument(content); 4336 ok(hr == S_OK, "endDocument failed: %08x\n", hr); 4337 4338 V_VT(&dest) = VT_EMPTY; 4339 hr = IMXWriter_get_output(writer, &dest); 4340 ok(hr == S_OK, "get_output failed: %08x\n", hr); 4341 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest)); 4342 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)), 4343 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4344 VariantClear(&dest); 4345 4346 /* test when BOM is written to output stream */ 4347 V_VT(&dest) = VT_EMPTY; 4348 hr = IMXWriter_put_output(writer, dest); 4349 EXPECT_HR(hr, S_OK); 4350 4351 pos.QuadPart = 0; 4352 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL); 4353 EXPECT_HR(hr, S_OK); 4354 4355 V_VT(&dest) = VT_UNKNOWN; 4356 V_UNKNOWN(&dest) = (IUnknown*)stream; 4357 hr = IMXWriter_put_output(writer, dest); 4358 EXPECT_HR(hr, S_OK); 4359 4360 hr = IMXWriter_put_byteOrderMark(writer, VARIANT_TRUE); 4361 EXPECT_HR(hr, S_OK); 4362 4363 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16")); 4364 EXPECT_HR(hr, S_OK); 4365 4366 hr = ISAXContentHandler_startDocument(content); 4367 EXPECT_HR(hr, S_OK); 4368 4369 pos.QuadPart = 0; 4370 pos2.QuadPart = 0; 4371 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2); 4372 EXPECT_HR(hr, S_OK); 4373 ok(pos2.QuadPart == 2, "got wrong position\n"); 4374 4375 IStream_Release(stream); 4376 ISAXContentHandler_Release(content); 4377 IMXWriter_Release(writer); 4378 4379 free_bstrs(); 4380 } 4381 4382 static const char *encoding_names[] = { 4383 "iso-8859-1", 4384 "iso-8859-2", 4385 "iso-8859-3", 4386 "iso-8859-4", 4387 "iso-8859-5", 4388 "iso-8859-7", 4389 "iso-8859-9", 4390 "iso-8859-13", 4391 "iso-8859-15", 4392 NULL 4393 }; 4394 4395 static void test_mxwriter_encoding(void) 4396 { 4397 ISAXContentHandler *content; 4398 IMXWriter *writer; 4399 IStream *stream; 4400 const char *enc; 4401 VARIANT dest; 4402 HRESULT hr; 4403 HGLOBAL g; 4404 char *ptr; 4405 BSTR s; 4406 int i; 4407 4408 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4409 &IID_IMXWriter, (void**)&writer); 4410 EXPECT_HR(hr, S_OK); 4411 4412 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4413 EXPECT_HR(hr, S_OK); 4414 4415 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8")); 4416 EXPECT_HR(hr, S_OK); 4417 4418 hr = ISAXContentHandler_startDocument(content); 4419 EXPECT_HR(hr, S_OK); 4420 4421 hr = ISAXContentHandler_endDocument(content); 4422 EXPECT_HR(hr, S_OK); 4423 4424 /* The content is always re-encoded to UTF-16 when the output is 4425 * retrieved as a BSTR. 4426 */ 4427 V_VT(&dest) = VT_EMPTY; 4428 hr = IMXWriter_get_output(writer, &dest); 4429 EXPECT_HR(hr, S_OK); 4430 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest)); 4431 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)), 4432 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4433 VariantClear(&dest); 4434 4435 /* switch encoding when something is written already */ 4436 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 4437 EXPECT_HR(hr, S_OK); 4438 4439 V_VT(&dest) = VT_UNKNOWN; 4440 V_UNKNOWN(&dest) = (IUnknown*)stream; 4441 hr = IMXWriter_put_output(writer, dest); 4442 EXPECT_HR(hr, S_OK); 4443 4444 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8")); 4445 EXPECT_HR(hr, S_OK); 4446 4447 /* write empty element */ 4448 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL); 4449 EXPECT_HR(hr, S_OK); 4450 4451 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1); 4452 EXPECT_HR(hr, S_OK); 4453 4454 /* switch */ 4455 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-16")); 4456 EXPECT_HR(hr, S_OK); 4457 4458 hr = IMXWriter_flush(writer); 4459 EXPECT_HR(hr, S_OK); 4460 4461 hr = GetHGlobalFromStream(stream, &g); 4462 EXPECT_HR(hr, S_OK); 4463 4464 ptr = GlobalLock(g); 4465 ok(!strncmp(ptr, "<a/>", 4), "got %c%c%c%c\n", ptr[0],ptr[1],ptr[2],ptr[3]); 4466 GlobalUnlock(g); 4467 4468 /* so output is unaffected, encoding name is stored however */ 4469 hr = IMXWriter_get_encoding(writer, &s); 4470 EXPECT_HR(hr, S_OK); 4471 ok(!lstrcmpW(s, _bstr_("UTF-16")), "got %s\n", wine_dbgstr_w(s)); 4472 SysFreeString(s); 4473 4474 IStream_Release(stream); 4475 4476 i = 0; 4477 enc = encoding_names[i]; 4478 while (enc) 4479 { 4480 char expectedA[200]; 4481 4482 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 4483 EXPECT_HR(hr, S_OK); 4484 4485 V_VT(&dest) = VT_UNKNOWN; 4486 V_UNKNOWN(&dest) = (IUnknown*)stream; 4487 hr = IMXWriter_put_output(writer, dest); 4488 EXPECT_HR(hr, S_OK); 4489 4490 hr = IMXWriter_put_encoding(writer, _bstr_(enc)); 4491 ok(hr == S_OK || broken(hr != S_OK) /* old win versions do not support certain encodings */, 4492 "%s: encoding not accepted\n", enc); 4493 if (hr != S_OK) 4494 { 4495 enc = encoding_names[++i]; 4496 IStream_Release(stream); 4497 continue; 4498 } 4499 4500 hr = ISAXContentHandler_startDocument(content); 4501 EXPECT_HR(hr, S_OK); 4502 4503 hr = ISAXContentHandler_endDocument(content); 4504 EXPECT_HR(hr, S_OK); 4505 4506 hr = IMXWriter_flush(writer); 4507 EXPECT_HR(hr, S_OK); 4508 4509 /* prepare expected string */ 4510 *expectedA = 0; 4511 strcat(expectedA, "<?xml version=\"1.0\" encoding=\""); 4512 strcat(expectedA, enc); 4513 strcat(expectedA, "\" standalone=\"no\"?>\r\n"); 4514 4515 hr = GetHGlobalFromStream(stream, &g); 4516 EXPECT_HR(hr, S_OK); 4517 4518 ptr = GlobalLock(g); 4519 ok(!strncmp(ptr, expectedA, strlen(expectedA)), "%s: got %s, expected %.50s\n", enc, ptr, expectedA); 4520 GlobalUnlock(g); 4521 4522 V_VT(&dest) = VT_EMPTY; 4523 hr = IMXWriter_put_output(writer, dest); 4524 EXPECT_HR(hr, S_OK); 4525 4526 IStream_Release(stream); 4527 4528 enc = encoding_names[++i]; 4529 } 4530 4531 ISAXContentHandler_Release(content); 4532 IMXWriter_Release(writer); 4533 4534 free_bstrs(); 4535 } 4536 4537 static void test_obj_dispex(IUnknown *obj) 4538 { 4539 static const WCHAR testW[] = {'t','e','s','t','p','r','o','p',0}; 4540 static const WCHAR starW[] = {'*',0}; 4541 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE; 4542 IDispatchEx *dispex; 4543 IUnknown *unk; 4544 DWORD props; 4545 UINT ticnt; 4546 HRESULT hr; 4547 BSTR name; 4548 DISPID did; 4549 4550 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex); 4551 EXPECT_HR(hr, S_OK); 4552 if (FAILED(hr)) return; 4553 4554 ticnt = 0; 4555 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt); 4556 EXPECT_HR(hr, S_OK); 4557 ok(ticnt == 1, "ticnt=%u\n", ticnt); 4558 4559 name = SysAllocString(starW); 4560 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive); 4561 EXPECT_HR(hr, E_NOTIMPL); 4562 SysFreeString(name); 4563 4564 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid); 4565 EXPECT_HR(hr, E_NOTIMPL); 4566 4567 props = 0; 4568 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props); 4569 EXPECT_HR(hr, E_NOTIMPL); 4570 ok(props == 0, "expected 0 got %d\n", props); 4571 4572 hr = IDispatchEx_GetMemberName(dispex, dispid, &name); 4573 EXPECT_HR(hr, E_NOTIMPL); 4574 if (SUCCEEDED(hr)) SysFreeString(name); 4575 4576 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid); 4577 EXPECT_HR(hr, E_NOTIMPL); 4578 4579 unk = (IUnknown*)0xdeadbeef; 4580 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk); 4581 EXPECT_HR(hr, E_NOTIMPL); 4582 ok(unk == (IUnknown*)0xdeadbeef, "got %p\n", unk); 4583 4584 name = SysAllocString(testW); 4585 hr = IDispatchEx_GetDispID(dispex, name, fdexNameEnsure, &did); 4586 ok(hr == DISP_E_UNKNOWNNAME, "got 0x%08x\n", hr); 4587 SysFreeString(name); 4588 4589 IDispatchEx_Release(dispex); 4590 } 4591 4592 static void test_saxreader_dispex(void) 4593 { 4594 IVBSAXXMLReader *vbreader; 4595 ISAXXMLReader *reader; 4596 DISPPARAMS dispparams; 4597 DISPID dispid; 4598 IUnknown *unk; 4599 VARIANT arg; 4600 HRESULT hr; 4601 4602 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER, 4603 &IID_ISAXXMLReader, (void**)&reader); 4604 EXPECT_HR(hr, S_OK); 4605 4606 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk); 4607 EXPECT_HR(hr, S_OK); 4608 test_obj_dispex(unk); 4609 IUnknown_Release(unk); 4610 4611 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader); 4612 EXPECT_HR(hr, S_OK); 4613 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk); 4614 EXPECT_HR(hr, S_OK); 4615 test_obj_dispex(unk); 4616 IUnknown_Release(unk); 4617 4618 dispid = DISPID_PROPERTYPUT; 4619 dispparams.cArgs = 1; 4620 dispparams.cNamedArgs = 1; 4621 dispparams.rgdispidNamedArgs = &dispid; 4622 dispparams.rgvarg = &arg; 4623 4624 V_VT(&arg) = VT_DISPATCH; 4625 V_DISPATCH(&arg) = NULL; 4626 4627 /* propputref is callable as PROPERTYPUT and PROPERTYPUTREF */ 4628 hr = IVBSAXXMLReader_Invoke(vbreader, 4629 DISPID_SAX_XMLREADER_CONTENTHANDLER, 4630 &IID_NULL, 4631 0, 4632 DISPATCH_PROPERTYPUT, 4633 &dispparams, 4634 NULL, 4635 NULL, 4636 NULL); 4637 ok(hr == S_OK, "got 0x%08x\n", hr); 4638 4639 hr = IVBSAXXMLReader_Invoke(vbreader, 4640 DISPID_SAX_XMLREADER_CONTENTHANDLER, 4641 &IID_NULL, 4642 0, 4643 DISPATCH_PROPERTYPUTREF, 4644 &dispparams, 4645 NULL, 4646 NULL, 4647 NULL); 4648 ok(hr == S_OK, "got 0x%08x\n", hr); 4649 4650 IVBSAXXMLReader_Release(vbreader); 4651 ISAXXMLReader_Release(reader); 4652 4653 if (is_clsid_supported(&CLSID_SAXXMLReader60, reader_support_data)) 4654 { 4655 hr = CoCreateInstance(&CLSID_SAXXMLReader60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); 4656 ok(hr == S_OK, "got 0x%08x\n", hr); 4657 test_obj_dispex(unk); 4658 IUnknown_Release(unk); 4659 } 4660 } 4661 4662 static void test_mxwriter_dispex(void) 4663 { 4664 IDispatchEx *dispex; 4665 IMXWriter *writer; 4666 IUnknown *unk; 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_IDispatchEx, (void**)&dispex); 4674 EXPECT_HR(hr, S_OK); 4675 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk); 4676 test_obj_dispex(unk); 4677 IUnknown_Release(unk); 4678 IDispatchEx_Release(dispex); 4679 IMXWriter_Release(writer); 4680 4681 if (is_clsid_supported(&CLSID_MXXMLWriter60, mxwriter_support_data)) 4682 { 4683 hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); 4684 ok(hr == S_OK, "got 0x%08x\n", hr); 4685 test_obj_dispex(unk); 4686 IUnknown_Release(unk); 4687 } 4688 } 4689 4690 static void test_mxwriter_comment(void) 4691 { 4692 static const WCHAR commentW[] = {'c','o','m','m','e','n','t',0}; 4693 IVBSAXLexicalHandler *vblexical; 4694 ISAXContentHandler *content; 4695 ISAXLexicalHandler *lexical; 4696 IMXWriter *writer; 4697 VARIANT dest; 4698 HRESULT hr; 4699 4700 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4701 &IID_IMXWriter, (void**)&writer); 4702 EXPECT_HR(hr, S_OK); 4703 4704 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4705 EXPECT_HR(hr, S_OK); 4706 4707 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical); 4708 EXPECT_HR(hr, S_OK); 4709 4710 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical); 4711 EXPECT_HR(hr, S_OK); 4712 4713 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4714 EXPECT_HR(hr, S_OK); 4715 4716 hr = ISAXContentHandler_startDocument(content); 4717 EXPECT_HR(hr, S_OK); 4718 4719 hr = ISAXLexicalHandler_comment(lexical, NULL, 0); 4720 EXPECT_HR(hr, E_INVALIDARG); 4721 4722 hr = IVBSAXLexicalHandler_comment(vblexical, NULL); 4723 EXPECT_HR(hr, E_POINTER); 4724 4725 hr = ISAXLexicalHandler_comment(lexical, commentW, 0); 4726 EXPECT_HR(hr, S_OK); 4727 4728 V_VT(&dest) = VT_EMPTY; 4729 hr = IMXWriter_get_output(writer, &dest); 4730 EXPECT_HR(hr, S_OK); 4731 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4732 ok(!lstrcmpW(_bstr_("<!---->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4733 VariantClear(&dest); 4734 4735 hr = ISAXLexicalHandler_comment(lexical, commentW, ARRAY_SIZE(commentW) - 1); 4736 EXPECT_HR(hr, S_OK); 4737 4738 V_VT(&dest) = VT_EMPTY; 4739 hr = IMXWriter_get_output(writer, &dest); 4740 EXPECT_HR(hr, S_OK); 4741 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4742 ok(!lstrcmpW(_bstr_("<!---->\r\n<!--comment-->\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4743 VariantClear(&dest); 4744 4745 ISAXContentHandler_Release(content); 4746 ISAXLexicalHandler_Release(lexical); 4747 IVBSAXLexicalHandler_Release(vblexical); 4748 IMXWriter_Release(writer); 4749 free_bstrs(); 4750 } 4751 4752 static void test_mxwriter_cdata(void) 4753 { 4754 IVBSAXLexicalHandler *vblexical; 4755 ISAXContentHandler *content; 4756 ISAXLexicalHandler *lexical; 4757 IMXWriter *writer; 4758 VARIANT dest; 4759 HRESULT hr; 4760 4761 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4762 &IID_IMXWriter, (void**)&writer); 4763 EXPECT_HR(hr, S_OK); 4764 4765 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4766 EXPECT_HR(hr, S_OK); 4767 4768 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical); 4769 EXPECT_HR(hr, S_OK); 4770 4771 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical); 4772 EXPECT_HR(hr, S_OK); 4773 4774 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4775 EXPECT_HR(hr, S_OK); 4776 4777 hr = ISAXContentHandler_startDocument(content); 4778 EXPECT_HR(hr, S_OK); 4779 4780 hr = ISAXLexicalHandler_startCDATA(lexical); 4781 EXPECT_HR(hr, S_OK); 4782 4783 V_VT(&dest) = VT_EMPTY; 4784 hr = IMXWriter_get_output(writer, &dest); 4785 EXPECT_HR(hr, S_OK); 4786 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4787 ok(!lstrcmpW(_bstr_("<![CDATA["), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4788 VariantClear(&dest); 4789 4790 hr = IVBSAXLexicalHandler_startCDATA(vblexical); 4791 EXPECT_HR(hr, S_OK); 4792 4793 /* all these are escaped for text nodes */ 4794 hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7); 4795 EXPECT_HR(hr, S_OK); 4796 4797 hr = ISAXLexicalHandler_endCDATA(lexical); 4798 EXPECT_HR(hr, S_OK); 4799 4800 V_VT(&dest) = VT_EMPTY; 4801 hr = IMXWriter_get_output(writer, &dest); 4802 EXPECT_HR(hr, S_OK); 4803 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4804 ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4805 VariantClear(&dest); 4806 4807 ISAXContentHandler_Release(content); 4808 ISAXLexicalHandler_Release(lexical); 4809 IVBSAXLexicalHandler_Release(vblexical); 4810 IMXWriter_Release(writer); 4811 free_bstrs(); 4812 } 4813 4814 static void test_mxwriter_pi(void) 4815 { 4816 static const WCHAR targetW[] = {'t','a','r','g','e','t',0}; 4817 static const WCHAR dataW[] = {'d','a','t','a',0}; 4818 ISAXContentHandler *content; 4819 IMXWriter *writer; 4820 VARIANT dest; 4821 HRESULT hr; 4822 4823 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4824 &IID_IMXWriter, (void**)&writer); 4825 EXPECT_HR(hr, S_OK); 4826 4827 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4828 EXPECT_HR(hr, S_OK); 4829 4830 hr = ISAXContentHandler_processingInstruction(content, NULL, 0, NULL, 0); 4831 EXPECT_HR(hr, E_INVALIDARG); 4832 4833 hr = ISAXContentHandler_processingInstruction(content, targetW, 0, NULL, 0); 4834 EXPECT_HR(hr, S_OK); 4835 4836 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, NULL, 0); 4837 EXPECT_HR(hr, S_OK); 4838 4839 V_VT(&dest) = VT_EMPTY; 4840 hr = IMXWriter_get_output(writer, &dest); 4841 EXPECT_HR(hr, S_OK); 4842 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4843 ok(!lstrcmpW(_bstr_("<?\?>\r\n<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4844 VariantClear(&dest); 4845 4846 hr = ISAXContentHandler_processingInstruction(content, targetW, 4, dataW, 4); 4847 EXPECT_HR(hr, S_OK); 4848 4849 V_VT(&dest) = VT_EMPTY; 4850 hr = IMXWriter_get_output(writer, &dest); 4851 EXPECT_HR(hr, S_OK); 4852 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4853 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))); 4854 VariantClear(&dest); 4855 4856 V_VT(&dest) = VT_EMPTY; 4857 hr = IMXWriter_put_output(writer, dest); 4858 EXPECT_HR(hr, S_OK); 4859 4860 hr = ISAXContentHandler_processingInstruction(content, targetW, 6, dataW, 0); 4861 EXPECT_HR(hr, S_OK); 4862 4863 V_VT(&dest) = VT_EMPTY; 4864 hr = IMXWriter_get_output(writer, &dest); 4865 EXPECT_HR(hr, S_OK); 4866 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4867 ok(!lstrcmpW(_bstr_("<?target?>\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4868 VariantClear(&dest); 4869 4870 4871 ISAXContentHandler_Release(content); 4872 IMXWriter_Release(writer); 4873 } 4874 4875 static void test_mxwriter_ignorablespaces(void) 4876 { 4877 static const WCHAR dataW[] = {'d','a','t','a',0}; 4878 ISAXContentHandler *content; 4879 IMXWriter *writer; 4880 VARIANT dest; 4881 HRESULT hr; 4882 4883 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4884 &IID_IMXWriter, (void**)&writer); 4885 EXPECT_HR(hr, S_OK); 4886 4887 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4888 EXPECT_HR(hr, S_OK); 4889 4890 hr = ISAXContentHandler_ignorableWhitespace(content, NULL, 0); 4891 EXPECT_HR(hr, E_INVALIDARG); 4892 4893 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 0); 4894 EXPECT_HR(hr, S_OK); 4895 4896 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 4); 4897 EXPECT_HR(hr, S_OK); 4898 4899 hr = ISAXContentHandler_ignorableWhitespace(content, dataW, 1); 4900 EXPECT_HR(hr, S_OK); 4901 4902 V_VT(&dest) = VT_EMPTY; 4903 hr = IMXWriter_get_output(writer, &dest); 4904 EXPECT_HR(hr, S_OK); 4905 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4906 ok(!lstrcmpW(_bstr_("datad"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4907 VariantClear(&dest); 4908 4909 ISAXContentHandler_Release(content); 4910 IMXWriter_Release(writer); 4911 } 4912 4913 static void test_mxwriter_dtd(void) 4914 { 4915 static const WCHAR contentW[] = {'c','o','n','t','e','n','t'}; 4916 static const WCHAR nameW[] = {'n','a','m','e'}; 4917 static const WCHAR pubW[] = {'p','u','b'}; 4918 static const WCHAR sysW[] = {'s','y','s'}; 4919 IVBSAXLexicalHandler *vblexical; 4920 ISAXContentHandler *content; 4921 ISAXLexicalHandler *lexical; 4922 IVBSAXDeclHandler *vbdecl; 4923 ISAXDeclHandler *decl; 4924 ISAXDTDHandler *dtd; 4925 IMXWriter *writer; 4926 VARIANT dest; 4927 HRESULT hr; 4928 4929 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, 4930 &IID_IMXWriter, (void**)&writer); 4931 EXPECT_HR(hr, S_OK); 4932 4933 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 4934 EXPECT_HR(hr, S_OK); 4935 4936 hr = IMXWriter_QueryInterface(writer, &IID_ISAXLexicalHandler, (void**)&lexical); 4937 EXPECT_HR(hr, S_OK); 4938 4939 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDeclHandler, (void**)&decl); 4940 EXPECT_HR(hr, S_OK); 4941 4942 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXDeclHandler, (void**)&vbdecl); 4943 EXPECT_HR(hr, S_OK); 4944 4945 hr = IMXWriter_QueryInterface(writer, &IID_IVBSAXLexicalHandler, (void**)&vblexical); 4946 EXPECT_HR(hr, S_OK); 4947 4948 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE); 4949 EXPECT_HR(hr, S_OK); 4950 4951 hr = ISAXContentHandler_startDocument(content); 4952 EXPECT_HR(hr, S_OK); 4953 4954 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, NULL, 0); 4955 EXPECT_HR(hr, E_INVALIDARG); 4956 4957 hr = IVBSAXLexicalHandler_startDTD(vblexical, NULL, NULL, NULL); 4958 EXPECT_HR(hr, E_POINTER); 4959 4960 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, ARRAY_SIZE(pubW), NULL, 0); 4961 EXPECT_HR(hr, E_INVALIDARG); 4962 4963 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, NULL, 0, sysW, ARRAY_SIZE(sysW)); 4964 EXPECT_HR(hr, E_INVALIDARG); 4965 4966 hr = ISAXLexicalHandler_startDTD(lexical, NULL, 0, pubW, ARRAY_SIZE(pubW), sysW, ARRAY_SIZE(sysW)); 4967 EXPECT_HR(hr, E_INVALIDARG); 4968 4969 hr = ISAXLexicalHandler_startDTD(lexical, nameW, ARRAY_SIZE(nameW), NULL, 0, NULL, 0); 4970 EXPECT_HR(hr, S_OK); 4971 4972 V_VT(&dest) = VT_EMPTY; 4973 hr = IMXWriter_get_output(writer, &dest); 4974 EXPECT_HR(hr, S_OK); 4975 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4976 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4977 VariantClear(&dest); 4978 4979 /* system id is required if public is present */ 4980 hr = ISAXLexicalHandler_startDTD(lexical, nameW, ARRAY_SIZE(nameW), pubW, ARRAY_SIZE(pubW), NULL, 0); 4981 EXPECT_HR(hr, E_INVALIDARG); 4982 4983 hr = ISAXLexicalHandler_startDTD(lexical, nameW, ARRAY_SIZE(nameW), 4984 pubW, ARRAY_SIZE(pubW), sysW, ARRAY_SIZE(sysW)); 4985 EXPECT_HR(hr, S_OK); 4986 4987 V_VT(&dest) = VT_EMPTY; 4988 hr = IMXWriter_get_output(writer, &dest); 4989 EXPECT_HR(hr, S_OK); 4990 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 4991 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\"" 4992 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 4993 VariantClear(&dest); 4994 4995 hr = ISAXLexicalHandler_endDTD(lexical); 4996 EXPECT_HR(hr, S_OK); 4997 4998 hr = IVBSAXLexicalHandler_endDTD(vblexical); 4999 EXPECT_HR(hr, S_OK); 5000 5001 V_VT(&dest) = VT_EMPTY; 5002 hr = IMXWriter_get_output(writer, &dest); 5003 EXPECT_HR(hr, S_OK); 5004 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5005 ok(!lstrcmpW(_bstr_("<!DOCTYPE name [\r\n<!DOCTYPE name PUBLIC \"pub\"" 5006 "<!DOCTYPE name PUBLIC \"pub\" \"sys\" [\r\n]>\r\n]>\r\n"), 5007 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5008 VariantClear(&dest); 5009 5010 /* element declaration */ 5011 V_VT(&dest) = VT_EMPTY; 5012 hr = IMXWriter_put_output(writer, dest); 5013 EXPECT_HR(hr, S_OK); 5014 5015 hr = ISAXDeclHandler_elementDecl(decl, NULL, 0, NULL, 0); 5016 EXPECT_HR(hr, E_INVALIDARG); 5017 5018 hr = IVBSAXDeclHandler_elementDecl(vbdecl, NULL, NULL); 5019 EXPECT_HR(hr, E_POINTER); 5020 5021 hr = ISAXDeclHandler_elementDecl(decl, nameW, ARRAY_SIZE(nameW), NULL, 0); 5022 EXPECT_HR(hr, E_INVALIDARG); 5023 5024 hr = ISAXDeclHandler_elementDecl(decl, nameW, ARRAY_SIZE(nameW), contentW, ARRAY_SIZE(contentW)); 5025 EXPECT_HR(hr, S_OK); 5026 5027 V_VT(&dest) = VT_EMPTY; 5028 hr = IMXWriter_get_output(writer, &dest); 5029 EXPECT_HR(hr, S_OK); 5030 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5031 ok(!lstrcmpW(_bstr_("<!ELEMENT name content>\r\n"), 5032 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5033 VariantClear(&dest); 5034 5035 V_VT(&dest) = VT_EMPTY; 5036 hr = IMXWriter_put_output(writer, dest); 5037 EXPECT_HR(hr, S_OK); 5038 5039 hr = ISAXDeclHandler_elementDecl(decl, nameW, ARRAY_SIZE(nameW), contentW, 0); 5040 EXPECT_HR(hr, S_OK); 5041 5042 V_VT(&dest) = VT_EMPTY; 5043 hr = IMXWriter_get_output(writer, &dest); 5044 EXPECT_HR(hr, S_OK); 5045 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5046 ok(!lstrcmpW(_bstr_("<!ELEMENT name >\r\n"), 5047 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5048 VariantClear(&dest); 5049 5050 /* attribute declaration */ 5051 V_VT(&dest) = VT_EMPTY; 5052 hr = IMXWriter_put_output(writer, dest); 5053 EXPECT_HR(hr, S_OK); 5054 5055 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"), 5056 _bstr_("attribute"), strlen("attribute"), _bstr_("CDATA"), strlen("CDATA"), 5057 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value"), strlen("value")); 5058 EXPECT_HR(hr, S_OK); 5059 5060 V_VT(&dest) = VT_EMPTY; 5061 hr = IMXWriter_get_output(writer, &dest); 5062 EXPECT_HR(hr, S_OK); 5063 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5064 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n"), 5065 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5066 VariantClear(&dest); 5067 5068 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element"), strlen("element"), 5069 _bstr_("attribute2"), strlen("attribute2"), _bstr_("CDATA"), strlen("CDATA"), 5070 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value2"), strlen("value2")); 5071 EXPECT_HR(hr, S_OK); 5072 5073 hr = ISAXDeclHandler_attributeDecl(decl, _bstr_("element2"), strlen("element2"), 5074 _bstr_("attribute3"), strlen("attribute3"), _bstr_("CDATA"), strlen("CDATA"), 5075 _bstr_("#REQUIRED"), strlen("#REQUIRED"), _bstr_("value3"), strlen("value3")); 5076 EXPECT_HR(hr, S_OK); 5077 5078 V_VT(&dest) = VT_EMPTY; 5079 hr = IMXWriter_get_output(writer, &dest); 5080 EXPECT_HR(hr, S_OK); 5081 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5082 ok(!lstrcmpW(_bstr_("<!ATTLIST element attribute CDATA #REQUIRED \"value\">\r\n" 5083 "<!ATTLIST element attribute2 CDATA #REQUIRED \"value2\">\r\n" 5084 "<!ATTLIST element2 attribute3 CDATA #REQUIRED \"value3\">\r\n"), 5085 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5086 VariantClear(&dest); 5087 5088 /* internal entities */ 5089 V_VT(&dest) = VT_EMPTY; 5090 hr = IMXWriter_put_output(writer, dest); 5091 EXPECT_HR(hr, S_OK); 5092 5093 hr = ISAXDeclHandler_internalEntityDecl(decl, NULL, 0, NULL, 0); 5094 EXPECT_HR(hr, E_INVALIDARG); 5095 5096 hr = IVBSAXDeclHandler_internalEntityDecl(vbdecl, NULL, NULL); 5097 EXPECT_HR(hr, E_POINTER); 5098 5099 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), -1, NULL, 0); 5100 EXPECT_HR(hr, E_INVALIDARG); 5101 5102 hr = ISAXDeclHandler_internalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("value"), strlen("value")); 5103 EXPECT_HR(hr, S_OK); 5104 5105 V_VT(&dest) = VT_EMPTY; 5106 hr = IMXWriter_get_output(writer, &dest); 5107 EXPECT_HR(hr, S_OK); 5108 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5109 ok(!lstrcmpW(_bstr_("<!ENTITY name \"value\">\r\n"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5110 VariantClear(&dest); 5111 5112 /* external entities */ 5113 V_VT(&dest) = VT_EMPTY; 5114 hr = IMXWriter_put_output(writer, dest); 5115 ok(hr == S_OK, "got 0x%08x\n", hr); 5116 5117 hr = ISAXDeclHandler_externalEntityDecl(decl, NULL, 0, NULL, 0, NULL, 0); 5118 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5119 5120 hr = IVBSAXDeclHandler_externalEntityDecl(vbdecl, NULL, NULL, NULL); 5121 ok(hr == E_POINTER, "got 0x%08x\n", hr); 5122 5123 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), 0, NULL, 0, NULL, 0); 5124 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5125 5126 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), -1, NULL, 0, NULL, 0); 5127 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5128 5129 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"), 5130 _bstr_("sysid"), strlen("sysid")); 5131 ok(hr == S_OK, "got 0x%08x\n", hr); 5132 5133 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), NULL, 0, _bstr_("sysid"), strlen("sysid")); 5134 ok(hr == S_OK, "got 0x%08x\n", hr); 5135 5136 hr = ISAXDeclHandler_externalEntityDecl(decl, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"), 5137 NULL, 0); 5138 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5139 5140 V_VT(&dest) = VT_EMPTY; 5141 hr = IMXWriter_get_output(writer, &dest); 5142 ok(hr == S_OK, "got 0x%08x\n", hr); 5143 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5144 ok(!lstrcmpW(_bstr_( 5145 "<!ENTITY name PUBLIC \"pubid\" \"sysid\">\r\n" 5146 "<!ENTITY name SYSTEM \"sysid\">\r\n"), 5147 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5148 5149 VariantClear(&dest); 5150 5151 /* notation declaration */ 5152 hr = IMXWriter_QueryInterface(writer, &IID_ISAXDTDHandler, (void**)&dtd); 5153 ok(hr == S_OK, "got 0x%08x\n", hr); 5154 5155 V_VT(&dest) = VT_EMPTY; 5156 hr = IMXWriter_put_output(writer, dest); 5157 ok(hr == S_OK, "got 0x%08x\n", hr); 5158 5159 hr = ISAXDTDHandler_notationDecl(dtd, NULL, 0, NULL, 0, NULL, 0); 5160 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5161 5162 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), NULL, 0, NULL, 0); 5163 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); 5164 5165 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"), NULL, 0); 5166 ok(hr == S_OK, "got 0x%08x\n", hr); 5167 5168 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), _bstr_("pubid"), strlen("pubid"), _bstr_("sysid"), strlen("sysid")); 5169 ok(hr == S_OK, "got 0x%08x\n", hr); 5170 5171 hr = ISAXDTDHandler_notationDecl(dtd, _bstr_("name"), strlen("name"), NULL, 0, _bstr_("sysid"), strlen("sysid")); 5172 ok(hr == S_OK, "got 0x%08x\n", hr); 5173 5174 hr = IMXWriter_get_output(writer, &dest); 5175 ok(hr == S_OK, "got 0x%08x\n", hr); 5176 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5177 ok(!lstrcmpW(_bstr_( 5178 "<!NOTATION name" 5179 "<!NOTATION name PUBLIC \"pubid\">\r\n" 5180 "<!NOTATION name PUBLIC \"pubid\" \"sysid\">\r\n" 5181 "<!NOTATION name SYSTEM \"sysid\">\r\n"), 5182 V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5183 5184 VariantClear(&dest); 5185 5186 ISAXDTDHandler_Release(dtd); 5187 5188 ISAXContentHandler_Release(content); 5189 ISAXLexicalHandler_Release(lexical); 5190 IVBSAXLexicalHandler_Release(vblexical); 5191 IVBSAXDeclHandler_Release(vbdecl); 5192 ISAXDeclHandler_Release(decl); 5193 IMXWriter_Release(writer); 5194 free_bstrs(); 5195 } 5196 5197 typedef struct { 5198 const CLSID *clsid; 5199 const char *uri; 5200 const char *local; 5201 const char *qname; 5202 const char *type; 5203 const char *value; 5204 HRESULT hr; 5205 } addattribute_test_t; 5206 5207 static const addattribute_test_t addattribute_data[] = { 5208 { &CLSID_SAXAttributes, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG }, 5209 { &CLSID_SAXAttributes30, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG }, 5210 { &CLSID_SAXAttributes40, NULL, NULL, "ns:qname", NULL, "value", E_INVALIDARG }, 5211 { &CLSID_SAXAttributes60, NULL, NULL, "ns:qname", NULL, "value", S_OK }, 5212 5213 { &CLSID_SAXAttributes, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5214 { &CLSID_SAXAttributes30, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5215 { &CLSID_SAXAttributes40, NULL, "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5216 { &CLSID_SAXAttributes60, NULL, "qname", "ns:qname", NULL, "value", S_OK }, 5217 5218 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5219 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5220 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", NULL, "value", E_INVALIDARG }, 5221 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", NULL, "value", S_OK }, 5222 5223 { &CLSID_SAXAttributes, "uri", "qname", "ns:qname", "type", "value", S_OK }, 5224 { &CLSID_SAXAttributes30, "uri", "qname", "ns:qname", "type", "value", S_OK }, 5225 { &CLSID_SAXAttributes40, "uri", "qname", "ns:qname", "type", "value", S_OK }, 5226 { &CLSID_SAXAttributes60, "uri", "qname", "ns:qname", "type", "value", S_OK }, 5227 5228 { NULL } 5229 }; 5230 5231 static void test_mxattr_addAttribute(void) 5232 { 5233 const addattribute_test_t *table = addattribute_data; 5234 int i = 0; 5235 5236 while (table->clsid) 5237 { 5238 ISAXAttributes *saxattr; 5239 IMXAttributes *mxattr; 5240 const WCHAR *value; 5241 int len, index; 5242 HRESULT hr; 5243 5244 if (!is_clsid_supported(table->clsid, mxattributes_support_data)) 5245 { 5246 table++; 5247 i++; 5248 continue; 5249 } 5250 5251 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 5252 &IID_IMXAttributes, (void**)&mxattr); 5253 EXPECT_HR(hr, S_OK); 5254 5255 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr); 5256 EXPECT_HR(hr, S_OK); 5257 5258 /* SAXAttributes40 and SAXAttributes60 both crash on this test */ 5259 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) || 5260 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30)) 5261 { 5262 hr = ISAXAttributes_getLength(saxattr, NULL); 5263 EXPECT_HR(hr, E_POINTER); 5264 } 5265 5266 len = -1; 5267 hr = ISAXAttributes_getLength(saxattr, &len); 5268 EXPECT_HR(hr, S_OK); 5269 ok(len == 0, "got %d\n", len); 5270 5271 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len); 5272 EXPECT_HR(hr, E_INVALIDARG); 5273 5274 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len); 5275 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5276 5277 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL); 5278 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5279 5280 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL); 5281 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5282 5283 hr = ISAXAttributes_getType(saxattr, 0, &value, &len); 5284 EXPECT_HR(hr, E_INVALIDARG); 5285 5286 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len); 5287 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5288 5289 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL); 5290 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5291 5292 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL); 5293 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5294 5295 hr = IMXAttributes_addAttribute(mxattr, _bstr_(table->uri), _bstr_(table->local), 5296 _bstr_(table->qname), _bstr_(table->type), _bstr_(table->value)); 5297 ok(hr == table->hr, "%d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr); 5298 5299 if (hr == S_OK) 5300 { 5301 /* SAXAttributes40 and SAXAttributes60 both crash on this test */ 5302 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) || 5303 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30)) 5304 { 5305 hr = ISAXAttributes_getValue(saxattr, 0, NULL, &len); 5306 EXPECT_HR(hr, E_POINTER); 5307 5308 hr = ISAXAttributes_getValue(saxattr, 0, &value, NULL); 5309 EXPECT_HR(hr, E_POINTER); 5310 5311 hr = ISAXAttributes_getValue(saxattr, 0, NULL, NULL); 5312 EXPECT_HR(hr, E_POINTER); 5313 5314 hr = ISAXAttributes_getType(saxattr, 0, NULL, &len); 5315 EXPECT_HR(hr, E_POINTER); 5316 5317 hr = ISAXAttributes_getType(saxattr, 0, &value, NULL); 5318 EXPECT_HR(hr, E_POINTER); 5319 5320 hr = ISAXAttributes_getType(saxattr, 0, NULL, NULL); 5321 EXPECT_HR(hr, E_POINTER); 5322 } 5323 5324 len = -1; 5325 hr = ISAXAttributes_getValue(saxattr, 0, &value, &len); 5326 EXPECT_HR(hr, S_OK); 5327 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value), 5328 table->value); 5329 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len); 5330 5331 len = -1; 5332 value = (void*)0xdeadbeef; 5333 hr = ISAXAttributes_getType(saxattr, 0, &value, &len); 5334 EXPECT_HR(hr, S_OK); 5335 5336 if (table->type) 5337 { 5338 ok(!lstrcmpW(_bstr_(table->type), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value), 5339 table->type); 5340 ok(lstrlenW(value) == len, "%d: got wrong type value length %d\n", i, len); 5341 } 5342 else 5343 { 5344 ok(*value == 0, "%d: got type value %s\n", i, wine_dbgstr_w(value)); 5345 ok(len == 0, "%d: got wrong type value length %d\n", i, len); 5346 } 5347 5348 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, NULL); 5349 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) || 5350 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30)) 5351 { 5352 EXPECT_HR(hr, E_POINTER); 5353 } 5354 else 5355 EXPECT_HR(hr, E_INVALIDARG); 5356 5357 hr = ISAXAttributes_getIndexFromQName(saxattr, NULL, 0, &index); 5358 EXPECT_HR(hr, E_INVALIDARG); 5359 5360 index = -1; 5361 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_("nonexistent"), 11, &index); 5362 EXPECT_HR(hr, E_INVALIDARG); 5363 ok(index == -1, "%d: got wrong index %d\n", i, index); 5364 5365 index = -1; 5366 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), 0, &index); 5367 EXPECT_HR(hr, E_INVALIDARG); 5368 ok(index == -1, "%d: got wrong index %d\n", i, index); 5369 5370 index = -1; 5371 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &index); 5372 EXPECT_HR(hr, S_OK); 5373 ok(index == 0, "%d: got wrong index %d\n", i, index); 5374 5375 index = -1; 5376 hr = ISAXAttributes_getIndexFromQName(saxattr, _bstr_(table->qname), strlen(table->qname)-1, &index); 5377 EXPECT_HR(hr, E_INVALIDARG); 5378 ok(index == -1, "%d: got wrong index %d\n", i, index); 5379 5380 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes40) || 5381 IsEqualGUID(table->clsid, &CLSID_SAXAttributes60)) 5382 { 5383 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL); 5384 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5385 5386 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL); 5387 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5388 5389 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL); 5390 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5391 5392 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL); 5393 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5394 5395 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL); 5396 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5397 5398 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL); 5399 ok(hr == E_POINTER /* win8 */ || hr == E_INVALIDARG, "got 0x%08x\n", hr); 5400 } 5401 else 5402 { 5403 hr = ISAXAttributes_getValueFromQName(saxattr, NULL, 0, NULL, NULL); 5404 EXPECT_HR(hr, E_POINTER); 5405 5406 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, NULL, NULL); 5407 EXPECT_HR(hr, E_POINTER); 5408 5409 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), 0, &value, NULL); 5410 EXPECT_HR(hr, E_POINTER); 5411 5412 /* versions 4 and 6 crash */ 5413 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, NULL); 5414 EXPECT_HR(hr, E_POINTER); 5415 5416 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), NULL, &len); 5417 EXPECT_HR(hr, E_POINTER); 5418 5419 hr = ISAXAttributes_getValueFromName(saxattr, NULL, 0, NULL, 0, NULL, NULL); 5420 EXPECT_HR(hr, E_POINTER); 5421 5422 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, NULL, NULL); 5423 EXPECT_HR(hr, E_POINTER); 5424 5425 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, NULL, 0, &value, NULL); 5426 EXPECT_HR(hr, E_POINTER); 5427 5428 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, &value, NULL); 5429 EXPECT_HR(hr, E_POINTER); 5430 5431 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), 0, _bstr_(table->local), 0, NULL, &len); 5432 EXPECT_HR(hr, E_POINTER); 5433 5434 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), _bstr_(table->local), 5435 strlen(table->local), NULL, NULL); 5436 EXPECT_HR(hr, E_POINTER); 5437 } 5438 5439 hr = ISAXAttributes_getValueFromQName(saxattr, _bstr_(table->qname), strlen(table->qname), &value, &len); 5440 EXPECT_HR(hr, S_OK); 5441 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value), 5442 table->value); 5443 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len); 5444 5445 if (table->uri) { 5446 hr = ISAXAttributes_getValueFromName(saxattr, _bstr_(table->uri), strlen(table->uri), 5447 _bstr_(table->local), strlen(table->local), &value, &len); 5448 EXPECT_HR(hr, S_OK); 5449 ok(!lstrcmpW(_bstr_(table->value), value), "%d: got %s, expected %s\n", i, wine_dbgstr_w(value), 5450 table->value); 5451 ok(lstrlenW(value) == len, "%d: got wrong value length %d\n", i, len); 5452 } 5453 } 5454 5455 len = -1; 5456 hr = ISAXAttributes_getLength(saxattr, &len); 5457 EXPECT_HR(hr, S_OK); 5458 if (table->hr == S_OK) 5459 ok(len == 1, "%d: got %d length, expected 1\n", i, len); 5460 else 5461 ok(len == 0, "%d: got %d length, expected 0\n", i, len); 5462 5463 ISAXAttributes_Release(saxattr); 5464 IMXAttributes_Release(mxattr); 5465 5466 table++; 5467 i++; 5468 } 5469 5470 free_bstrs(); 5471 } 5472 5473 static void test_mxattr_clear(void) 5474 { 5475 ISAXAttributes *saxattr; 5476 IMXAttributes *mxattr; 5477 const WCHAR *ptr; 5478 HRESULT hr; 5479 int len; 5480 5481 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER, 5482 &IID_IMXAttributes, (void**)&mxattr); 5483 EXPECT_HR(hr, S_OK); 5484 5485 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr); 5486 EXPECT_HR(hr, S_OK); 5487 5488 hr = ISAXAttributes_getQName(saxattr, 0, NULL, NULL); 5489 EXPECT_HR(hr, E_INVALIDARG); 5490 5491 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len); 5492 EXPECT_HR(hr, E_INVALIDARG); 5493 5494 hr = IMXAttributes_clear(mxattr); 5495 EXPECT_HR(hr, S_OK); 5496 5497 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("local"), 5498 _bstr_("qname"), _bstr_("type"), _bstr_("value")); 5499 EXPECT_HR(hr, S_OK); 5500 5501 len = -1; 5502 hr = ISAXAttributes_getLength(saxattr, &len); 5503 EXPECT_HR(hr, S_OK); 5504 ok(len == 1, "got %d\n", len); 5505 5506 len = -1; 5507 hr = ISAXAttributes_getQName(saxattr, 0, NULL, &len); 5508 EXPECT_HR(hr, E_POINTER); 5509 ok(len == -1, "got %d\n", len); 5510 5511 ptr = (void*)0xdeadbeef; 5512 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, NULL); 5513 EXPECT_HR(hr, E_POINTER); 5514 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr); 5515 5516 len = 0; 5517 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len); 5518 EXPECT_HR(hr, S_OK); 5519 ok(len == 5, "got %d\n", len); 5520 ok(!lstrcmpW(ptr, _bstr_("qname")), "got %s\n", wine_dbgstr_w(ptr)); 5521 5522 hr = IMXAttributes_clear(mxattr); 5523 EXPECT_HR(hr, S_OK); 5524 5525 len = -1; 5526 hr = ISAXAttributes_getLength(saxattr, &len); 5527 EXPECT_HR(hr, S_OK); 5528 ok(len == 0, "got %d\n", len); 5529 5530 len = -1; 5531 ptr = (void*)0xdeadbeef; 5532 hr = ISAXAttributes_getQName(saxattr, 0, &ptr, &len); 5533 EXPECT_HR(hr, E_INVALIDARG); 5534 ok(len == -1, "got %d\n", len); 5535 ok(ptr == (void*)0xdeadbeef, "got %p\n", ptr); 5536 5537 IMXAttributes_Release(mxattr); 5538 ISAXAttributes_Release(saxattr); 5539 free_bstrs(); 5540 } 5541 5542 static void test_mxattr_dispex(void) 5543 { 5544 IMXAttributes *mxattr; 5545 IDispatchEx *dispex; 5546 IUnknown *unk; 5547 HRESULT hr; 5548 5549 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER, 5550 &IID_IMXAttributes, (void**)&mxattr); 5551 EXPECT_HR(hr, S_OK); 5552 5553 hr = IMXAttributes_QueryInterface(mxattr, &IID_IDispatchEx, (void**)&dispex); 5554 EXPECT_HR(hr, S_OK); 5555 hr = IDispatchEx_QueryInterface(dispex, &IID_IUnknown, (void**)&unk); 5556 test_obj_dispex(unk); 5557 IUnknown_Release(unk); 5558 IDispatchEx_Release(dispex); 5559 5560 IMXAttributes_Release(mxattr); 5561 } 5562 5563 static void test_mxattr_qi(void) 5564 { 5565 IVBSAXAttributes *vbsaxattr, *vbsaxattr2; 5566 ISAXAttributes *saxattr; 5567 IMXAttributes *mxattr; 5568 HRESULT hr; 5569 5570 hr = CoCreateInstance(&CLSID_SAXAttributes, NULL, CLSCTX_INPROC_SERVER, 5571 &IID_IMXAttributes, (void**)&mxattr); 5572 EXPECT_HR(hr, S_OK); 5573 5574 EXPECT_REF(mxattr, 1); 5575 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr); 5576 EXPECT_HR(hr, S_OK); 5577 5578 EXPECT_REF(mxattr, 2); 5579 EXPECT_REF(saxattr, 2); 5580 5581 hr = IMXAttributes_QueryInterface(mxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr); 5582 EXPECT_HR(hr, S_OK); 5583 5584 EXPECT_REF(vbsaxattr, 3); 5585 EXPECT_REF(mxattr, 3); 5586 EXPECT_REF(saxattr, 3); 5587 5588 hr = ISAXAttributes_QueryInterface(saxattr, &IID_IVBSAXAttributes, (void**)&vbsaxattr2); 5589 EXPECT_HR(hr, S_OK); 5590 5591 EXPECT_REF(vbsaxattr, 4); 5592 EXPECT_REF(mxattr, 4); 5593 EXPECT_REF(saxattr, 4); 5594 5595 IMXAttributes_Release(mxattr); 5596 ISAXAttributes_Release(saxattr); 5597 IVBSAXAttributes_Release(vbsaxattr); 5598 IVBSAXAttributes_Release(vbsaxattr2); 5599 } 5600 5601 static struct msxmlsupported_data_t saxattr_support_data[] = 5602 { 5603 { &CLSID_SAXAttributes, "SAXAttributes" }, 5604 { &CLSID_SAXAttributes30, "SAXAttributes30" }, 5605 { &CLSID_SAXAttributes40, "SAXAttributes40" }, 5606 { &CLSID_SAXAttributes60, "SAXAttributes60" }, 5607 { NULL } 5608 }; 5609 5610 static void test_mxattr_localname(void) 5611 { 5612 static const WCHAR localname1W[] = {'l','o','c','a','l','n','a','m','e','1',0}; 5613 static const WCHAR localnameW[] = {'l','o','c','a','l','n','a','m','e',0}; 5614 static const WCHAR uri1W[] = {'u','r','i','1',0}; 5615 static const WCHAR uriW[] = {'u','r','i',0}; 5616 5617 const struct msxmlsupported_data_t *table = saxattr_support_data; 5618 5619 while (table->clsid) 5620 { 5621 ISAXAttributes *saxattr; 5622 IMXAttributes *mxattr; 5623 HRESULT hr; 5624 int index; 5625 5626 if (!is_clsid_supported(table->clsid, mxattributes_support_data)) 5627 { 5628 table++; 5629 continue; 5630 } 5631 5632 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, 5633 &IID_IMXAttributes, (void**)&mxattr); 5634 EXPECT_HR(hr, S_OK); 5635 5636 hr = IMXAttributes_QueryInterface(mxattr, &IID_ISAXAttributes, (void**)&saxattr); 5637 EXPECT_HR(hr, S_OK); 5638 5639 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, &index); 5640 EXPECT_HR(hr, E_INVALIDARG); 5641 5642 /* add some ambiguos attribute names */ 5643 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"), 5644 _bstr_("a:localname"), _bstr_(""), _bstr_("value")); 5645 EXPECT_HR(hr, S_OK); 5646 hr = IMXAttributes_addAttribute(mxattr, _bstr_("uri"), _bstr_("localname"), 5647 _bstr_("b:localname"), _bstr_(""), _bstr_("value")); 5648 EXPECT_HR(hr, S_OK); 5649 5650 index = -1; 5651 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localnameW, lstrlenW(localnameW), &index); 5652 EXPECT_HR(hr, S_OK); 5653 ok(index == 0, "%s: got index %d\n", table->name, index); 5654 5655 index = -1; 5656 hr = ISAXAttributes_getIndexFromName(saxattr, uri1W, lstrlenW(uri1W), localnameW, lstrlenW(localnameW), &index); 5657 EXPECT_HR(hr, E_INVALIDARG); 5658 ok(index == -1, "%s: got index %d\n", table->name, index); 5659 5660 index = -1; 5661 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), &index); 5662 EXPECT_HR(hr, E_INVALIDARG); 5663 ok(index == -1, "%s: got index %d\n", table->name, index); 5664 5665 if (IsEqualGUID(table->clsid, &CLSID_SAXAttributes) || 5666 IsEqualGUID(table->clsid, &CLSID_SAXAttributes30)) 5667 { 5668 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL); 5669 EXPECT_HR(hr, E_POINTER); 5670 5671 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL); 5672 EXPECT_HR(hr, E_POINTER); 5673 } 5674 else 5675 { 5676 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, NULL, 0, NULL); 5677 EXPECT_HR(hr, E_INVALIDARG); 5678 5679 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), localname1W, lstrlenW(localname1W), NULL); 5680 EXPECT_HR(hr, E_INVALIDARG); 5681 } 5682 5683 hr = ISAXAttributes_getIndexFromName(saxattr, uriW, lstrlenW(uriW), NULL, 0, &index); 5684 EXPECT_HR(hr, E_INVALIDARG); 5685 5686 hr = ISAXAttributes_getIndexFromName(saxattr, NULL, 0, localname1W, lstrlenW(localname1W), &index); 5687 EXPECT_HR(hr, E_INVALIDARG); 5688 5689 table++; 5690 5691 ISAXAttributes_Release(saxattr); 5692 IMXAttributes_Release(mxattr); 5693 free_bstrs(); 5694 } 5695 } 5696 5697 static void test_mxwriter_indent(void) 5698 { 5699 ISAXContentHandler *content; 5700 IMXWriter *writer; 5701 VARIANT dest; 5702 HRESULT hr; 5703 5704 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void**)&writer); 5705 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); 5706 5707 hr = IMXWriter_put_indent(writer, VARIANT_TRUE); 5708 ok(hr == S_OK, "got %08x\n", hr); 5709 5710 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); 5711 ok(hr == S_OK, "got %08x\n", hr); 5712 5713 hr = ISAXContentHandler_startDocument(content); 5714 ok(hr == S_OK, "got %08x\n", hr); 5715 5716 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL); 5717 ok(hr == S_OK, "got %08x\n", hr); 5718 5719 hr = ISAXContentHandler_characters(content, _bstr_(""), 0); 5720 ok(hr == S_OK, "got %08x\n", hr); 5721 5722 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1, NULL); 5723 ok(hr == S_OK, "got %08x\n", hr); 5724 5725 hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1, NULL); 5726 ok(hr == S_OK, "got %08x\n", hr); 5727 5728 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1); 5729 ok(hr == S_OK, "got %08x\n", hr); 5730 5731 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1); 5732 ok(hr == S_OK, "got %08x\n", hr); 5733 5734 hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1); 5735 ok(hr == S_OK, "got %08x\n", hr); 5736 5737 hr = ISAXContentHandler_endDocument(content); 5738 ok(hr == S_OK, "got %08x\n", hr); 5739 5740 V_VT(&dest) = VT_EMPTY; 5741 hr = IMXWriter_get_output(writer, &dest); 5742 ok(hr == S_OK, "got %08x\n", hr); 5743 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); 5744 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)), 5745 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); 5746 VariantClear(&dest); 5747 5748 ISAXContentHandler_Release(content); 5749 IMXWriter_Release(writer); 5750 5751 free_bstrs(); 5752 } 5753 5754 START_TEST(saxreader) 5755 { 5756 ISAXXMLReader *reader; 5757 HRESULT hr; 5758 5759 hr = CoInitialize(NULL); 5760 ok(hr == S_OK, "failed to init com\n"); 5761 5762 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER, 5763 &IID_ISAXXMLReader, (void**)&reader); 5764 5765 if(FAILED(hr)) 5766 { 5767 win_skip("Failed to create SAXXMLReader instance\n"); 5768 CoUninitialize(); 5769 return; 5770 } 5771 ISAXXMLReader_Release(reader); 5772 5773 init_call_sequences(sequences, NUM_CALL_SEQUENCES); 5774 5775 get_class_support_data(reader_support_data, &IID_ISAXXMLReader); 5776 5777 test_saxreader(); 5778 test_saxreader_properties(); 5779 test_saxreader_features(); 5780 test_saxreader_encoding(); 5781 test_saxreader_dispex(); 5782 5783 /* MXXMLWriter tests */ 5784 get_class_support_data(mxwriter_support_data, &IID_IMXWriter); 5785 if (is_clsid_supported(&CLSID_MXXMLWriter, mxwriter_support_data)) 5786 { 5787 test_mxwriter_handlers(); 5788 test_mxwriter_startenddocument(); 5789 test_mxwriter_startendelement(); 5790 test_mxwriter_characters(); 5791 test_mxwriter_comment(); 5792 test_mxwriter_cdata(); 5793 test_mxwriter_pi(); 5794 test_mxwriter_ignorablespaces(); 5795 test_mxwriter_dtd(); 5796 test_mxwriter_properties(); 5797 test_mxwriter_flush(); 5798 test_mxwriter_stream(); 5799 test_mxwriter_encoding(); 5800 test_mxwriter_dispex(); 5801 test_mxwriter_indent(); 5802 } 5803 else 5804 win_skip("MXXMLWriter not supported\n"); 5805 5806 /* SAXAttributes tests */ 5807 get_class_support_data(mxattributes_support_data, &IID_IMXAttributes); 5808 if (is_clsid_supported(&CLSID_SAXAttributes, mxattributes_support_data)) 5809 { 5810 test_mxattr_qi(); 5811 test_mxattr_addAttribute(); 5812 test_mxattr_clear(); 5813 test_mxattr_localname(); 5814 test_mxattr_dispex(); 5815 } 5816 else 5817 win_skip("SAXAttributes not supported\n"); 5818 5819 CoUninitialize(); 5820 } 5821