1 /* Tests in the "basic" test case for the Expat test suite 2 __ __ _ 3 ___\ \/ /_ __ __ _| |_ 4 / _ \\ /| '_ \ / _` | __| 5 | __// \| |_) | (_| | |_ 6 \___/_/\_\ .__/ \__,_|\__| 7 |_| XML parser 8 9 Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net> 10 Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net> 11 Copyright (c) 2005-2007 Steven Solie <steven@solie.ca> 12 Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net> 13 Copyright (c) 2016-2026 Sebastian Pipping <sebastian@pipping.org> 14 Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk> 15 Copyright (c) 2017 Joe Orton <jorton@redhat.com> 16 Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com> 17 Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it> 18 Copyright (c) 2019 David Loffredo <loffredo@steptools.com> 19 Copyright (c) 2020 Tim Gates <tim.gates@iress.com> 20 Copyright (c) 2021 Donghee Na <donghee.na@python.org> 21 Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com> 22 Copyright (c) 2024-2026 Berkay Eren Ürün <berkay.ueruen@siemens.com> 23 Copyright (c) 2026 Francesco Bertolaccini 24 Copyright (c) 2026 Matthew Fernandez <matthew.fernandez@gmail.com> 25 Copyright (c) 2026 Kartik Kenchi <netliomax25@gmail.com> 26 Licensed under the MIT license: 27 28 Permission is hereby granted, free of charge, to any person obtaining 29 a copy of this software and associated documentation files (the 30 "Software"), to deal in the Software without restriction, including 31 without limitation the rights to use, copy, modify, merge, publish, 32 distribute, sublicense, and/or sell copies of the Software, and to permit 33 persons to whom the Software is furnished to do so, subject to the 34 following conditions: 35 36 The above copyright notice and this permission notice shall be included 37 in all copies or substantial portions of the Software. 38 39 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 40 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 41 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 42 NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 43 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 44 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 45 USE OR OTHER DEALINGS IN THE SOFTWARE. 46 47 SPDX-License-Identifier: MIT 48 */ 49 50 #if defined(NDEBUG) 51 # undef NDEBUG /* because test suite relies on assert(...) at the moment */ 52 #endif 53 54 #include "expat_config.h" 55 56 #include <assert.h> 57 #include <limits.h> // ULONG_MAX 58 #include <stdbool.h> 59 #include <stdio.h> 60 #include <string.h> 61 #include <time.h> 62 63 #include "expat.h" 64 #include "internal.h" 65 #include "minicheck.h" 66 #include "structdata.h" 67 #include "common.h" 68 #include "dummy.h" 69 #include "handlers.h" 70 #include "siphash.h" 71 #include "basic_tests.h" 72 73 #define EXPAT_TESTS_ASAN 1 74 75 #if defined(__has_feature) 76 # if ! __has_feature(address_sanitizer) 77 # undef EXPAT_TESTS_ASAN 78 # define EXPAT_TESTS_ASAN 0 79 # endif 80 #endif 81 82 #if ULONG_MAX == 18446744073709551615u // 2^64-1 83 # define EXPAT_TESTS_64BIT 1 84 #else 85 # define EXPAT_TESTS_64BIT 0 86 #endif 87 88 static void 89 basic_setup(void) { 90 g_parser = XML_ParserCreate(NULL); 91 if (g_parser == NULL) 92 fail("Parser not created."); 93 } 94 95 /* 96 * Character & encoding tests. 97 */ 98 99 START_TEST(test_nul_byte) { 100 char text[] = "<doc>\0</doc>"; 101 102 /* test that a NUL byte (in US-ASCII data) is an error */ 103 if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE) 104 == XML_STATUS_OK) 105 fail("Parser did not report error on NUL-byte."); 106 if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN) 107 xml_failure(g_parser); 108 } 109 END_TEST 110 111 START_TEST(test_u0000_char) { 112 /* test that a NUL byte (in US-ASCII data) is an error */ 113 expect_failure("<doc>�</doc>", XML_ERROR_BAD_CHAR_REF, 114 "Parser did not report error on NUL-byte."); 115 } 116 END_TEST 117 118 START_TEST(test_siphash_self) { 119 if (! sip24_valid()) 120 fail("SipHash self-test failed"); 121 } 122 END_TEST 123 124 START_TEST(test_siphash_spec) { 125 /* https://131002.net/siphash/siphash.pdf (page 19, "Test values") */ 126 const char message[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09" 127 "\x0a\x0b\x0c\x0d\x0e"; 128 const size_t len = sizeof(message) - 1; 129 const uint64_t expected = SIP_ULL(0xa129ca61U, 0x49be45e5U); 130 struct siphash state; 131 struct sipkey key; 132 133 sip_tokey(&key, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09" 134 "\x0a\x0b\x0c\x0d\x0e\x0f"); 135 sip24_init(&state, &key); 136 137 /* Cover spread across calls */ 138 sip24_update(&state, message, 4); 139 sip24_update(&state, message + 4, len - 4); 140 141 /* Cover null length */ 142 sip24_update(&state, message, 0); 143 144 if (sip24_final(&state) != expected) 145 fail("sip24_final failed spec test\n"); 146 147 /* Cover wrapper */ 148 if (siphash24(message, len, &key) != expected) 149 fail("siphash24 failed spec test\n"); 150 } 151 END_TEST 152 153 START_TEST(test_bom_utf8) { 154 /* This test is really just making sure we don't core on a UTF-8 BOM. */ 155 const char *text = "\357\273\277<e/>"; 156 157 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 158 == XML_STATUS_ERROR) 159 xml_failure(g_parser); 160 } 161 END_TEST 162 163 START_TEST(test_bom_utf16_be) { 164 char text[] = "\376\377\0<\0e\0/\0>"; 165 166 if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE) 167 == XML_STATUS_ERROR) 168 xml_failure(g_parser); 169 } 170 END_TEST 171 172 START_TEST(test_bom_utf16_le) { 173 char text[] = "\377\376<\0e\0/\0>\0"; 174 175 if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE) 176 == XML_STATUS_ERROR) 177 xml_failure(g_parser); 178 } 179 END_TEST 180 181 START_TEST(test_nobom_utf16_le) { 182 char text[] = " \0<\0e\0/\0>\0"; 183 184 if (g_chunkSize == 1) { 185 // TODO: with just the first byte, we can't tell the difference between 186 // UTF-16-LE and UTF-8. Avoid the failure for now. 187 return; 188 } 189 190 if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE) 191 == XML_STATUS_ERROR) 192 xml_failure(g_parser); 193 } 194 END_TEST 195 196 START_TEST(test_hash_collision) { 197 /* For full coverage of the lookup routine, we need to ensure a 198 * hash collision even though we can only tell that we have one 199 * through breakpoint debugging or coverage statistics. The 200 * following will cause a hash collision on machines with a 64-bit 201 * long type; others will have to experiment. The full coverage 202 * tests invoked from qa.sh usually provide a hash collision, but 203 * not always. This is an attempt to provide insurance. 204 */ 205 #define COLLIDING_HASH_SALT (unsigned long)SIP_ULL(0xffffffffU, 0xff99fc90U) 206 const char *text 207 = "<doc>\n" 208 "<a1/><a2/><a3/><a4/><a5/><a6/><a7/><a8/>\n" 209 "<b1></b1><b2 attr='foo'>This is a foo</b2><b3></b3><b4></b4>\n" 210 "<b5></b5><b6></b6><b7></b7><b8></b8>\n" 211 "<c1/><c2/><c3/><c4/><c5/><c6/><c7/><c8/>\n" 212 "<d1/><d2/><d3/><d4/><d5/><d6/><d7/>\n" 213 "<d8>This triggers the table growth and collides with b2</d8>\n" 214 "</doc>\n"; 215 216 XML_SetHashSalt(g_parser, COLLIDING_HASH_SALT); 217 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 218 == XML_STATUS_ERROR) 219 xml_failure(g_parser); 220 } 221 END_TEST 222 #undef COLLIDING_HASH_SALT 223 224 START_TEST(test_hash_salt_setter) { 225 const uint8_t entropy[16] = {'0', '1', '2', '3', '4', '5', '6', '7', 226 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 227 XML_Parser parser = XML_ParserCreate(NULL); 228 229 // NULL parser should be rejected 230 assert_true(XML_SetHashSalt16Bytes(NULL, entropy) == XML_FALSE); 231 232 // NULL entropy should be rejected 233 assert_true(XML_SetHashSalt16Bytes(parser, NULL) == XML_FALSE); 234 235 // Setting should be allowed more than once 236 assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_TRUE); 237 assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_TRUE); 238 239 // But not after parsing has started 240 assert_true(XML_Parse(parser, "", 0, XML_FALSE /* isFinal */) 241 == XML_STATUS_OK); 242 assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_FALSE); 243 244 XML_ParserFree(parser); 245 } 246 END_TEST 247 248 /* Regression test for SF bug #491986. */ 249 START_TEST(test_danish_latin1) { 250 const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n" 251 "<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>"; 252 #ifdef XML_UNICODE 253 const XML_Char *expected 254 = XCS("J\x00f8rgen \x00e6\x00f8\x00e5\x00c6\x00d8\x00c5"); 255 #else 256 const XML_Char *expected 257 = XCS("J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85"); 258 #endif 259 run_character_check(text, expected); 260 } 261 END_TEST 262 263 /* Regression test for SF bug #514281. */ 264 START_TEST(test_french_charref_hexidecimal) { 265 const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n" 266 "<doc>éèàçêÈ</doc>"; 267 #ifdef XML_UNICODE 268 const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8"); 269 #else 270 const XML_Char *expected 271 = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88"); 272 #endif 273 run_character_check(text, expected); 274 } 275 END_TEST 276 277 START_TEST(test_french_charref_decimal) { 278 const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n" 279 "<doc>éèàçêÈ</doc>"; 280 #ifdef XML_UNICODE 281 const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8"); 282 #else 283 const XML_Char *expected 284 = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88"); 285 #endif 286 run_character_check(text, expected); 287 } 288 END_TEST 289 290 START_TEST(test_french_latin1) { 291 const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n" 292 "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>"; 293 #ifdef XML_UNICODE 294 const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8"); 295 #else 296 const XML_Char *expected 297 = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88"); 298 #endif 299 run_character_check(text, expected); 300 } 301 END_TEST 302 303 START_TEST(test_french_utf8) { 304 const char *text = "<?xml version='1.0' encoding='utf-8'?>\n" 305 "<doc>\xC3\xA9</doc>"; 306 #ifdef XML_UNICODE 307 const XML_Char *expected = XCS("\x00e9"); 308 #else 309 const XML_Char *expected = XCS("\xC3\xA9"); 310 #endif 311 run_character_check(text, expected); 312 } 313 END_TEST 314 315 /* Regression test for SF bug #600479. 316 XXX There should be a test that exercises all legal XML Unicode 317 characters as PCDATA and attribute value content, and XML Name 318 characters as part of element and attribute names. 319 */ 320 START_TEST(test_utf8_false_rejection) { 321 const char *text = "<doc>\xEF\xBA\xBF</doc>"; 322 #ifdef XML_UNICODE 323 const XML_Char *expected = XCS("\xfebf"); 324 #else 325 const XML_Char *expected = XCS("\xEF\xBA\xBF"); 326 #endif 327 run_character_check(text, expected); 328 } 329 END_TEST 330 331 /* Regression test for SF bug #477667. 332 This test assures that any 8-bit character followed by a 7-bit 333 character will not be mistakenly interpreted as a valid UTF-8 334 sequence. 335 */ 336 START_TEST(test_illegal_utf8) { 337 char text[100]; 338 int i; 339 340 for (i = 128; i <= 255; ++i) { 341 snprintf(text, sizeof(text), "<e>%ccd</e>", i); 342 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 343 == XML_STATUS_OK) { 344 snprintf(text, sizeof(text), 345 "expected token error for '%c' (ordinal %d) in UTF-8 text", i, 346 i); 347 fail(text); 348 } else if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN) 349 xml_failure(g_parser); 350 /* Reset the parser since we use the same parser repeatedly. */ 351 XML_ParserReset(g_parser, NULL); 352 } 353 } 354 END_TEST 355 356 /* Examples, not masks: */ 357 #define UTF8_LEAD_1 "\x7f" /* 0b01111111 */ 358 #define UTF8_LEAD_2 "\xdf" /* 0b11011111 */ 359 #define UTF8_LEAD_3 "\xef" /* 0b11101111 */ 360 #define UTF8_LEAD_4 "\xf7" /* 0b11110111 */ 361 #define UTF8_FOLLOW "\xbf" /* 0b10111111 */ 362 363 START_TEST(test_utf8_auto_align) { 364 struct TestCase { 365 ptrdiff_t expectedMovementInChars; 366 const char *input; 367 }; 368 369 struct TestCase cases[] = { 370 {00, ""}, 371 372 {00, UTF8_LEAD_1}, 373 374 {-1, UTF8_LEAD_2}, 375 {00, UTF8_LEAD_2 UTF8_FOLLOW}, 376 377 {-1, UTF8_LEAD_3}, 378 {-2, UTF8_LEAD_3 UTF8_FOLLOW}, 379 {00, UTF8_LEAD_3 UTF8_FOLLOW UTF8_FOLLOW}, 380 381 {-1, UTF8_LEAD_4}, 382 {-2, UTF8_LEAD_4 UTF8_FOLLOW}, 383 {-3, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW}, 384 {00, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW UTF8_FOLLOW}, 385 }; 386 387 size_t i = 0; 388 bool success = true; 389 for (; i < sizeof(cases) / sizeof(*cases); i++) { 390 const char *fromLim = cases[i].input + strlen(cases[i].input); 391 const char *const fromLimInitially = fromLim; 392 ptrdiff_t actualMovementInChars; 393 394 _INTERNAL_trim_to_complete_utf8_characters(cases[i].input, &fromLim); 395 396 actualMovementInChars = (fromLim - fromLimInitially); 397 if (actualMovementInChars != cases[i].expectedMovementInChars) { 398 size_t j = 0; 399 success = false; 400 printf("[-] UTF-8 case %2u: Expected movement by %2d chars" 401 ", actually moved by %2d chars: \"", 402 (unsigned)(i + 1), (int)cases[i].expectedMovementInChars, 403 (int)actualMovementInChars); 404 for (; j < strlen(cases[i].input); j++) { 405 printf("\\x%02x", (unsigned char)cases[i].input[j]); 406 } 407 printf("\"\n"); 408 } 409 } 410 411 if (! success) { 412 fail("UTF-8 auto-alignment is not bullet-proof\n"); 413 } 414 } 415 END_TEST 416 417 START_TEST(test_utf16) { 418 /* <?xml version="1.0" encoding="UTF-16"?> 419 * <doc a='123'>some {A} text</doc> 420 * 421 * where {A} is U+FF21, FULLWIDTH LATIN CAPITAL LETTER A 422 */ 423 char text[] 424 = "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o" 425 "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o" 426 "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066" 427 "\000'\000?\000>\000\n" 428 "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'\000>" 429 "\000s\000o\000m\000e\000 \xff\x21\000 \000t\000e\000x\000t\000" 430 "<\000/\000d\000o\000c\000>"; 431 #ifdef XML_UNICODE 432 const XML_Char *expected = XCS("some \xff21 text"); 433 #else 434 const XML_Char *expected = XCS("some \357\274\241 text"); 435 #endif 436 CharData storage; 437 438 CharData_Init(&storage); 439 XML_SetUserData(g_parser, &storage); 440 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 441 if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE) 442 == XML_STATUS_ERROR) 443 xml_failure(g_parser); 444 CharData_CheckXMLChars(&storage, expected); 445 } 446 END_TEST 447 448 START_TEST(test_utf16_le_epilog_newline) { 449 unsigned int first_chunk_bytes = 17; 450 char text[] = "\xFF\xFE" /* BOM */ 451 "<\000e\000/\000>\000" /* document element */ 452 "\r\000\n\000\r\000\n\000"; /* epilog */ 453 454 if (first_chunk_bytes >= sizeof(text) - 1) 455 fail("bad value of first_chunk_bytes"); 456 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)first_chunk_bytes, XML_FALSE) 457 == XML_STATUS_ERROR) 458 xml_failure(g_parser); 459 else { 460 enum XML_Status rc; 461 rc = _XML_Parse_SINGLE_BYTES(g_parser, text + first_chunk_bytes, 462 (int)(sizeof(text) - first_chunk_bytes - 1), 463 XML_TRUE); 464 if (rc == XML_STATUS_ERROR) 465 xml_failure(g_parser); 466 } 467 } 468 END_TEST 469 470 /* Test that an outright lie in the encoding is faulted */ 471 START_TEST(test_not_utf16) { 472 const char *text = "<?xml version='1.0' encoding='utf-16'?>" 473 "<doc>Hi</doc>"; 474 475 /* Use a handler to provoke the appropriate code paths */ 476 XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler); 477 expect_failure(text, XML_ERROR_INCORRECT_ENCODING, 478 "UTF-16 declared in UTF-8 not faulted"); 479 } 480 END_TEST 481 482 /* Test that an unknown encoding is rejected */ 483 START_TEST(test_bad_encoding) { 484 const char *text = "<doc>Hi</doc>"; 485 486 if (! XML_SetEncoding(g_parser, XCS("unknown-encoding"))) 487 fail("XML_SetEncoding failed"); 488 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING, 489 "Unknown encoding not faulted"); 490 } 491 END_TEST 492 493 /* Regression test for SF bug #481609, #774028. */ 494 START_TEST(test_latin1_umlauts) { 495 const char *text 496 = "<?xml version='1.0' encoding='iso-8859-1'?>\n" 497 "<e a='\xE4 \xF6 \xFC ä ö ü ä ö ü >'\n" 498 " >\xE4 \xF6 \xFC ä ö ü ä ö ü ></e>"; 499 #ifdef XML_UNICODE 500 /* Expected results in UTF-16 */ 501 const XML_Char *expected = XCS("\x00e4 \x00f6 \x00fc ") 502 XCS("\x00e4 \x00f6 \x00fc ") XCS("\x00e4 \x00f6 \x00fc >"); 503 #else 504 /* Expected results in UTF-8 */ 505 const XML_Char *expected = XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ") 506 XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ") XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC >"); 507 #endif 508 509 run_character_check(text, expected); 510 XML_ParserReset(g_parser, NULL); 511 run_attribute_check(text, expected); 512 /* Repeat with a default handler */ 513 XML_ParserReset(g_parser, NULL); 514 XML_SetDefaultHandler(g_parser, dummy_default_handler); 515 run_character_check(text, expected); 516 XML_ParserReset(g_parser, NULL); 517 XML_SetDefaultHandler(g_parser, dummy_default_handler); 518 run_attribute_check(text, expected); 519 } 520 END_TEST 521 522 /* Test that an element name with a 4-byte UTF-8 character is rejected */ 523 START_TEST(test_long_utf8_character) { 524 const char *text 525 = "<?xml version='1.0' encoding='utf-8'?>\n" 526 /* 0xf0 0x90 0x80 0x80 = U+10000, the first Linear B character */ 527 "<do\xf0\x90\x80\x80/>"; 528 expect_failure(text, XML_ERROR_INVALID_TOKEN, 529 "4-byte UTF-8 character in element name not faulted"); 530 } 531 END_TEST 532 533 /* Test that a long latin-1 attribute (too long to convert in one go) 534 * is correctly converted 535 */ 536 START_TEST(test_long_latin1_attribute) { 537 const char *text 538 = "<?xml version='1.0' encoding='iso-8859-1'?>\n" 539 "<doc att='" 540 /* 64 characters per line */ 541 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 542 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 543 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 544 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 545 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 546 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 547 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 548 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 549 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 550 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 551 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 552 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 553 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 554 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 555 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 556 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO" 557 /* Last character splits across a buffer boundary */ 558 "\xe4'>\n</doc>"; 559 560 const XML_Char *expected = 561 /* 64 characters per line */ 562 /* clang-format off */ 563 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 564 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 565 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 566 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 567 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 568 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 569 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 570 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 571 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 572 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 573 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 574 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 575 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 576 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 577 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 578 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO") 579 /* clang-format on */ 580 #ifdef XML_UNICODE 581 XCS("\x00e4"); 582 #else 583 XCS("\xc3\xa4"); 584 #endif 585 586 run_attribute_check(text, expected); 587 } 588 END_TEST 589 590 /* Test that a long ASCII attribute (too long to convert in one go) 591 * is correctly converted 592 */ 593 START_TEST(test_long_ascii_attribute) { 594 const char *text 595 = "<?xml version='1.0' encoding='us-ascii'?>\n" 596 "<doc att='" 597 /* 64 characters per line */ 598 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 599 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 600 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 601 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 602 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 603 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 604 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 605 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 606 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 607 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 608 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 609 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 610 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 611 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 612 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 613 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP" 614 "01234'>\n</doc>"; 615 const XML_Char *expected = 616 /* 64 characters per line */ 617 /* clang-format off */ 618 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 619 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 620 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 621 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 622 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 623 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 624 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 625 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 626 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 627 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 628 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 629 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 630 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 631 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 632 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 633 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 634 XCS("01234"); 635 /* clang-format on */ 636 637 run_attribute_check(text, expected); 638 } 639 END_TEST 640 641 /* Regression test #1 for SF bug #653180. */ 642 START_TEST(test_line_number_after_parse) { 643 const char *text = "<tag>\n" 644 "\n" 645 "\n</tag>"; 646 XML_Size lineno; 647 648 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 649 == XML_STATUS_ERROR) 650 xml_failure(g_parser); 651 lineno = XML_GetCurrentLineNumber(g_parser); 652 if (lineno != 4) { 653 char buffer[100]; 654 snprintf(buffer, sizeof(buffer), 655 "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno); 656 fail(buffer); 657 } 658 } 659 END_TEST 660 661 /* Regression test #2 for SF bug #653180. */ 662 START_TEST(test_column_number_after_parse) { 663 const char *text = "<tag></tag>"; 664 XML_Size colno; 665 666 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 667 == XML_STATUS_ERROR) 668 xml_failure(g_parser); 669 colno = XML_GetCurrentColumnNumber(g_parser); 670 if (colno != 11) { 671 char buffer[100]; 672 snprintf(buffer, sizeof(buffer), 673 "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno); 674 fail(buffer); 675 } 676 } 677 END_TEST 678 679 /* Regression test #3 for SF bug #653180. */ 680 START_TEST(test_line_and_column_numbers_inside_handlers) { 681 const char *text = "<a>\n" /* Unix end-of-line */ 682 " <b>\r\n" /* Windows end-of-line */ 683 " <c/>\r" /* Mac OS end-of-line */ 684 " </b>\n" 685 " <d>\n" 686 " <f/>\n" 687 " </d>\n" 688 "</a>"; 689 const StructDataEntry expected[] 690 = {{XCS("a"), 0, 1, STRUCT_START_TAG}, {XCS("b"), 2, 2, STRUCT_START_TAG}, 691 {XCS("c"), 4, 3, STRUCT_START_TAG}, {XCS("c"), 8, 3, STRUCT_END_TAG}, 692 {XCS("b"), 2, 4, STRUCT_END_TAG}, {XCS("d"), 2, 5, STRUCT_START_TAG}, 693 {XCS("f"), 4, 6, STRUCT_START_TAG}, {XCS("f"), 8, 6, STRUCT_END_TAG}, 694 {XCS("d"), 2, 7, STRUCT_END_TAG}, {XCS("a"), 0, 8, STRUCT_END_TAG}}; 695 const int expected_count = sizeof(expected) / sizeof(StructDataEntry); 696 StructData storage; 697 698 StructData_Init(&storage); 699 XML_SetUserData(g_parser, &storage); 700 XML_SetStartElementHandler(g_parser, start_element_event_handler2); 701 XML_SetEndElementHandler(g_parser, end_element_event_handler2); 702 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 703 == XML_STATUS_ERROR) 704 xml_failure(g_parser); 705 706 StructData_CheckItems(&storage, expected, expected_count); 707 StructData_Dispose(&storage); 708 } 709 END_TEST 710 711 /* Regression test #4 for SF bug #653180. */ 712 START_TEST(test_line_number_after_error) { 713 const char *text = "<a>\n" 714 " <b>\n" 715 " </a>"; /* missing </b> */ 716 XML_Size lineno; 717 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 718 != XML_STATUS_ERROR) 719 fail("Expected a parse error"); 720 721 lineno = XML_GetCurrentLineNumber(g_parser); 722 if (lineno != 3) { 723 char buffer[100]; 724 snprintf(buffer, sizeof(buffer), 725 "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno); 726 fail(buffer); 727 } 728 } 729 END_TEST 730 731 /* Regression test #5 for SF bug #653180. */ 732 START_TEST(test_column_number_after_error) { 733 const char *text = "<a>\n" 734 " <b>\n" 735 " </a>"; /* missing </b> */ 736 XML_Size colno; 737 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 738 != XML_STATUS_ERROR) 739 fail("Expected a parse error"); 740 741 colno = XML_GetCurrentColumnNumber(g_parser); 742 if (colno != 4) { 743 char buffer[100]; 744 snprintf(buffer, sizeof(buffer), 745 "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno); 746 fail(buffer); 747 } 748 } 749 END_TEST 750 751 /* Regression test for SF bug #478332. */ 752 START_TEST(test_really_long_lines) { 753 /* This parses an input line longer than INIT_DATA_BUF_SIZE 754 characters long (defined to be 1024 in xmlparse.c). We take a 755 really cheesy approach to building the input buffer, because 756 this avoids writing bugs in buffer-filling code. 757 */ 758 const char *text 759 = "<e>" 760 /* 64 chars */ 761 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 762 /* until we have at least 1024 characters on the line: */ 763 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 764 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 765 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 766 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 767 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 768 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 769 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 770 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 771 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 772 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 773 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 774 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 775 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 776 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 777 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 778 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 779 "</e>"; 780 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 781 == XML_STATUS_ERROR) 782 xml_failure(g_parser); 783 } 784 END_TEST 785 786 /* Test cdata processing across a buffer boundary */ 787 START_TEST(test_really_long_encoded_lines) { 788 /* As above, except that we want to provoke an output buffer 789 * overflow with a non-trivial encoding. For this we need to pass 790 * the whole cdata in one go, not byte-by-byte. 791 */ 792 void *buffer; 793 const char *text 794 = "<?xml version='1.0' encoding='iso-8859-1'?>" 795 "<e>" 796 /* 64 chars */ 797 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 798 /* until we have at least 1024 characters on the line: */ 799 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 800 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 801 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 802 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 803 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 804 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 805 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 806 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 807 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 808 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 809 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 810 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 811 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 812 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 813 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 814 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" 815 "</e>"; 816 int parse_len = (int)strlen(text); 817 818 /* Need a cdata handler to provoke the code path we want to test */ 819 XML_SetCharacterDataHandler(g_parser, dummy_cdata_handler); 820 buffer = XML_GetBuffer(g_parser, parse_len); 821 if (buffer == NULL) 822 fail("Could not allocate parse buffer"); 823 assert(buffer != NULL); 824 memcpy(buffer, text, parse_len); 825 if (XML_ParseBuffer(g_parser, parse_len, XML_TRUE) == XML_STATUS_ERROR) 826 xml_failure(g_parser); 827 } 828 END_TEST 829 830 /* 831 * Element event tests. 832 */ 833 834 START_TEST(test_end_element_events) { 835 const char *text = "<a><b><c/></b><d><f/></d></a>"; 836 const XML_Char *expected = XCS("/c/b/f/d/a"); 837 CharData storage; 838 839 CharData_Init(&storage); 840 XML_SetUserData(g_parser, &storage); 841 XML_SetEndElementHandler(g_parser, end_element_event_handler); 842 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 843 == XML_STATUS_ERROR) 844 xml_failure(g_parser); 845 CharData_CheckXMLChars(&storage, expected); 846 } 847 END_TEST 848 849 /* 850 * Attribute tests. 851 */ 852 853 /* Helper used by the following tests; this checks any "attr" and "refs" 854 attributes to make sure whitespace has been normalized. 855 856 Return true if whitespace has been normalized in a string, using 857 the rules for attribute value normalization. The 'is_cdata' flag 858 is needed since CDATA attributes don't need to have multiple 859 whitespace characters collapsed to a single space, while other 860 attribute data types do. (Section 3.3.3 of the recommendation.) 861 */ 862 static int 863 is_whitespace_normalized(const XML_Char *s, int is_cdata) { 864 int blanks = 0; 865 int at_start = 1; 866 while (*s) { 867 if (*s == XCS(' ')) 868 ++blanks; 869 else if (*s == XCS('\t') || *s == XCS('\n') || *s == XCS('\r')) 870 return 0; 871 else { 872 if (at_start) { 873 at_start = 0; 874 if (blanks && ! is_cdata) 875 /* illegal leading blanks */ 876 return 0; 877 } else if (blanks > 1 && ! is_cdata) 878 return 0; 879 blanks = 0; 880 } 881 ++s; 882 } 883 if (blanks && ! is_cdata) 884 return 0; 885 return 1; 886 } 887 888 /* Check the attribute whitespace checker: */ 889 START_TEST(test_helper_is_whitespace_normalized) { 890 assert(is_whitespace_normalized(XCS("abc"), 0)); 891 assert(is_whitespace_normalized(XCS("abc"), 1)); 892 assert(is_whitespace_normalized(XCS("abc def ghi"), 0)); 893 assert(is_whitespace_normalized(XCS("abc def ghi"), 1)); 894 assert(! is_whitespace_normalized(XCS(" abc def ghi"), 0)); 895 assert(is_whitespace_normalized(XCS(" abc def ghi"), 1)); 896 assert(! is_whitespace_normalized(XCS("abc def ghi"), 0)); 897 assert(is_whitespace_normalized(XCS("abc def ghi"), 1)); 898 assert(! is_whitespace_normalized(XCS("abc def ghi "), 0)); 899 assert(is_whitespace_normalized(XCS("abc def ghi "), 1)); 900 assert(! is_whitespace_normalized(XCS(" "), 0)); 901 assert(is_whitespace_normalized(XCS(" "), 1)); 902 assert(! is_whitespace_normalized(XCS("\t"), 0)); 903 assert(! is_whitespace_normalized(XCS("\t"), 1)); 904 assert(! is_whitespace_normalized(XCS("\n"), 0)); 905 assert(! is_whitespace_normalized(XCS("\n"), 1)); 906 assert(! is_whitespace_normalized(XCS("\r"), 0)); 907 assert(! is_whitespace_normalized(XCS("\r"), 1)); 908 assert(! is_whitespace_normalized(XCS("abc\t def"), 1)); 909 } 910 END_TEST 911 912 static void XMLCALL 913 check_attr_contains_normalized_whitespace(void *userData, const XML_Char *name, 914 const XML_Char **atts) { 915 int i; 916 UNUSED_P(userData); 917 UNUSED_P(name); 918 for (i = 0; atts[i] != NULL; i += 2) { 919 const XML_Char *attrname = atts[i]; 920 const XML_Char *value = atts[i + 1]; 921 if (xcstrcmp(XCS("attr"), attrname) == 0 922 || xcstrcmp(XCS("ents"), attrname) == 0 923 || xcstrcmp(XCS("refs"), attrname) == 0) { 924 if (! is_whitespace_normalized(value, 0)) { 925 char buffer[256]; 926 snprintf(buffer, sizeof(buffer), 927 "attribute value not normalized: %" XML_FMT_STR 928 "='%" XML_FMT_STR "'", 929 attrname, value); 930 fail(buffer); 931 } 932 } 933 } 934 } 935 936 START_TEST(test_attr_whitespace_normalization) { 937 const char *text 938 = "<!DOCTYPE doc [\n" 939 " <!ATTLIST doc\n" 940 " attr NMTOKENS #REQUIRED\n" 941 " ents ENTITIES #REQUIRED\n" 942 " refs IDREFS #REQUIRED>\n" 943 "]>\n" 944 "<doc attr=' a b c\t\td\te\t' refs=' id-1 \t id-2\t\t' \n" 945 " ents=' ent-1 \t\r\n" 946 " ent-2 ' >\n" 947 " <e id='id-1'/>\n" 948 " <e id='id-2'/>\n" 949 "</doc>"; 950 951 XML_SetStartElementHandler(g_parser, 952 check_attr_contains_normalized_whitespace); 953 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 954 == XML_STATUS_ERROR) 955 xml_failure(g_parser); 956 } 957 END_TEST 958 959 /* 960 * XML declaration tests. 961 */ 962 963 START_TEST(test_xmldecl_misplaced) { 964 expect_failure("\n" 965 "<?xml version='1.0'?>\n" 966 "<a/>", 967 XML_ERROR_MISPLACED_XML_PI, 968 "failed to report misplaced XML declaration"); 969 } 970 END_TEST 971 972 START_TEST(test_xmldecl_invalid) { 973 expect_failure("<?xml version='1.0' \xc3\xa7?>\n<doc/>", XML_ERROR_XML_DECL, 974 "Failed to report invalid XML declaration"); 975 } 976 END_TEST 977 978 START_TEST(test_xmldecl_missing_attr) { 979 expect_failure("<?xml ='1.0'?>\n<doc/>\n", XML_ERROR_XML_DECL, 980 "Failed to report missing XML declaration attribute"); 981 } 982 END_TEST 983 984 START_TEST(test_xmldecl_missing_value) { 985 expect_failure("<?xml version='1.0' encoding='us-ascii' standalone?>\n" 986 "<doc/>", 987 XML_ERROR_XML_DECL, 988 "Failed to report missing attribute value"); 989 } 990 END_TEST 991 992 START_TEST(test_xmldecl_empty_version) { 993 expect_failure("<?xml version=''?>\n" 994 "<doc/>", 995 XML_ERROR_XML_DECL, 996 "Failed to report empty version in XML declaration"); 997 } 998 END_TEST 999 1000 /* Regression test for SF bug #584832. */ 1001 START_TEST(test_unknown_encoding_internal_entity) { 1002 const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n" 1003 "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n" 1004 "<test a='&foo;'/>"; 1005 1006 XML_SetUnknownEncodingHandler(g_parser, UnknownEncodingHandler, NULL); 1007 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1008 == XML_STATUS_ERROR) 1009 xml_failure(g_parser); 1010 } 1011 END_TEST 1012 1013 /* Test unrecognised encoding handler */ 1014 START_TEST(test_unrecognised_encoding_internal_entity) { 1015 const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n" 1016 "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n" 1017 "<test a='&foo;'/>"; 1018 1019 XML_SetUnknownEncodingHandler(g_parser, UnrecognisedEncodingHandler, NULL); 1020 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1021 != XML_STATUS_ERROR) 1022 fail("Unrecognised encoding not rejected"); 1023 } 1024 END_TEST 1025 1026 /* Regression test for SF bug #620106. */ 1027 START_TEST(test_ext_entity_set_encoding) { 1028 const char *text = "<!DOCTYPE doc [\n" 1029 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 1030 "]>\n" 1031 "<doc>&en;</doc>"; 1032 ExtTest test_data 1033 = {/* This text says it's an unsupported encoding, but it's really 1034 UTF-8, which we tell Expat using XML_SetEncoding(). 1035 */ 1036 "<?xml encoding='iso-8859-3'?>\xC3\xA9", XCS("utf-8"), NULL}; 1037 #ifdef XML_UNICODE 1038 const XML_Char *expected = XCS("\x00e9"); 1039 #else 1040 const XML_Char *expected = XCS("\xc3\xa9"); 1041 #endif 1042 1043 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 1044 run_ext_character_check(text, &test_data, expected); 1045 } 1046 END_TEST 1047 1048 /* Test external entities with no handler */ 1049 START_TEST(test_ext_entity_no_handler) { 1050 const char *text = "<!DOCTYPE doc [\n" 1051 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 1052 "]>\n" 1053 "<doc>&en;</doc>"; 1054 1055 XML_SetDefaultHandler(g_parser, dummy_default_handler); 1056 run_character_check(text, XCS("")); 1057 } 1058 END_TEST 1059 1060 /* Test UTF-8 BOM is accepted */ 1061 START_TEST(test_ext_entity_set_bom) { 1062 const char *text = "<!DOCTYPE doc [\n" 1063 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 1064 "]>\n" 1065 "<doc>&en;</doc>"; 1066 ExtTest test_data = {"\xEF\xBB\xBF" /* BOM */ 1067 "<?xml encoding='iso-8859-3'?>" 1068 "\xC3\xA9", 1069 XCS("utf-8"), NULL}; 1070 #ifdef XML_UNICODE 1071 const XML_Char *expected = XCS("\x00e9"); 1072 #else 1073 const XML_Char *expected = XCS("\xc3\xa9"); 1074 #endif 1075 1076 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 1077 run_ext_character_check(text, &test_data, expected); 1078 } 1079 END_TEST 1080 1081 /* Test that bad encodings are faulted */ 1082 START_TEST(test_ext_entity_bad_encoding) { 1083 const char *text = "<!DOCTYPE doc [\n" 1084 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 1085 "]>\n" 1086 "<doc>&en;</doc>"; 1087 ExtFaults fault 1088 = {"<?xml encoding='iso-8859-3'?>u", "Unsupported encoding not faulted", 1089 XCS("unknown"), XML_ERROR_UNKNOWN_ENCODING}; 1090 1091 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter); 1092 XML_SetUserData(g_parser, &fault); 1093 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 1094 "Bad encoding should not have been accepted"); 1095 } 1096 END_TEST 1097 1098 /* Try handing an invalid encoding to an external entity parser */ 1099 START_TEST(test_ext_entity_bad_encoding_2) { 1100 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 1101 "<!DOCTYPE doc SYSTEM 'foo'>\n" 1102 "<doc>&entity;</doc>"; 1103 ExtFaults fault 1104 = {"<!ELEMENT doc (#PCDATA)*>", "Unknown encoding not faulted", 1105 XCS("unknown-encoding"), XML_ERROR_UNKNOWN_ENCODING}; 1106 1107 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 1108 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter); 1109 XML_SetUserData(g_parser, &fault); 1110 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 1111 "Bad encoding not faulted in external entity handler"); 1112 } 1113 END_TEST 1114 1115 /* Test that no error is reported for unknown entities if we don't 1116 read an external subset. This was fixed in Expat 1.95.5. 1117 */ 1118 START_TEST(test_wfc_undeclared_entity_unread_external_subset) { 1119 const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n" 1120 "<doc>&entity;</doc>"; 1121 1122 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1123 == XML_STATUS_ERROR) 1124 xml_failure(g_parser); 1125 } 1126 END_TEST 1127 1128 /* Test that an error is reported for unknown entities if we don't 1129 have an external subset. 1130 */ 1131 START_TEST(test_wfc_undeclared_entity_no_external_subset) { 1132 expect_failure("<doc>&entity;</doc>", XML_ERROR_UNDEFINED_ENTITY, 1133 "Parser did not report undefined entity w/out a DTD."); 1134 } 1135 END_TEST 1136 1137 /* Test that an error is reported for unknown entities if we don't 1138 read an external subset, but have been declared standalone. 1139 */ 1140 START_TEST(test_wfc_undeclared_entity_standalone) { 1141 const char *text 1142 = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n" 1143 "<!DOCTYPE doc SYSTEM 'foo'>\n" 1144 "<doc>&entity;</doc>"; 1145 1146 expect_failure(text, XML_ERROR_UNDEFINED_ENTITY, 1147 "Parser did not report undefined entity (standalone)."); 1148 } 1149 END_TEST 1150 1151 /* Test that an error is reported for unknown entities if we have read 1152 an external subset, and standalone is true. 1153 */ 1154 START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) { 1155 const char *text 1156 = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n" 1157 "<!DOCTYPE doc SYSTEM 'foo'>\n" 1158 "<doc>&entity;</doc>"; 1159 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL}; 1160 1161 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 1162 XML_SetUserData(g_parser, &test_data); 1163 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 1164 expect_failure(text, XML_ERROR_UNDEFINED_ENTITY, 1165 "Parser did not report undefined entity (external DTD)."); 1166 } 1167 END_TEST 1168 1169 /* Test that external entity handling is not done if the parsing flag 1170 * is set to UNLESS_STANDALONE 1171 */ 1172 START_TEST(test_entity_with_external_subset_unless_standalone) { 1173 const char *text 1174 = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n" 1175 "<!DOCTYPE doc SYSTEM 'foo'>\n" 1176 "<doc>&entity;</doc>"; 1177 ExtTest test_data = {"<!ENTITY entity 'bar'>", NULL, NULL}; 1178 1179 XML_SetParamEntityParsing(g_parser, 1180 XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE); 1181 XML_SetUserData(g_parser, &test_data); 1182 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 1183 expect_failure(text, XML_ERROR_UNDEFINED_ENTITY, 1184 "Parser did not report undefined entity"); 1185 } 1186 END_TEST 1187 1188 /* Test that no error is reported for unknown entities if we have read 1189 an external subset, and standalone is false. 1190 */ 1191 START_TEST(test_wfc_undeclared_entity_with_external_subset) { 1192 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 1193 "<!DOCTYPE doc SYSTEM 'foo'>\n" 1194 "<doc>&entity;</doc>"; 1195 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL}; 1196 1197 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 1198 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 1199 run_ext_character_check(text, &test_data, XCS("")); 1200 } 1201 END_TEST 1202 1203 /* Test that an error is reported if our NotStandalone handler fails */ 1204 START_TEST(test_not_standalone_handler_reject) { 1205 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 1206 "<!DOCTYPE doc SYSTEM 'foo'>\n" 1207 "<doc>&entity;</doc>"; 1208 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL}; 1209 1210 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 1211 XML_SetUserData(g_parser, &test_data); 1212 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 1213 XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler); 1214 expect_failure(text, XML_ERROR_NOT_STANDALONE, 1215 "NotStandalone handler failed to reject"); 1216 1217 /* Try again but without external entity handling */ 1218 XML_ParserReset(g_parser, NULL); 1219 XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler); 1220 expect_failure(text, XML_ERROR_NOT_STANDALONE, 1221 "NotStandalone handler failed to reject"); 1222 } 1223 END_TEST 1224 1225 /* Test that no error is reported if our NotStandalone handler succeeds */ 1226 START_TEST(test_not_standalone_handler_accept) { 1227 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 1228 "<!DOCTYPE doc SYSTEM 'foo'>\n" 1229 "<doc>&entity;</doc>"; 1230 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL}; 1231 1232 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 1233 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 1234 XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler); 1235 run_ext_character_check(text, &test_data, XCS("")); 1236 1237 /* Repeat without the external entity handler */ 1238 XML_ParserReset(g_parser, NULL); 1239 XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler); 1240 run_character_check(text, XCS("")); 1241 } 1242 END_TEST 1243 1244 START_TEST(test_entity_start_tag_level_greater_than_one) { 1245 const char *const text = "<!DOCTYPE t1 [\n" 1246 " <!ENTITY e1 'hello'>\n" 1247 "]>\n" 1248 "<t1>\n" 1249 " <t2>&e1;</t2>\n" 1250 "</t1>\n"; 1251 1252 XML_Parser parser = XML_ParserCreate(NULL); 1253 assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), 1254 /*isFinal*/ XML_TRUE) 1255 == XML_STATUS_OK); 1256 XML_ParserFree(parser); 1257 } 1258 END_TEST 1259 1260 START_TEST(test_wfc_no_recursive_entity_refs) { 1261 const char *text = "<!DOCTYPE doc [\n" 1262 " <!ENTITY entity '&entity;'>\n" 1263 "]>\n" 1264 "<doc>&entity;</doc>"; 1265 1266 expect_failure(text, XML_ERROR_RECURSIVE_ENTITY_REF, 1267 "Parser did not report recursive entity reference."); 1268 } 1269 END_TEST 1270 1271 START_TEST(test_no_indirectly_recursive_entity_refs) { 1272 struct TestCase { 1273 const char *doc; 1274 bool usesParameterEntities; 1275 }; 1276 1277 const struct TestCase cases[] = { 1278 // general entity + character data 1279 {"<!DOCTYPE a [\n" 1280 " <!ENTITY e1 '&e2;'>\n" 1281 " <!ENTITY e2 '&e1;'>\n" 1282 "]><a>&e2;</a>\n", 1283 false}, 1284 1285 // general entity + attribute value 1286 {"<!DOCTYPE a [\n" 1287 " <!ENTITY e1 '&e2;'>\n" 1288 " <!ENTITY e2 '&e1;'>\n" 1289 "]><a k1='&e2;' />\n", 1290 false}, 1291 1292 // parameter entity 1293 {"<!DOCTYPE doc [\n" 1294 " <!ENTITY % p1 '%p2;'>\n" 1295 " <!ENTITY % p2 '%p1;'>\n" 1296 " <!ENTITY % define_g \"<!ENTITY g '%p2;'>\">\n" 1297 " %define_g;\n" 1298 "]>\n" 1299 "<doc/>\n", 1300 true}, 1301 }; 1302 const XML_Bool reset_or_not[] = {XML_TRUE, XML_FALSE}; 1303 1304 for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { 1305 for (size_t j = 0; j < sizeof(reset_or_not) / sizeof(reset_or_not[0]); 1306 j++) { 1307 const XML_Bool reset_wanted = reset_or_not[j]; 1308 const char *const doc = cases[i].doc; 1309 const bool usesParameterEntities = cases[i].usesParameterEntities; 1310 1311 set_subtest("[%i,reset=%i] %s", (int)i, (int)j, doc); 1312 1313 #ifdef XML_DTD // both GE and DTD 1314 const bool rejection_expected = true; 1315 #elif XML_GE == 1 // GE but not DTD 1316 const bool rejection_expected = ! usesParameterEntities; 1317 #else // neither DTD nor GE 1318 const bool rejection_expected = false; 1319 #endif 1320 1321 XML_Parser parser = XML_ParserCreate(NULL); 1322 1323 #ifdef XML_DTD 1324 if (usesParameterEntities) { 1325 assert_true( 1326 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS) 1327 == 1); 1328 } 1329 #else 1330 UNUSED_P(usesParameterEntities); 1331 #endif // XML_DTD 1332 1333 const enum XML_Status status 1334 = _XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), 1335 /*isFinal*/ XML_TRUE); 1336 1337 if (rejection_expected) { 1338 assert_true(status == XML_STATUS_ERROR); 1339 assert_true(XML_GetErrorCode(parser) == XML_ERROR_RECURSIVE_ENTITY_REF); 1340 } else { 1341 assert_true(status == XML_STATUS_OK); 1342 } 1343 1344 if (reset_wanted) { 1345 // This covers free'ing of (eventually) all three open entity lists by 1346 // XML_ParserReset. 1347 XML_ParserReset(parser, NULL); 1348 } 1349 1350 // This covers free'ing of (eventually) all three open entity lists by 1351 // XML_ParserFree (unless XML_ParserReset has already done that above). 1352 XML_ParserFree(parser); 1353 } 1354 } 1355 } 1356 END_TEST 1357 1358 START_TEST(test_recursive_external_parameter_entity_2) { 1359 struct TestCase { 1360 const char *doc; 1361 enum XML_Status expectedStatus; 1362 }; 1363 1364 struct TestCase cases[] = { 1365 {"<!ENTITY % p1 '%p1;'>", XML_STATUS_ERROR}, 1366 {"<!ENTITY % p1 '%p1;'>" 1367 "<!ENTITY % p1 'first declaration wins'>", 1368 XML_STATUS_ERROR}, 1369 {"<!ENTITY % p1 'first declaration wins'>" 1370 "<!ENTITY % p1 '%p1;'>", 1371 XML_STATUS_OK}, 1372 {"<!ENTITY % p1 '%p1;'>", XML_STATUS_OK}, 1373 }; 1374 1375 for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { 1376 const char *const doc = cases[i].doc; 1377 const enum XML_Status expectedStatus = cases[i].expectedStatus; 1378 set_subtest("%s", doc); 1379 1380 XML_Parser parser = XML_ParserCreate(NULL); 1381 assert_true(parser != NULL); 1382 1383 XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, NULL, NULL); 1384 assert_true(ext_parser != NULL); 1385 1386 const enum XML_Status actualStatus 1387 = _XML_Parse_SINGLE_BYTES(ext_parser, doc, (int)strlen(doc), XML_TRUE); 1388 1389 assert_true(actualStatus == expectedStatus); 1390 if (actualStatus != XML_STATUS_OK) { 1391 assert_true(XML_GetErrorCode(ext_parser) 1392 == XML_ERROR_RECURSIVE_ENTITY_REF); 1393 } 1394 1395 XML_ParserFree(ext_parser); 1396 XML_ParserFree(parser); 1397 } 1398 } 1399 END_TEST 1400 1401 /* Test incomplete external entities are faulted */ 1402 START_TEST(test_ext_entity_invalid_parse) { 1403 const char *text = "<!DOCTYPE doc [\n" 1404 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 1405 "]>\n" 1406 "<doc>&en;</doc>"; 1407 const ExtFaults faults[] 1408 = {{"<", "Incomplete element declaration not faulted", NULL, 1409 XML_ERROR_UNCLOSED_TOKEN}, 1410 {"<\xe2\x82", /* First two bytes of a three-byte char */ 1411 "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR}, 1412 {"<tag>\xe2\x82", "Incomplete character in CDATA not faulted", NULL, 1413 XML_ERROR_PARTIAL_CHAR}, 1414 {NULL, NULL, NULL, XML_ERROR_NONE}}; 1415 const ExtFaults *fault = faults; 1416 1417 for (; fault->parse_text != NULL; fault++) { 1418 set_subtest("\"%s\"", fault->parse_text); 1419 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 1420 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter); 1421 XML_SetUserData(g_parser, (void *)fault); 1422 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 1423 "Parser did not report external entity error"); 1424 XML_ParserReset(g_parser, NULL); 1425 } 1426 } 1427 END_TEST 1428 1429 /* Regression test for SF bug #483514. */ 1430 START_TEST(test_dtd_default_handling) { 1431 const char *text = "<!DOCTYPE doc [\n" 1432 "<!ENTITY e SYSTEM 'http://example.org/e'>\n" 1433 "<!NOTATION n SYSTEM 'http://example.org/n'>\n" 1434 "<!ELEMENT doc EMPTY>\n" 1435 "<!ATTLIST doc a CDATA #IMPLIED>\n" 1436 "<?pi in dtd?>\n" 1437 "<!--comment in dtd-->\n" 1438 "]><doc/>"; 1439 1440 XML_SetDefaultHandler(g_parser, accumulate_characters); 1441 XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler); 1442 XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler); 1443 XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler); 1444 XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler); 1445 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler); 1446 XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler); 1447 XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler); 1448 XML_SetCommentHandler(g_parser, dummy_comment_handler); 1449 XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler); 1450 XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler); 1451 run_character_check(text, XCS("\n\n\n\n\n\n\n<doc/>")); 1452 } 1453 END_TEST 1454 1455 /* Test handling of attribute declarations */ 1456 START_TEST(test_dtd_attr_handling) { 1457 const char *prolog = "<!DOCTYPE doc [\n" 1458 "<!ELEMENT doc EMPTY>\n"; 1459 AttTest attr_data[] 1460 = {{"<!ATTLIST doc a ( one | two | three ) #REQUIRED>\n" 1461 "]>" 1462 "<doc a='two'/>", 1463 XCS("doc"), XCS("a"), 1464 XCS("(one|two|three)"), /* Extraneous spaces will be removed */ 1465 NULL, XML_TRUE}, 1466 {"<!NOTATION foo SYSTEM 'http://example.org/foo'>\n" 1467 "<!ATTLIST doc a NOTATION (foo) #IMPLIED>\n" 1468 "]>" 1469 "<doc/>", 1470 XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), NULL, XML_FALSE}, 1471 {"<!ATTLIST doc a NOTATION (foo) 'bar'>\n" 1472 "]>" 1473 "<doc/>", 1474 XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), XCS("bar"), XML_FALSE}, 1475 {"<!ATTLIST doc a CDATA '\xdb\xb2'>\n" 1476 "]>" 1477 "<doc/>", 1478 XCS("doc"), XCS("a"), XCS("CDATA"), 1479 #ifdef XML_UNICODE 1480 XCS("\x06f2"), 1481 #else 1482 XCS("\xdb\xb2"), 1483 #endif 1484 XML_FALSE}, 1485 {NULL, NULL, NULL, NULL, NULL, XML_FALSE}}; 1486 AttTest *test; 1487 1488 for (test = attr_data; test->definition != NULL; test++) { 1489 set_subtest("%s", test->definition); 1490 XML_SetAttlistDeclHandler(g_parser, verify_attlist_decl_handler); 1491 XML_SetUserData(g_parser, test); 1492 if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)strlen(prolog), 1493 XML_FALSE) 1494 == XML_STATUS_ERROR) 1495 xml_failure(g_parser); 1496 if (_XML_Parse_SINGLE_BYTES(g_parser, test->definition, 1497 (int)strlen(test->definition), XML_TRUE) 1498 == XML_STATUS_ERROR) 1499 xml_failure(g_parser); 1500 XML_ParserReset(g_parser, NULL); 1501 } 1502 } 1503 END_TEST 1504 1505 /* See related SF bug #673791. 1506 When namespace processing is enabled, setting the namespace URI for 1507 a prefix is not allowed; this test ensures that it *is* allowed 1508 when namespace processing is not enabled. 1509 (See Namespaces in XML, section 2.) 1510 */ 1511 START_TEST(test_empty_ns_without_namespaces) { 1512 const char *text = "<doc xmlns:prefix='http://example.org/'>\n" 1513 " <e xmlns:prefix=''/>\n" 1514 "</doc>"; 1515 1516 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1517 == XML_STATUS_ERROR) 1518 xml_failure(g_parser); 1519 } 1520 END_TEST 1521 1522 /* Regression test for SF bug #824420. 1523 Checks that an xmlns:prefix attribute set in an attribute's default 1524 value isn't misinterpreted. 1525 */ 1526 START_TEST(test_ns_in_attribute_default_without_namespaces) { 1527 const char *text = "<!DOCTYPE e:element [\n" 1528 " <!ATTLIST e:element\n" 1529 " xmlns:e CDATA 'http://example.org/'>\n" 1530 " ]>\n" 1531 "<e:element/>"; 1532 1533 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1534 == XML_STATUS_ERROR) 1535 xml_failure(g_parser); 1536 } 1537 END_TEST 1538 1539 /* Regression test for SF bug #1515266: missing check of stopped 1540 parser in doContext() 'for' loop. */ 1541 START_TEST(test_stop_parser_between_char_data_calls) { 1542 /* The sample data must be big enough that there are two calls to 1543 the character data handler from within the inner "for" loop of 1544 the XML_TOK_DATA_CHARS case in doContent(), and the character 1545 handler must stop the parser and clear the character data 1546 handler. 1547 */ 1548 const char *text = long_character_data_text; 1549 1550 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler); 1551 g_resumable = XML_FALSE; 1552 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1553 != XML_STATUS_ERROR) 1554 xml_failure(g_parser); 1555 if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED) 1556 xml_failure(g_parser); 1557 } 1558 END_TEST 1559 1560 /* Regression test for SF bug #1515266: missing check of stopped 1561 parser in doContext() 'for' loop. */ 1562 START_TEST(test_suspend_parser_between_char_data_calls) { 1563 /* The sample data must be big enough that there are two calls to 1564 the character data handler from within the inner "for" loop of 1565 the XML_TOK_DATA_CHARS case in doContent(), and the character 1566 handler must stop the parser and clear the character data 1567 handler. 1568 */ 1569 const char *text = long_character_data_text; 1570 1571 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler); 1572 g_resumable = XML_TRUE; 1573 // can't use SINGLE_BYTES here, because it'll return early on suspension, and 1574 // we won't know exactly how much input we actually managed to give Expat. 1575 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) 1576 != XML_STATUS_SUSPENDED) 1577 xml_failure(g_parser); 1578 if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE) 1579 xml_failure(g_parser); 1580 /* Try parsing directly */ 1581 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1582 != XML_STATUS_ERROR) 1583 fail("Attempt to continue parse while suspended not faulted"); 1584 if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED) 1585 fail("Suspended parse not faulted with correct error"); 1586 } 1587 END_TEST 1588 1589 /* Test repeated calls to XML_StopParser are handled correctly */ 1590 START_TEST(test_repeated_stop_parser_between_char_data_calls) { 1591 const char *text = long_character_data_text; 1592 1593 XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler); 1594 g_resumable = XML_FALSE; 1595 g_abortable = XML_FALSE; 1596 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1597 != XML_STATUS_ERROR) 1598 fail("Failed to double-stop parser"); 1599 1600 XML_ParserReset(g_parser, NULL); 1601 XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler); 1602 g_resumable = XML_TRUE; 1603 g_abortable = XML_FALSE; 1604 // can't use SINGLE_BYTES here, because it'll return early on suspension, and 1605 // we won't know exactly how much input we actually managed to give Expat. 1606 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) 1607 != XML_STATUS_SUSPENDED) 1608 fail("Failed to double-suspend parser"); 1609 1610 XML_ParserReset(g_parser, NULL); 1611 XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler); 1612 g_resumable = XML_TRUE; 1613 g_abortable = XML_TRUE; 1614 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1615 != XML_STATUS_ERROR) 1616 fail("Failed to suspend-abort parser"); 1617 } 1618 END_TEST 1619 1620 START_TEST(test_good_cdata_ascii) { 1621 const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>"; 1622 const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>"); 1623 1624 CharData storage; 1625 CharData_Init(&storage); 1626 XML_SetUserData(g_parser, &storage); 1627 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 1628 /* Add start and end handlers for coverage */ 1629 XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler); 1630 XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler); 1631 1632 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1633 == XML_STATUS_ERROR) 1634 xml_failure(g_parser); 1635 CharData_CheckXMLChars(&storage, expected); 1636 1637 /* Try again, this time with a default handler */ 1638 XML_ParserReset(g_parser, NULL); 1639 CharData_Init(&storage); 1640 XML_SetUserData(g_parser, &storage); 1641 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 1642 XML_SetDefaultHandler(g_parser, dummy_default_handler); 1643 1644 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 1645 == XML_STATUS_ERROR) 1646 xml_failure(g_parser); 1647 CharData_CheckXMLChars(&storage, expected); 1648 } 1649 END_TEST 1650 1651 START_TEST(test_good_cdata_utf16) { 1652 /* Test data is: 1653 * <?xml version='1.0' encoding='utf-16'?> 1654 * <a><![CDATA[hello]]></a> 1655 */ 1656 const char text[] 1657 = "\0<\0?\0x\0m\0l\0" 1658 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0" 1659 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0" 1660 "1\0" 1661 "6\0'" 1662 "\0?\0>\0\n" 1663 "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>"; 1664 const XML_Char *expected = XCS("hello"); 1665 1666 CharData storage; 1667 CharData_Init(&storage); 1668 XML_SetUserData(g_parser, &storage); 1669 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 1670 1671 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 1672 == XML_STATUS_ERROR) 1673 xml_failure(g_parser); 1674 CharData_CheckXMLChars(&storage, expected); 1675 } 1676 END_TEST 1677 1678 START_TEST(test_good_cdata_utf16_le) { 1679 /* Test data is: 1680 * <?xml version='1.0' encoding='utf-16'?> 1681 * <a><![CDATA[hello]]></a> 1682 */ 1683 const char text[] 1684 = "<\0?\0x\0m\0l\0" 1685 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0" 1686 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0" 1687 "1\0" 1688 "6\0'" 1689 "\0?\0>\0\n" 1690 "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>\0"; 1691 const XML_Char *expected = XCS("hello"); 1692 1693 CharData storage; 1694 CharData_Init(&storage); 1695 XML_SetUserData(g_parser, &storage); 1696 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 1697 1698 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 1699 == XML_STATUS_ERROR) 1700 xml_failure(g_parser); 1701 CharData_CheckXMLChars(&storage, expected); 1702 } 1703 END_TEST 1704 1705 /* Test UTF16 conversion of a long cdata string */ 1706 1707 /* 16 characters: handy macro to reduce visual clutter */ 1708 #define A_TO_P_IN_UTF16 "\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P" 1709 1710 START_TEST(test_long_cdata_utf16) { 1711 /* Test data is: 1712 * <?xlm version='1.0' encoding='utf-16'?> 1713 * <a><![CDATA[ 1714 * ABCDEFGHIJKLMNOP 1715 * ]]></a> 1716 */ 1717 const char text[] 1718 = "\0<\0?\0x\0m\0l\0 " 1719 "\0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0 " 1720 "\0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0\x31\0\x36\0'\0?\0>" 1721 "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[" 1722 /* 64 characters per line */ 1723 /* clang-format off */ 1724 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1725 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1726 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1727 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1728 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1729 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1730 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1731 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1732 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1733 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1734 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1735 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1736 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1737 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1738 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1739 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 1740 A_TO_P_IN_UTF16 1741 /* clang-format on */ 1742 "\0]\0]\0>\0<\0/\0a\0>"; 1743 const XML_Char *expected = 1744 /* clang-format off */ 1745 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1746 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1747 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1748 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1749 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1750 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1751 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1752 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1753 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1754 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1755 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1756 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1757 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1758 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1759 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1760 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP") 1761 XCS("ABCDEFGHIJKLMNOP"); 1762 /* clang-format on */ 1763 CharData storage; 1764 void *buffer; 1765 1766 CharData_Init(&storage); 1767 XML_SetUserData(g_parser, &storage); 1768 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 1769 buffer = XML_GetBuffer(g_parser, sizeof(text) - 1); 1770 if (buffer == NULL) 1771 fail("Could not allocate parse buffer"); 1772 assert(buffer != NULL); 1773 memcpy(buffer, text, sizeof(text) - 1); 1774 if (XML_ParseBuffer(g_parser, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR) 1775 xml_failure(g_parser); 1776 CharData_CheckXMLChars(&storage, expected); 1777 } 1778 END_TEST 1779 1780 /* Test handling of multiple unit UTF-16 characters */ 1781 START_TEST(test_multichar_cdata_utf16) { 1782 /* Test data is: 1783 * <?xml version='1.0' encoding='utf-16'?> 1784 * <a><![CDATA[{MINIM}{CROTCHET}]]></a> 1785 * 1786 * where {MINIM} is U+1d15e (a minim or half-note) 1787 * UTF-16: 0xd834 0xdd5e 1788 * UTF-8: 0xf0 0x9d 0x85 0x9e 1789 * and {CROTCHET} is U+1d15f (a crotchet or quarter-note) 1790 * UTF-16: 0xd834 0xdd5f 1791 * UTF-8: 0xf0 0x9d 0x85 0x9f 1792 */ 1793 const char text[] = "\0<\0?\0x\0m\0l\0" 1794 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0" 1795 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0" 1796 "1\0" 1797 "6\0'" 1798 "\0?\0>\0\n" 1799 "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[" 1800 "\xd8\x34\xdd\x5e\xd8\x34\xdd\x5f" 1801 "\0]\0]\0>\0<\0/\0a\0>"; 1802 #ifdef XML_UNICODE 1803 const XML_Char *expected = XCS("\xd834\xdd5e\xd834\xdd5f"); 1804 #else 1805 const XML_Char *expected = XCS("\xf0\x9d\x85\x9e\xf0\x9d\x85\x9f"); 1806 #endif 1807 CharData storage; 1808 1809 CharData_Init(&storage); 1810 XML_SetUserData(g_parser, &storage); 1811 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 1812 1813 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 1814 == XML_STATUS_ERROR) 1815 xml_failure(g_parser); 1816 CharData_CheckXMLChars(&storage, expected); 1817 } 1818 END_TEST 1819 1820 /* Test that an element name with a UTF-16 surrogate pair is rejected */ 1821 START_TEST(test_utf16_bad_surrogate_pair) { 1822 /* Test data is: 1823 * <?xml version='1.0' encoding='utf-16'?> 1824 * <a><![CDATA[{BADLINB}]]></a> 1825 * 1826 * where {BADLINB} is U+10000 (the first Linear B character) 1827 * with the UTF-16 surrogate pair in the wrong order, i.e. 1828 * 0xdc00 0xd800 1829 */ 1830 const char text[] = "\0<\0?\0x\0m\0l\0" 1831 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0" 1832 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0" 1833 "1\0" 1834 "6\0'" 1835 "\0?\0>\0\n" 1836 "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[" 1837 "\xdc\x00\xd8\x00" 1838 "\0]\0]\0>\0<\0/\0a\0>"; 1839 1840 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 1841 != XML_STATUS_ERROR) 1842 fail("Reversed UTF-16 surrogate pair not faulted"); 1843 if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN) 1844 xml_failure(g_parser); 1845 } 1846 END_TEST 1847 1848 START_TEST(test_bad_cdata) { 1849 struct CaseData { 1850 const char *text; 1851 enum XML_Error expectedError; 1852 }; 1853 1854 struct CaseData cases[] 1855 = {{"<a><", XML_ERROR_UNCLOSED_TOKEN}, 1856 {"<a><!", XML_ERROR_UNCLOSED_TOKEN}, 1857 {"<a><![", XML_ERROR_UNCLOSED_TOKEN}, 1858 {"<a><![C", XML_ERROR_UNCLOSED_TOKEN}, 1859 {"<a><![CD", XML_ERROR_UNCLOSED_TOKEN}, 1860 {"<a><![CDA", XML_ERROR_UNCLOSED_TOKEN}, 1861 {"<a><![CDAT", XML_ERROR_UNCLOSED_TOKEN}, 1862 {"<a><![CDATA", XML_ERROR_UNCLOSED_TOKEN}, 1863 1864 {"<a><![CDATA[", XML_ERROR_UNCLOSED_CDATA_SECTION}, 1865 {"<a><![CDATA[]", XML_ERROR_UNCLOSED_CDATA_SECTION}, 1866 {"<a><![CDATA[]]", XML_ERROR_UNCLOSED_CDATA_SECTION}, 1867 1868 {"<a><!<a/>", XML_ERROR_INVALID_TOKEN}, 1869 {"<a><![<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */ 1870 {"<a><![C<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */ 1871 {"<a><![CD<a/>", XML_ERROR_INVALID_TOKEN}, 1872 {"<a><![CDA<a/>", XML_ERROR_INVALID_TOKEN}, 1873 {"<a><![CDAT<a/>", XML_ERROR_INVALID_TOKEN}, 1874 {"<a><![CDATA<a/>", XML_ERROR_INVALID_TOKEN}, 1875 1876 {"<a><![CDATA[<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION}, 1877 {"<a><![CDATA[]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION}, 1878 {"<a><![CDATA[]]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION}}; 1879 1880 size_t i = 0; 1881 for (; i < sizeof(cases) / sizeof(struct CaseData); i++) { 1882 set_subtest("%s", cases[i].text); 1883 const enum XML_Status actualStatus = _XML_Parse_SINGLE_BYTES( 1884 g_parser, cases[i].text, (int)strlen(cases[i].text), XML_TRUE); 1885 const enum XML_Error actualError = XML_GetErrorCode(g_parser); 1886 1887 assert(actualStatus == XML_STATUS_ERROR); 1888 1889 if (actualError != cases[i].expectedError) { 1890 char message[100]; 1891 snprintf(message, sizeof(message), 1892 "Expected error %d but got error %d for case %u: \"%s\"\n", 1893 cases[i].expectedError, actualError, (unsigned int)i + 1, 1894 cases[i].text); 1895 fail(message); 1896 } 1897 1898 XML_ParserReset(g_parser, NULL); 1899 } 1900 } 1901 END_TEST 1902 1903 /* Test failures in UTF-16 CDATA */ 1904 START_TEST(test_bad_cdata_utf16) { 1905 struct CaseData { 1906 size_t text_bytes; 1907 const char *text; 1908 enum XML_Error expected_error; 1909 }; 1910 1911 const char prolog[] = "\0<\0?\0x\0m\0l\0" 1912 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0" 1913 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0" 1914 "1\0" 1915 "6\0'" 1916 "\0?\0>\0\n" 1917 "\0<\0a\0>"; 1918 struct CaseData cases[] = { 1919 {1, "\0", XML_ERROR_UNCLOSED_TOKEN}, 1920 {2, "\0<", XML_ERROR_UNCLOSED_TOKEN}, 1921 {3, "\0<\0", XML_ERROR_UNCLOSED_TOKEN}, 1922 {4, "\0<\0!", XML_ERROR_UNCLOSED_TOKEN}, 1923 {5, "\0<\0!\0", XML_ERROR_UNCLOSED_TOKEN}, 1924 {6, "\0<\0!\0[", XML_ERROR_UNCLOSED_TOKEN}, 1925 {7, "\0<\0!\0[\0", XML_ERROR_UNCLOSED_TOKEN}, 1926 {8, "\0<\0!\0[\0C", XML_ERROR_UNCLOSED_TOKEN}, 1927 {9, "\0<\0!\0[\0C\0", XML_ERROR_UNCLOSED_TOKEN}, 1928 {10, "\0<\0!\0[\0C\0D", XML_ERROR_UNCLOSED_TOKEN}, 1929 {11, "\0<\0!\0[\0C\0D\0", XML_ERROR_UNCLOSED_TOKEN}, 1930 {12, "\0<\0!\0[\0C\0D\0A", XML_ERROR_UNCLOSED_TOKEN}, 1931 {13, "\0<\0!\0[\0C\0D\0A\0", XML_ERROR_UNCLOSED_TOKEN}, 1932 {14, "\0<\0!\0[\0C\0D\0A\0T", XML_ERROR_UNCLOSED_TOKEN}, 1933 {15, "\0<\0!\0[\0C\0D\0A\0T\0", XML_ERROR_UNCLOSED_TOKEN}, 1934 {16, "\0<\0!\0[\0C\0D\0A\0T\0A", XML_ERROR_UNCLOSED_TOKEN}, 1935 {17, "\0<\0!\0[\0C\0D\0A\0T\0A\0", XML_ERROR_UNCLOSED_TOKEN}, 1936 {18, "\0<\0!\0[\0C\0D\0A\0T\0A\0[", XML_ERROR_UNCLOSED_CDATA_SECTION}, 1937 {19, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0", XML_ERROR_UNCLOSED_CDATA_SECTION}, 1938 {20, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z", XML_ERROR_UNCLOSED_CDATA_SECTION}, 1939 /* Now add a four-byte UTF-16 character */ 1940 {21, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8", 1941 XML_ERROR_UNCLOSED_CDATA_SECTION}, 1942 {22, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34", XML_ERROR_PARTIAL_CHAR}, 1943 {23, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd", 1944 XML_ERROR_PARTIAL_CHAR}, 1945 {24, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd\x5e", 1946 XML_ERROR_UNCLOSED_CDATA_SECTION}}; 1947 size_t i; 1948 1949 for (i = 0; i < sizeof(cases) / sizeof(struct CaseData); i++) { 1950 set_subtest("case %lu", (long unsigned)(i + 1)); 1951 enum XML_Status actual_status; 1952 enum XML_Error actual_error; 1953 1954 if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)sizeof(prolog) - 1, 1955 XML_FALSE) 1956 == XML_STATUS_ERROR) 1957 xml_failure(g_parser); 1958 actual_status = _XML_Parse_SINGLE_BYTES(g_parser, cases[i].text, 1959 (int)cases[i].text_bytes, XML_TRUE); 1960 assert(actual_status == XML_STATUS_ERROR); 1961 actual_error = XML_GetErrorCode(g_parser); 1962 if (actual_error != cases[i].expected_error) { 1963 char message[1024]; 1964 1965 snprintf(message, sizeof(message), 1966 "Expected error %d (%" XML_FMT_STR "), got %d (%" XML_FMT_STR 1967 ") for case %lu\n", 1968 cases[i].expected_error, 1969 XML_ErrorString(cases[i].expected_error), actual_error, 1970 XML_ErrorString(actual_error), (long unsigned)(i + 1)); 1971 fail(message); 1972 } 1973 XML_ParserReset(g_parser, NULL); 1974 } 1975 } 1976 END_TEST 1977 1978 /* Test stopping the parser in cdata handler */ 1979 START_TEST(test_stop_parser_between_cdata_calls) { 1980 const char *text = long_cdata_text; 1981 1982 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler); 1983 g_resumable = XML_FALSE; 1984 expect_failure(text, XML_ERROR_ABORTED, "Parse not aborted in CDATA handler"); 1985 } 1986 END_TEST 1987 1988 /* Test suspending the parser in cdata handler */ 1989 START_TEST(test_suspend_parser_between_cdata_calls) { 1990 if (g_chunkSize != 0) { 1991 // this test does not use SINGLE_BYTES, because of suspension 1992 return; 1993 } 1994 1995 const char *text = long_cdata_text; 1996 enum XML_Status result; 1997 1998 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler); 1999 g_resumable = XML_TRUE; 2000 // can't use SINGLE_BYTES here, because it'll return early on suspension, and 2001 // we won't know exactly how much input we actually managed to give Expat. 2002 result = XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE); 2003 if (result != XML_STATUS_SUSPENDED) { 2004 if (result == XML_STATUS_ERROR) 2005 xml_failure(g_parser); 2006 fail("Parse not suspended in CDATA handler"); 2007 } 2008 if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE) 2009 xml_failure(g_parser); 2010 } 2011 END_TEST 2012 2013 /* Test memory allocation functions */ 2014 START_TEST(test_memory_allocation) { 2015 char *buffer = (char *)XML_MemMalloc(g_parser, 256); 2016 char *p; 2017 2018 if (buffer == NULL) { 2019 fail("Allocation failed"); 2020 } else { 2021 /* Try writing to memory; some OSes try to cheat! */ 2022 buffer[0] = 'T'; 2023 buffer[1] = 'E'; 2024 buffer[2] = 'S'; 2025 buffer[3] = 'T'; 2026 buffer[4] = '\0'; 2027 if (strcmp(buffer, "TEST") != 0) { 2028 fail("Memory not writable"); 2029 } else { 2030 p = (char *)XML_MemRealloc(g_parser, buffer, 512); 2031 if (p == NULL) { 2032 fail("Reallocation failed"); 2033 } else { 2034 /* Write again, just to be sure */ 2035 buffer = p; 2036 buffer[0] = 'V'; 2037 if (strcmp(buffer, "VEST") != 0) { 2038 fail("Reallocated memory not writable"); 2039 } 2040 } 2041 } 2042 XML_MemFree(g_parser, buffer); 2043 } 2044 } 2045 END_TEST 2046 2047 /* Test XML_DefaultCurrent() passes handling on correctly */ 2048 START_TEST(test_default_current) { 2049 const char *text = "<doc>hell]</doc>"; 2050 const char *entity_text = "<!DOCTYPE doc [\n" 2051 "<!ENTITY entity '%'>\n" 2052 "]>\n" 2053 "<doc>&entity;</doc>"; 2054 2055 set_subtest("with defaulting"); 2056 { 2057 struct handler_record_list storage; 2058 storage.count = 0; 2059 XML_SetDefaultHandler(g_parser, record_default_handler); 2060 XML_SetCharacterDataHandler(g_parser, record_cdata_handler); 2061 XML_SetUserData(g_parser, &storage); 2062 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 2063 == XML_STATUS_ERROR) 2064 xml_failure(g_parser); 2065 int i = 0; 2066 assert_record_handler_called(&storage, i++, "record_default_handler", 5); 2067 // we should have gotten one or more cdata callbacks, totaling 5 chars 2068 int cdata_len_remaining = 5; 2069 while (cdata_len_remaining > 0) { 2070 const struct handler_record_entry *c_entry 2071 = handler_record_get(&storage, i++); 2072 assert_true(strcmp(c_entry->name, "record_cdata_handler") == 0); 2073 assert_true(c_entry->arg > 0); 2074 assert_true(c_entry->arg <= cdata_len_remaining); 2075 cdata_len_remaining -= c_entry->arg; 2076 // default handler must follow, with the exact same len argument. 2077 assert_record_handler_called(&storage, i++, "record_default_handler", 2078 c_entry->arg); 2079 } 2080 assert_record_handler_called(&storage, i++, "record_default_handler", 6); 2081 assert_true(storage.count == i); 2082 } 2083 2084 /* Again, without the defaulting */ 2085 set_subtest("no defaulting"); 2086 { 2087 struct handler_record_list storage; 2088 storage.count = 0; 2089 XML_ParserReset(g_parser, NULL); 2090 XML_SetDefaultHandler(g_parser, record_default_handler); 2091 XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler); 2092 XML_SetUserData(g_parser, &storage); 2093 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 2094 == XML_STATUS_ERROR) 2095 xml_failure(g_parser); 2096 int i = 0; 2097 assert_record_handler_called(&storage, i++, "record_default_handler", 5); 2098 // we should have gotten one or more cdata callbacks, totaling 5 chars 2099 int cdata_len_remaining = 5; 2100 while (cdata_len_remaining > 0) { 2101 const struct handler_record_entry *c_entry 2102 = handler_record_get(&storage, i++); 2103 assert_true(strcmp(c_entry->name, "record_cdata_nodefault_handler") == 0); 2104 assert_true(c_entry->arg > 0); 2105 assert_true(c_entry->arg <= cdata_len_remaining); 2106 cdata_len_remaining -= c_entry->arg; 2107 } 2108 assert_record_handler_called(&storage, i++, "record_default_handler", 6); 2109 assert_true(storage.count == i); 2110 } 2111 2112 /* Now with an internal entity to complicate matters */ 2113 set_subtest("with internal entity"); 2114 { 2115 struct handler_record_list storage; 2116 storage.count = 0; 2117 XML_ParserReset(g_parser, NULL); 2118 XML_SetDefaultHandler(g_parser, record_default_handler); 2119 XML_SetCharacterDataHandler(g_parser, record_cdata_handler); 2120 XML_SetUserData(g_parser, &storage); 2121 if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text), 2122 XML_TRUE) 2123 == XML_STATUS_ERROR) 2124 xml_failure(g_parser); 2125 /* The default handler suppresses the entity */ 2126 assert_record_handler_called(&storage, 0, "record_default_handler", 9); 2127 assert_record_handler_called(&storage, 1, "record_default_handler", 1); 2128 assert_record_handler_called(&storage, 2, "record_default_handler", 3); 2129 assert_record_handler_called(&storage, 3, "record_default_handler", 1); 2130 assert_record_handler_called(&storage, 4, "record_default_handler", 1); 2131 assert_record_handler_called(&storage, 5, "record_default_handler", 1); 2132 assert_record_handler_called(&storage, 6, "record_default_handler", 8); 2133 assert_record_handler_called(&storage, 7, "record_default_handler", 1); 2134 assert_record_handler_called(&storage, 8, "record_default_handler", 6); 2135 assert_record_handler_called(&storage, 9, "record_default_handler", 1); 2136 assert_record_handler_called(&storage, 10, "record_default_handler", 7); 2137 assert_record_handler_called(&storage, 11, "record_default_handler", 1); 2138 assert_record_handler_called(&storage, 12, "record_default_handler", 1); 2139 assert_record_handler_called(&storage, 13, "record_default_handler", 1); 2140 assert_record_handler_called(&storage, 14, "record_default_handler", 1); 2141 assert_record_handler_called(&storage, 15, "record_default_handler", 1); 2142 assert_record_handler_called(&storage, 16, "record_default_handler", 5); 2143 assert_record_handler_called(&storage, 17, "record_default_handler", 8); 2144 assert_record_handler_called(&storage, 18, "record_default_handler", 6); 2145 assert_true(storage.count == 19); 2146 } 2147 2148 /* Again, with a skip handler */ 2149 set_subtest("with skip handler"); 2150 { 2151 struct handler_record_list storage; 2152 storage.count = 0; 2153 XML_ParserReset(g_parser, NULL); 2154 XML_SetDefaultHandler(g_parser, record_default_handler); 2155 XML_SetCharacterDataHandler(g_parser, record_cdata_handler); 2156 XML_SetSkippedEntityHandler(g_parser, record_skip_handler); 2157 XML_SetUserData(g_parser, &storage); 2158 if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text), 2159 XML_TRUE) 2160 == XML_STATUS_ERROR) 2161 xml_failure(g_parser); 2162 /* The default handler suppresses the entity */ 2163 assert_record_handler_called(&storage, 0, "record_default_handler", 9); 2164 assert_record_handler_called(&storage, 1, "record_default_handler", 1); 2165 assert_record_handler_called(&storage, 2, "record_default_handler", 3); 2166 assert_record_handler_called(&storage, 3, "record_default_handler", 1); 2167 assert_record_handler_called(&storage, 4, "record_default_handler", 1); 2168 assert_record_handler_called(&storage, 5, "record_default_handler", 1); 2169 assert_record_handler_called(&storage, 6, "record_default_handler", 8); 2170 assert_record_handler_called(&storage, 7, "record_default_handler", 1); 2171 assert_record_handler_called(&storage, 8, "record_default_handler", 6); 2172 assert_record_handler_called(&storage, 9, "record_default_handler", 1); 2173 assert_record_handler_called(&storage, 10, "record_default_handler", 7); 2174 assert_record_handler_called(&storage, 11, "record_default_handler", 1); 2175 assert_record_handler_called(&storage, 12, "record_default_handler", 1); 2176 assert_record_handler_called(&storage, 13, "record_default_handler", 1); 2177 assert_record_handler_called(&storage, 14, "record_default_handler", 1); 2178 assert_record_handler_called(&storage, 15, "record_default_handler", 1); 2179 assert_record_handler_called(&storage, 16, "record_default_handler", 5); 2180 assert_record_handler_called(&storage, 17, "record_skip_handler", 0); 2181 assert_record_handler_called(&storage, 18, "record_default_handler", 6); 2182 assert_true(storage.count == 19); 2183 } 2184 2185 /* This time, allow the entity through */ 2186 set_subtest("allow entity"); 2187 { 2188 struct handler_record_list storage; 2189 storage.count = 0; 2190 XML_ParserReset(g_parser, NULL); 2191 XML_SetDefaultHandlerExpand(g_parser, record_default_handler); 2192 XML_SetCharacterDataHandler(g_parser, record_cdata_handler); 2193 XML_SetUserData(g_parser, &storage); 2194 if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text), 2195 XML_TRUE) 2196 == XML_STATUS_ERROR) 2197 xml_failure(g_parser); 2198 assert_record_handler_called(&storage, 0, "record_default_handler", 9); 2199 assert_record_handler_called(&storage, 1, "record_default_handler", 1); 2200 assert_record_handler_called(&storage, 2, "record_default_handler", 3); 2201 assert_record_handler_called(&storage, 3, "record_default_handler", 1); 2202 assert_record_handler_called(&storage, 4, "record_default_handler", 1); 2203 assert_record_handler_called(&storage, 5, "record_default_handler", 1); 2204 assert_record_handler_called(&storage, 6, "record_default_handler", 8); 2205 assert_record_handler_called(&storage, 7, "record_default_handler", 1); 2206 assert_record_handler_called(&storage, 8, "record_default_handler", 6); 2207 assert_record_handler_called(&storage, 9, "record_default_handler", 1); 2208 assert_record_handler_called(&storage, 10, "record_default_handler", 7); 2209 assert_record_handler_called(&storage, 11, "record_default_handler", 1); 2210 assert_record_handler_called(&storage, 12, "record_default_handler", 1); 2211 assert_record_handler_called(&storage, 13, "record_default_handler", 1); 2212 assert_record_handler_called(&storage, 14, "record_default_handler", 1); 2213 assert_record_handler_called(&storage, 15, "record_default_handler", 1); 2214 assert_record_handler_called(&storage, 16, "record_default_handler", 5); 2215 assert_record_handler_called(&storage, 17, "record_cdata_handler", 1); 2216 assert_record_handler_called(&storage, 18, "record_default_handler", 1); 2217 assert_record_handler_called(&storage, 19, "record_default_handler", 6); 2218 assert_true(storage.count == 20); 2219 } 2220 2221 /* Finally, without passing the cdata to the default handler */ 2222 set_subtest("not passing cdata"); 2223 { 2224 struct handler_record_list storage; 2225 storage.count = 0; 2226 XML_ParserReset(g_parser, NULL); 2227 XML_SetDefaultHandlerExpand(g_parser, record_default_handler); 2228 XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler); 2229 XML_SetUserData(g_parser, &storage); 2230 if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text), 2231 XML_TRUE) 2232 == XML_STATUS_ERROR) 2233 xml_failure(g_parser); 2234 assert_record_handler_called(&storage, 0, "record_default_handler", 9); 2235 assert_record_handler_called(&storage, 1, "record_default_handler", 1); 2236 assert_record_handler_called(&storage, 2, "record_default_handler", 3); 2237 assert_record_handler_called(&storage, 3, "record_default_handler", 1); 2238 assert_record_handler_called(&storage, 4, "record_default_handler", 1); 2239 assert_record_handler_called(&storage, 5, "record_default_handler", 1); 2240 assert_record_handler_called(&storage, 6, "record_default_handler", 8); 2241 assert_record_handler_called(&storage, 7, "record_default_handler", 1); 2242 assert_record_handler_called(&storage, 8, "record_default_handler", 6); 2243 assert_record_handler_called(&storage, 9, "record_default_handler", 1); 2244 assert_record_handler_called(&storage, 10, "record_default_handler", 7); 2245 assert_record_handler_called(&storage, 11, "record_default_handler", 1); 2246 assert_record_handler_called(&storage, 12, "record_default_handler", 1); 2247 assert_record_handler_called(&storage, 13, "record_default_handler", 1); 2248 assert_record_handler_called(&storage, 14, "record_default_handler", 1); 2249 assert_record_handler_called(&storage, 15, "record_default_handler", 1); 2250 assert_record_handler_called(&storage, 16, "record_default_handler", 5); 2251 assert_record_handler_called(&storage, 17, "record_cdata_nodefault_handler", 2252 1); 2253 assert_record_handler_called(&storage, 18, "record_default_handler", 6); 2254 assert_true(storage.count == 19); 2255 } 2256 } 2257 END_TEST 2258 2259 /* Test DTD element parsing code paths */ 2260 START_TEST(test_dtd_elements) { 2261 const char *text = "<!DOCTYPE doc [\n" 2262 "<!ELEMENT doc (chapter)>\n" 2263 "<!ELEMENT chapter (#PCDATA)>\n" 2264 "]>\n" 2265 "<doc><chapter>Wombats are go</chapter></doc>"; 2266 2267 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler); 2268 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 2269 == XML_STATUS_ERROR) 2270 xml_failure(g_parser); 2271 } 2272 END_TEST 2273 2274 static void XMLCALL 2275 element_decl_check_model(void *userData, const XML_Char *name, 2276 XML_Content *model) { 2277 UNUSED_P(userData); 2278 uint32_t errorFlags = 0; 2279 2280 /* Expected model array structure is this: 2281 * [0] (type 6, quant 0) 2282 * [1] (type 5, quant 0) 2283 * [3] (type 4, quant 0, name "bar") 2284 * [4] (type 4, quant 0, name "foo") 2285 * [5] (type 4, quant 3, name "xyz") 2286 * [2] (type 4, quant 2, name "zebra") 2287 */ 2288 errorFlags |= ((xcstrcmp(name, XCS("junk")) == 0) ? 0 : (1u << 0)); 2289 errorFlags |= ((model != NULL) ? 0 : (1u << 1)); 2290 2291 if (model != NULL) { 2292 errorFlags |= ((model[0].type == XML_CTYPE_SEQ) ? 0 : (1u << 2)); 2293 errorFlags |= ((model[0].quant == XML_CQUANT_NONE) ? 0 : (1u << 3)); 2294 errorFlags |= ((model[0].numchildren == 2) ? 0 : (1u << 4)); 2295 errorFlags |= ((model[0].children == &model[1]) ? 0 : (1u << 5)); 2296 errorFlags |= ((model[0].name == NULL) ? 0 : (1u << 6)); 2297 2298 errorFlags |= ((model[1].type == XML_CTYPE_CHOICE) ? 0 : (1u << 7)); 2299 errorFlags |= ((model[1].quant == XML_CQUANT_NONE) ? 0 : (1u << 8)); 2300 errorFlags |= ((model[1].numchildren == 3) ? 0 : (1u << 9)); 2301 errorFlags |= ((model[1].children == &model[3]) ? 0 : (1u << 10)); 2302 errorFlags |= ((model[1].name == NULL) ? 0 : (1u << 11)); 2303 2304 errorFlags |= ((model[2].type == XML_CTYPE_NAME) ? 0 : (1u << 12)); 2305 errorFlags |= ((model[2].quant == XML_CQUANT_REP) ? 0 : (1u << 13)); 2306 errorFlags |= ((model[2].numchildren == 0) ? 0 : (1u << 14)); 2307 errorFlags |= ((model[2].children == NULL) ? 0 : (1u << 15)); 2308 errorFlags 2309 |= ((xcstrcmp(model[2].name, XCS("zebra")) == 0) ? 0 : (1u << 16)); 2310 2311 errorFlags |= ((model[3].type == XML_CTYPE_NAME) ? 0 : (1u << 17)); 2312 errorFlags |= ((model[3].quant == XML_CQUANT_NONE) ? 0 : (1u << 18)); 2313 errorFlags |= ((model[3].numchildren == 0) ? 0 : (1u << 19)); 2314 errorFlags |= ((model[3].children == NULL) ? 0 : (1u << 20)); 2315 errorFlags |= ((xcstrcmp(model[3].name, XCS("bar")) == 0) ? 0 : (1u << 21)); 2316 2317 errorFlags |= ((model[4].type == XML_CTYPE_NAME) ? 0 : (1u << 22)); 2318 errorFlags |= ((model[4].quant == XML_CQUANT_NONE) ? 0 : (1u << 23)); 2319 errorFlags |= ((model[4].numchildren == 0) ? 0 : (1u << 24)); 2320 errorFlags |= ((model[4].children == NULL) ? 0 : (1u << 25)); 2321 errorFlags |= ((xcstrcmp(model[4].name, XCS("foo")) == 0) ? 0 : (1u << 26)); 2322 2323 errorFlags |= ((model[5].type == XML_CTYPE_NAME) ? 0 : (1u << 27)); 2324 errorFlags |= ((model[5].quant == XML_CQUANT_PLUS) ? 0 : (1u << 28)); 2325 errorFlags |= ((model[5].numchildren == 0) ? 0 : (1u << 29)); 2326 errorFlags |= ((model[5].children == NULL) ? 0 : (1u << 30)); 2327 errorFlags |= ((xcstrcmp(model[5].name, XCS("xyz")) == 0) ? 0 : (1u << 31)); 2328 } 2329 2330 XML_SetUserData(g_parser, (void *)(uintptr_t)errorFlags); 2331 XML_FreeContentModel(g_parser, model); 2332 } 2333 2334 START_TEST(test_dtd_elements_nesting) { 2335 // Payload inspired by a test in Perl's XML::Parser 2336 const char *text = "<!DOCTYPE foo [\n" 2337 "<!ELEMENT junk ((bar|foo|xyz+), zebra*)>\n" 2338 "]>\n" 2339 "<foo/>"; 2340 2341 XML_SetUserData(g_parser, (void *)(uintptr_t)-1); 2342 2343 XML_SetElementDeclHandler(g_parser, element_decl_check_model); 2344 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 2345 == XML_STATUS_ERROR) 2346 xml_failure(g_parser); 2347 2348 if ((uint32_t)(uintptr_t)XML_GetUserData(g_parser) != 0) 2349 fail("Element declaration model regression detected"); 2350 } 2351 END_TEST 2352 2353 /* Test foreign DTD handling */ 2354 START_TEST(test_set_foreign_dtd) { 2355 const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"; 2356 const char *text2 = "<doc>&entity;</doc>"; 2357 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL}; 2358 2359 /* Check hash salt is passed through too */ 2360 XML_SetHashSalt(g_parser, 0x12345678); 2361 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2362 XML_SetUserData(g_parser, &test_data); 2363 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 2364 /* Add a default handler to exercise more code paths */ 2365 XML_SetDefaultHandler(g_parser, dummy_default_handler); 2366 if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE) 2367 fail("Could not set foreign DTD"); 2368 if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE) 2369 == XML_STATUS_ERROR) 2370 xml_failure(g_parser); 2371 2372 /* Ensure that trying to set the DTD after parsing has started 2373 * is faulted, even if it's the same setting. 2374 */ 2375 if (XML_UseForeignDTD(g_parser, XML_TRUE) 2376 != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING) 2377 fail("Failed to reject late foreign DTD setting"); 2378 /* Ditto for the hash salt */ 2379 if (XML_SetHashSalt(g_parser, 0x23456789)) 2380 fail("Failed to reject late hash salt change"); 2381 2382 /* Now finish the parse */ 2383 if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE) 2384 == XML_STATUS_ERROR) 2385 xml_failure(g_parser); 2386 } 2387 END_TEST 2388 2389 /* Test foreign DTD handling with a failing NotStandalone handler */ 2390 START_TEST(test_foreign_dtd_not_standalone) { 2391 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 2392 "<doc>&entity;</doc>"; 2393 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL}; 2394 2395 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2396 XML_SetUserData(g_parser, &test_data); 2397 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 2398 XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler); 2399 if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE) 2400 fail("Could not set foreign DTD"); 2401 expect_failure(text, XML_ERROR_NOT_STANDALONE, 2402 "NotStandalonehandler failed to reject"); 2403 } 2404 END_TEST 2405 2406 /* Test invalid character in a foreign DTD is faulted */ 2407 START_TEST(test_invalid_foreign_dtd) { 2408 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 2409 "<doc>&entity;</doc>"; 2410 ExtFaults test_data 2411 = {"$", "Dollar not faulted", NULL, XML_ERROR_INVALID_TOKEN}; 2412 2413 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2414 XML_SetUserData(g_parser, &test_data); 2415 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter); 2416 XML_UseForeignDTD(g_parser, XML_TRUE); 2417 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 2418 "Bad DTD should not have been accepted"); 2419 } 2420 END_TEST 2421 2422 /* Test foreign DTD use with a doctype */ 2423 START_TEST(test_foreign_dtd_with_doctype) { 2424 const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n" 2425 "<!DOCTYPE doc [<!ENTITY entity 'hello world'>]>\n"; 2426 const char *text2 = "<doc>&entity;</doc>"; 2427 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL}; 2428 2429 /* Check hash salt is passed through too */ 2430 XML_SetHashSalt(g_parser, 0x12345678); 2431 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2432 XML_SetUserData(g_parser, &test_data); 2433 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 2434 /* Add a default handler to exercise more code paths */ 2435 XML_SetDefaultHandler(g_parser, dummy_default_handler); 2436 if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE) 2437 fail("Could not set foreign DTD"); 2438 if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE) 2439 == XML_STATUS_ERROR) 2440 xml_failure(g_parser); 2441 2442 /* Ensure that trying to set the DTD after parsing has started 2443 * is faulted, even if it's the same setting. 2444 */ 2445 if (XML_UseForeignDTD(g_parser, XML_TRUE) 2446 != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING) 2447 fail("Failed to reject late foreign DTD setting"); 2448 /* Ditto for the hash salt */ 2449 if (XML_SetHashSalt(g_parser, 0x23456789)) 2450 fail("Failed to reject late hash salt change"); 2451 2452 /* Now finish the parse */ 2453 if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE) 2454 == XML_STATUS_ERROR) 2455 xml_failure(g_parser); 2456 } 2457 END_TEST 2458 2459 /* Test XML_UseForeignDTD with no external subset present */ 2460 START_TEST(test_foreign_dtd_without_external_subset) { 2461 const char *text = "<!DOCTYPE doc [<!ENTITY foo 'bar'>]>\n" 2462 "<doc>&foo;</doc>"; 2463 2464 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2465 XML_SetUserData(g_parser, NULL); 2466 XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader); 2467 XML_UseForeignDTD(g_parser, XML_TRUE); 2468 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 2469 == XML_STATUS_ERROR) 2470 xml_failure(g_parser); 2471 } 2472 END_TEST 2473 2474 START_TEST(test_empty_foreign_dtd) { 2475 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 2476 "<doc>&entity;</doc>"; 2477 2478 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2479 XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader); 2480 XML_UseForeignDTD(g_parser, XML_TRUE); 2481 expect_failure(text, XML_ERROR_UNDEFINED_ENTITY, 2482 "Undefined entity not faulted"); 2483 } 2484 END_TEST 2485 2486 /* Test XML Base is set and unset appropriately */ 2487 START_TEST(test_set_base) { 2488 const XML_Char *old_base; 2489 const XML_Char *new_base = XCS("/local/file/name.xml"); 2490 2491 old_base = XML_GetBase(g_parser); 2492 if (XML_SetBase(g_parser, new_base) != XML_STATUS_OK) 2493 fail("Unable to set base"); 2494 if (xcstrcmp(XML_GetBase(g_parser), new_base) != 0) 2495 fail("Base setting not correct"); 2496 if (XML_SetBase(g_parser, NULL) != XML_STATUS_OK) 2497 fail("Unable to NULL base"); 2498 if (XML_GetBase(g_parser) != NULL) 2499 fail("Base setting not nulled"); 2500 XML_SetBase(g_parser, old_base); 2501 } 2502 END_TEST 2503 2504 /* Test attribute counts, indexing, etc */ 2505 START_TEST(test_attributes) { 2506 const char *text = "<!DOCTYPE doc [\n" 2507 "<!ELEMENT doc (tag)>\n" 2508 "<!ATTLIST doc id ID #REQUIRED>\n" 2509 "]>" 2510 "<doc a='1' id='one' b='2'>" 2511 "<tag c='3'/>" 2512 "</doc>"; 2513 AttrInfo doc_info[] = {{XCS("a"), XCS("1")}, 2514 {XCS("b"), XCS("2")}, 2515 {XCS("id"), XCS("one")}, 2516 {NULL, NULL}}; 2517 AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}}; 2518 ElementInfo info[] = {{XCS("doc"), 3, 0, XCS("id"), doc_info}, 2519 {XCS("tag"), 1, 0, NULL, tag_info}, 2520 {NULL, 0, 0, NULL, NULL}}; 2521 2522 XML_Parser parser = XML_ParserCreate(NULL); 2523 assert_true(parser != NULL); 2524 ParserAndElementInfo parserAndElementInfos = { 2525 parser, 2526 info, 2527 }; 2528 2529 XML_SetStartElementHandler(parser, counting_start_element_handler); 2530 XML_SetUserData(parser, &parserAndElementInfos); 2531 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 2532 == XML_STATUS_ERROR) 2533 xml_failure(parser); 2534 2535 XML_ParserFree(parser); 2536 } 2537 END_TEST 2538 2539 START_TEST(test_duplicate_cdata_attribute) { 2540 /* 2541 https://www.w3.org/TR/xml/#attdecls 2542 2543 Test the following statement from the linked specification: 2544 When more than one definition is provided for the same attribute of a given 2545 element type, the first declaration is binding and later declarations are 2546 ignored. 2547 */ 2548 2549 const char *text 2550 = "<!DOCTYPE doc [\n" 2551 " <!ATTLIST doc attribute CDATA 'expected' attribute CDATA 'ignored'>\n" 2552 "]>\n" 2553 "<doc/>\n"; 2554 AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected")}, {NULL, NULL}}; 2555 ElementInfo info[] 2556 = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}}; 2557 2558 XML_Parser parser = XML_ParserCreate(NULL); 2559 assert_true(parser != NULL); 2560 2561 ParserAndElementInfo parserAndElementInfos = { 2562 parser, 2563 info, 2564 }; 2565 2566 XML_SetStartElementHandler(parser, counting_start_element_handler); 2567 XML_SetUserData(parser, &parserAndElementInfos); 2568 2569 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 2570 != XML_STATUS_OK) 2571 xml_failure(parser); 2572 2573 XML_ParserFree(parser); 2574 } 2575 END_TEST 2576 2577 START_TEST(test_duplicate_id_attribute_1) { 2578 /* 2579 https://www.w3.org/TR/xml/#attdecls 2580 2581 Test the following statement from the linked specification: 2582 When more than one definition is provided for the same attribute of a given 2583 element type, the first declaration is binding and later declarations are 2584 ignored. 2585 */ 2586 2587 const char *text 2588 = "<!DOCTYPE doc [\n" 2589 " <!ATTLIST doc identifier CDATA 'expected' identifier ID #REQUIRED>\n" 2590 "]>\n" 2591 "<doc/>\n"; 2592 AttrInfo doc_info[] = {{XCS("identifier"), XCS("expected")}, {NULL, NULL}}; 2593 ElementInfo info[] 2594 = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}}; 2595 2596 XML_Parser parser = XML_ParserCreate(NULL); 2597 assert_true(parser != NULL); 2598 2599 ParserAndElementInfo parserAndElementInfos = { 2600 parser, 2601 info, 2602 }; 2603 2604 XML_SetStartElementHandler(parser, counting_start_element_handler); 2605 XML_SetUserData(parser, &parserAndElementInfos); 2606 2607 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 2608 != XML_STATUS_OK) 2609 xml_failure(parser); 2610 2611 XML_ParserFree(parser); 2612 } 2613 END_TEST 2614 2615 START_TEST(test_duplicate_id_attribute_2) { 2616 /* 2617 https://www.w3.org/TR/xml/#attdecls 2618 2619 Test the following statement from the linked specification: 2620 When more than one definition is provided for the same attribute of a given 2621 element type, the first declaration is binding and later declarations are 2622 ignored. 2623 */ 2624 2625 const char *text 2626 = "<!DOCTYPE doc [\n" 2627 " <!ATTLIST doc identifier ID #REQUIRED identifier CDATA 'unexpected'>\n" 2628 "]>\n" 2629 "<doc/>\n"; 2630 AttrInfo doc_info[] = {{NULL, NULL}}; 2631 2632 ElementInfo info[] 2633 = {{XCS("doc"), 0, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}}; 2634 2635 XML_Parser parser = XML_ParserCreate(NULL); 2636 assert_true(parser != NULL); 2637 2638 ParserAndElementInfo parserAndElementInfos = { 2639 parser, 2640 info, 2641 }; 2642 2643 XML_SetStartElementHandler(parser, counting_start_element_handler); 2644 XML_SetUserData(parser, &parserAndElementInfos); 2645 2646 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 2647 != XML_STATUS_OK) 2648 xml_failure(parser); 2649 2650 XML_ParserFree(parser); 2651 } 2652 END_TEST 2653 2654 START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl) { 2655 /* 2656 https://www.w3.org/TR/xml/#attdecls 2657 2658 Test the following statement from the linked specification: 2659 When more than one AttlistDecl is provided for a given element type, 2660 the contents of all those provided are merged. 2661 */ 2662 const char *text = "<!DOCTYPE doc [\n" 2663 " <!ATTLIST doc attribute CDATA 'expected'>\n" 2664 " <!ATTLIST doc attribute CDATA 'ignored'>\n" 2665 "]>\n" 2666 "<doc/>\n"; 2667 AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected")}, {NULL, NULL}}; 2668 ElementInfo info[] 2669 = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}}; 2670 2671 XML_Parser parser = XML_ParserCreate(NULL); 2672 assert_true(parser != NULL); 2673 2674 ParserAndElementInfo parserAndElementInfos = { 2675 parser, 2676 info, 2677 }; 2678 2679 XML_SetStartElementHandler(parser, counting_start_element_handler); 2680 XML_SetUserData(parser, &parserAndElementInfos); 2681 2682 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 2683 != XML_STATUS_OK) 2684 xml_failure(parser); 2685 2686 XML_ParserFree(parser); 2687 } 2688 END_TEST 2689 2690 START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_2) { 2691 /* 2692 https://www.w3.org/TR/xml/#attdecls 2693 2694 Test the following statement from the linked specification: 2695 When more than one AttlistDecl is provided for a given element type, 2696 the contents of all those provided are merged. 2697 */ 2698 const char *text = "<!DOCTYPE doc [\n" 2699 " <!ATTLIST doc attribute CDATA 'expected_doc'>\n" 2700 " <!ATTLIST tag attribute CDATA 'expected_tag'>\n" 2701 " <!ATTLIST doc attribute CDATA 'ignored_doc'>\n" 2702 "]>\n" 2703 "<doc><tag></tag></doc>\n"; 2704 AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected_doc")}, {NULL, NULL}}; 2705 AttrInfo tag_info[] = {{XCS("attribute"), XCS("expected_tag")}, {NULL, NULL}}; 2706 ElementInfo info[] = {{XCS("doc"), 0, 1, NULL, doc_info}, 2707 {XCS("tag"), 0, 1, NULL, tag_info}, 2708 {NULL, 0, 0, NULL, NULL}}; 2709 2710 XML_Parser parser = XML_ParserCreate(NULL); 2711 assert_true(parser != NULL); 2712 2713 ParserAndElementInfo parserAndElementInfos = { 2714 parser, 2715 info, 2716 }; 2717 2718 XML_SetStartElementHandler(parser, counting_start_element_handler); 2719 XML_SetUserData(parser, &parserAndElementInfos); 2720 2721 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 2722 != XML_STATUS_OK) 2723 xml_failure(parser); 2724 2725 XML_ParserFree(parser); 2726 } 2727 END_TEST 2728 2729 START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_3) { 2730 /* 2731 https://www.w3.org/TR/xml/#attdecls 2732 2733 Test the following statement from the linked specification: 2734 When more than one AttlistDecl is provided for a given element type, 2735 the contents of all those provided are merged. 2736 */ 2737 const char *text 2738 = "<!DOCTYPE doc [\n" 2739 " <!ATTLIST doc attribute CDATA 'expected_doc'>\n" 2740 " <!ATTLIST tag attribute CDATA 'expected_tag'>\n" 2741 " <!ATTLIST doc second_attribute CDATA 'second_expected_doc' attribute CDATA 'ignored_doc'>\n" 2742 "]>\n" 2743 "<doc><tag></tag></doc>\n"; 2744 AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected_doc")}, 2745 {XCS("second_attribute"), XCS("second_expected_doc")}, 2746 {NULL, NULL}}; 2747 AttrInfo tag_info[] = {{XCS("attribute"), XCS("expected_tag")}, {NULL, NULL}}; 2748 ElementInfo info[] = {{XCS("doc"), 0, 2, NULL, doc_info}, 2749 {XCS("tag"), 0, 1, NULL, tag_info}, 2750 {NULL, 0, 0, NULL, NULL}}; 2751 2752 XML_Parser parser = XML_ParserCreate(NULL); 2753 assert_true(parser != NULL); 2754 2755 ParserAndElementInfo parserAndElementInfos = { 2756 parser, 2757 info, 2758 }; 2759 2760 XML_SetStartElementHandler(parser, counting_start_element_handler); 2761 XML_SetUserData(parser, &parserAndElementInfos); 2762 2763 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 2764 != XML_STATUS_OK) 2765 xml_failure(parser); 2766 2767 XML_ParserFree(parser); 2768 } 2769 END_TEST 2770 2771 START_TEST(test_duplicate_id_attribute_multiple_attlistdecl) { 2772 /* 2773 https://www.w3.org/TR/xml/#attdecls 2774 2775 Test the following statement from the linked specification: 2776 When more than one AttlistDecl is provided for a given element type, 2777 the contents of all those provided are merged. 2778 */ 2779 const char *text = "<!DOCTYPE doc [\n" 2780 " <!ATTLIST doc identifier ID #REQUIRED>\n" 2781 " <!ATTLIST tag identifier CDATA 'identifier_tag'>\n" 2782 " <!ATTLIST doc identifier CDATA 'ignored'>\n" 2783 "]>\n" 2784 "<doc identifier='doc_identity'><tag></tag></doc>\n"; 2785 AttrInfo doc_info[] 2786 = {{XCS("identifier"), XCS("doc_identity")}, {NULL, NULL}}; 2787 AttrInfo tag_info[] 2788 = {{XCS("identifier"), XCS("identifier_tag")}, {NULL, NULL}}; 2789 ElementInfo info[] = {{XCS("doc"), 1, 0, XCS("identifier"), doc_info}, 2790 {XCS("tag"), 0, 1, NULL, tag_info}, 2791 {NULL, 0, 0, NULL, NULL}}; 2792 2793 XML_Parser parser = XML_ParserCreate(NULL); 2794 assert_true(parser != NULL); 2795 2796 ParserAndElementInfo parserAndElementInfos = { 2797 parser, 2798 info, 2799 }; 2800 2801 XML_SetStartElementHandler(parser, counting_start_element_handler); 2802 XML_SetUserData(parser, &parserAndElementInfos); 2803 2804 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 2805 != XML_STATUS_OK) 2806 xml_failure(parser); 2807 2808 XML_ParserFree(parser); 2809 } 2810 END_TEST 2811 2812 /* Test reset works correctly in the middle of processing an internal 2813 * entity. Exercises some obscure code in XML_ParserReset(). 2814 */ 2815 START_TEST(test_reset_in_entity) { 2816 if (g_chunkSize != 0) { 2817 // this test does not use SINGLE_BYTES, because of suspension 2818 return; 2819 } 2820 2821 const char *text = "<!DOCTYPE doc [\n" 2822 "<!ENTITY wombat 'wom'>\n" 2823 "<!ENTITY entity 'hi &wom; there'>\n" 2824 "]>\n" 2825 "<doc>&entity;</doc>"; 2826 XML_ParsingStatus status; 2827 2828 g_resumable = XML_TRUE; 2829 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler); 2830 // can't use SINGLE_BYTES here, because it'll return early on suspension, and 2831 // we won't know exactly how much input we actually managed to give Expat. 2832 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) 2833 == XML_STATUS_ERROR) 2834 xml_failure(g_parser); 2835 XML_GetParsingStatus(g_parser, &status); 2836 if (status.parsing != XML_SUSPENDED) 2837 fail("Parsing status not SUSPENDED"); 2838 XML_ParserReset(g_parser, NULL); 2839 XML_GetParsingStatus(g_parser, &status); 2840 if (status.parsing != XML_INITIALIZED) 2841 fail("Parsing status doesn't reset to INITIALIZED"); 2842 } 2843 END_TEST 2844 2845 /* Test that resume correctly passes through parse errors */ 2846 START_TEST(test_resume_invalid_parse) { 2847 const char *text = "<doc>Hello</doc"; /* Missing closing wedge */ 2848 2849 g_resumable = XML_TRUE; 2850 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler); 2851 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) 2852 == XML_STATUS_ERROR) 2853 xml_failure(g_parser); 2854 if (XML_ResumeParser(g_parser) == XML_STATUS_OK) 2855 fail("Resumed invalid parse not faulted"); 2856 if (XML_GetErrorCode(g_parser) != XML_ERROR_UNCLOSED_TOKEN) 2857 fail("Invalid parse not correctly faulted"); 2858 } 2859 END_TEST 2860 2861 /* Test that re-suspended parses are correctly passed through */ 2862 START_TEST(test_resume_resuspended) { 2863 const char *text = "<doc>Hello<meep/>world</doc>"; 2864 2865 g_resumable = XML_TRUE; 2866 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler); 2867 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) 2868 == XML_STATUS_ERROR) 2869 xml_failure(g_parser); 2870 g_resumable = XML_TRUE; 2871 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler); 2872 if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED) 2873 fail("Resumption not suspended"); 2874 /* This one should succeed and finish up */ 2875 if (XML_ResumeParser(g_parser) != XML_STATUS_OK) 2876 xml_failure(g_parser); 2877 } 2878 END_TEST 2879 2880 /* Test that CDATA shows up correctly through a default handler */ 2881 START_TEST(test_cdata_default) { 2882 const char *text = "<doc><![CDATA[Hello\nworld]]></doc>"; 2883 const XML_Char *expected = XCS("<doc><![CDATA[Hello\nworld]]></doc>"); 2884 CharData storage; 2885 2886 CharData_Init(&storage); 2887 XML_SetUserData(g_parser, &storage); 2888 XML_SetDefaultHandler(g_parser, accumulate_characters); 2889 2890 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 2891 == XML_STATUS_ERROR) 2892 xml_failure(g_parser); 2893 CharData_CheckXMLChars(&storage, expected); 2894 } 2895 END_TEST 2896 2897 /* Test resetting a subordinate parser does exactly nothing */ 2898 START_TEST(test_subordinate_reset) { 2899 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 2900 "<!DOCTYPE doc SYSTEM 'foo'>\n" 2901 "<doc>&entity;</doc>"; 2902 2903 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2904 XML_SetExternalEntityRefHandler(g_parser, external_entity_resetter); 2905 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 2906 == XML_STATUS_ERROR) 2907 xml_failure(g_parser); 2908 } 2909 END_TEST 2910 2911 /* Test suspending a subordinate parser */ 2912 START_TEST(test_subordinate_suspend) { 2913 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 2914 "<!DOCTYPE doc SYSTEM 'foo'>\n" 2915 "<doc>&entity;</doc>"; 2916 2917 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2918 XML_SetExternalEntityRefHandler(g_parser, external_entity_suspender); 2919 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 2920 == XML_STATUS_ERROR) 2921 xml_failure(g_parser); 2922 } 2923 END_TEST 2924 2925 /* Test suspending a subordinate parser from an XML declaration */ 2926 /* Increases code coverage of the tests */ 2927 2928 START_TEST(test_subordinate_xdecl_suspend) { 2929 const char *text 2930 = "<!DOCTYPE doc [\n" 2931 " <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n" 2932 "]>\n" 2933 "<doc>&entity;</doc>"; 2934 2935 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2936 XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl); 2937 g_resumable = XML_TRUE; 2938 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 2939 == XML_STATUS_ERROR) 2940 xml_failure(g_parser); 2941 } 2942 END_TEST 2943 2944 START_TEST(test_subordinate_xdecl_abort) { 2945 const char *text 2946 = "<!DOCTYPE doc [\n" 2947 " <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n" 2948 "]>\n" 2949 "<doc>&entity;</doc>"; 2950 2951 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2952 XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl); 2953 g_resumable = XML_FALSE; 2954 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 2955 == XML_STATUS_ERROR) 2956 xml_failure(g_parser); 2957 } 2958 END_TEST 2959 2960 /* Test external entity fault handling with suspension */ 2961 START_TEST(test_ext_entity_invalid_suspended_parse) { 2962 const char *text = "<!DOCTYPE doc [\n" 2963 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 2964 "]>\n" 2965 "<doc>&en;</doc>"; 2966 ExtFaults faults[] 2967 = {{"<?xml version='1.0' encoding='us-ascii'?><", 2968 "Incomplete element declaration not faulted", NULL, 2969 XML_ERROR_UNCLOSED_TOKEN}, 2970 {/* First two bytes of a three-byte char */ 2971 "<?xml version='1.0' encoding='utf-8'?>\xe2\x82", 2972 "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR}, 2973 {NULL, NULL, NULL, XML_ERROR_NONE}}; 2974 ExtFaults *fault; 2975 2976 for (fault = &faults[0]; fault->parse_text != NULL; fault++) { 2977 set_subtest("%s", fault->parse_text); 2978 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 2979 XML_SetExternalEntityRefHandler(g_parser, 2980 external_entity_suspending_faulter); 2981 XML_SetUserData(g_parser, fault); 2982 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 2983 "Parser did not report external entity error"); 2984 XML_ParserReset(g_parser, NULL); 2985 } 2986 } 2987 END_TEST 2988 2989 /* Test setting an explicit encoding */ 2990 START_TEST(test_explicit_encoding) { 2991 const char *text1 = "<doc>Hello "; 2992 const char *text2 = " World</doc>"; 2993 2994 /* Just check that we can set the encoding to NULL before starting */ 2995 if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK) 2996 fail("Failed to initialise encoding to NULL"); 2997 /* Say we are UTF-8 */ 2998 if (XML_SetEncoding(g_parser, XCS("utf-8")) != XML_STATUS_OK) 2999 fail("Failed to set explicit encoding"); 3000 if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE) 3001 == XML_STATUS_ERROR) 3002 xml_failure(g_parser); 3003 /* Try to switch encodings mid-parse */ 3004 if (XML_SetEncoding(g_parser, XCS("us-ascii")) != XML_STATUS_ERROR) 3005 fail("Allowed encoding change"); 3006 if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE) 3007 == XML_STATUS_ERROR) 3008 xml_failure(g_parser); 3009 /* Try now the parse is over */ 3010 if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK) 3011 fail("Failed to unset encoding"); 3012 } 3013 END_TEST 3014 3015 /* Test handling of trailing CR (rather than newline) */ 3016 START_TEST(test_trailing_cr) { 3017 const char *text = "<doc>\r"; 3018 int found_cr; 3019 3020 /* Try with a character handler, for code coverage */ 3021 XML_SetCharacterDataHandler(g_parser, cr_cdata_handler); 3022 XML_SetUserData(g_parser, &found_cr); 3023 found_cr = 0; 3024 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3025 == XML_STATUS_OK) 3026 fail("Failed to fault unclosed doc"); 3027 if (found_cr == 0) 3028 fail("Did not catch the carriage return"); 3029 XML_ParserReset(g_parser, NULL); 3030 3031 /* Now with a default handler instead */ 3032 XML_SetDefaultHandler(g_parser, cr_cdata_handler); 3033 XML_SetUserData(g_parser, &found_cr); 3034 found_cr = 0; 3035 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3036 == XML_STATUS_OK) 3037 fail("Failed to fault unclosed doc"); 3038 if (found_cr == 0) 3039 fail("Did not catch default carriage return"); 3040 } 3041 END_TEST 3042 3043 /* Test trailing CR in an external entity parse */ 3044 START_TEST(test_ext_entity_trailing_cr) { 3045 const char *text = "<!DOCTYPE doc [\n" 3046 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 3047 "]>\n" 3048 "<doc>&en;</doc>"; 3049 int found_cr; 3050 3051 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3052 XML_SetExternalEntityRefHandler(g_parser, external_entity_cr_catcher); 3053 XML_SetUserData(g_parser, &found_cr); 3054 found_cr = 0; 3055 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3056 != XML_STATUS_OK) 3057 xml_failure(g_parser); 3058 if (found_cr == 0) 3059 fail("No carriage return found"); 3060 XML_ParserReset(g_parser, NULL); 3061 3062 /* Try again with a different trailing CR */ 3063 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3064 XML_SetExternalEntityRefHandler(g_parser, external_entity_bad_cr_catcher); 3065 XML_SetUserData(g_parser, &found_cr); 3066 found_cr = 0; 3067 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3068 != XML_STATUS_OK) 3069 xml_failure(g_parser); 3070 if (found_cr == 0) 3071 fail("No carriage return found"); 3072 } 3073 END_TEST 3074 3075 /* Test handling of trailing square bracket */ 3076 START_TEST(test_trailing_rsqb) { 3077 const char *text8 = "<doc>]"; 3078 const char text16[] = "\xFF\xFE<\000d\000o\000c\000>\000]\000"; 3079 int found_rsqb; 3080 int text8_len = (int)strlen(text8); 3081 3082 XML_SetCharacterDataHandler(g_parser, rsqb_handler); 3083 XML_SetUserData(g_parser, &found_rsqb); 3084 found_rsqb = 0; 3085 if (_XML_Parse_SINGLE_BYTES(g_parser, text8, text8_len, XML_TRUE) 3086 == XML_STATUS_OK) 3087 fail("Failed to fault unclosed doc"); 3088 if (found_rsqb == 0) 3089 fail("Did not catch the right square bracket"); 3090 3091 /* Try again with a different encoding */ 3092 XML_ParserReset(g_parser, NULL); 3093 XML_SetCharacterDataHandler(g_parser, rsqb_handler); 3094 XML_SetUserData(g_parser, &found_rsqb); 3095 found_rsqb = 0; 3096 if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1, 3097 XML_TRUE) 3098 == XML_STATUS_OK) 3099 fail("Failed to fault unclosed doc"); 3100 if (found_rsqb == 0) 3101 fail("Did not catch the right square bracket"); 3102 3103 /* And finally with a default handler */ 3104 XML_ParserReset(g_parser, NULL); 3105 XML_SetDefaultHandler(g_parser, rsqb_handler); 3106 XML_SetUserData(g_parser, &found_rsqb); 3107 found_rsqb = 0; 3108 if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1, 3109 XML_TRUE) 3110 == XML_STATUS_OK) 3111 fail("Failed to fault unclosed doc"); 3112 if (found_rsqb == 0) 3113 fail("Did not catch the right square bracket"); 3114 } 3115 END_TEST 3116 3117 /* Test trailing right square bracket in an external entity parse */ 3118 START_TEST(test_ext_entity_trailing_rsqb) { 3119 const char *text = "<!DOCTYPE doc [\n" 3120 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 3121 "]>\n" 3122 "<doc>&en;</doc>"; 3123 int found_rsqb; 3124 3125 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3126 XML_SetExternalEntityRefHandler(g_parser, external_entity_rsqb_catcher); 3127 XML_SetUserData(g_parser, &found_rsqb); 3128 found_rsqb = 0; 3129 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3130 != XML_STATUS_OK) 3131 xml_failure(g_parser); 3132 if (found_rsqb == 0) 3133 fail("No right square bracket found"); 3134 } 3135 END_TEST 3136 3137 /* Test CDATA handling in an external entity */ 3138 START_TEST(test_ext_entity_good_cdata) { 3139 const char *text = "<!DOCTYPE doc [\n" 3140 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 3141 "]>\n" 3142 "<doc>&en;</doc>"; 3143 3144 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3145 XML_SetExternalEntityRefHandler(g_parser, external_entity_good_cdata_ascii); 3146 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3147 != XML_STATUS_OK) 3148 xml_failure(g_parser); 3149 } 3150 END_TEST 3151 3152 /* Test user parameter settings */ 3153 START_TEST(test_user_parameters) { 3154 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 3155 "<!-- Primary parse -->\n" 3156 "<!DOCTYPE doc SYSTEM 'foo'>\n" 3157 "<doc>&entity;"; 3158 const char *epilog = "<!-- Back to primary parser -->\n" 3159 "</doc>"; 3160 3161 g_comment_count = 0; 3162 g_skip_count = 0; 3163 g_xdecl_count = 0; 3164 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3165 XML_SetXmlDeclHandler(g_parser, xml_decl_handler); 3166 XML_SetExternalEntityRefHandler(g_parser, external_entity_param_checker); 3167 XML_SetCommentHandler(g_parser, data_check_comment_handler); 3168 XML_SetSkippedEntityHandler(g_parser, param_check_skip_handler); 3169 XML_UseParserAsHandlerArg(g_parser); 3170 XML_SetUserData(g_parser, (void *)1); 3171 g_handler_data = g_parser; 3172 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE) 3173 == XML_STATUS_ERROR) 3174 xml_failure(g_parser); 3175 /* Ensure we can't change policy mid-parse */ 3176 if (XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_NEVER)) 3177 fail("Changed param entity parsing policy while parsing"); 3178 if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE) 3179 == XML_STATUS_ERROR) 3180 xml_failure(g_parser); 3181 if (g_comment_count != 3) 3182 fail("Comment handler not invoked enough times"); 3183 if (g_skip_count != 1) 3184 fail("Skip handler not invoked enough times"); 3185 if (g_xdecl_count != 1) 3186 fail("XML declaration handler not invoked"); 3187 } 3188 END_TEST 3189 3190 /* Test that an explicit external entity handler argument replaces 3191 * the parser as the first argument. 3192 * 3193 * We do not call the first parameter to the external entity handler 3194 * 'parser' for once, since the first time the handler is called it 3195 * will actually be a text string. We need to be able to access the 3196 * global 'parser' variable to create our external entity parser from, 3197 * since there are code paths we need to ensure get executed. 3198 */ 3199 START_TEST(test_ext_entity_ref_parameter) { 3200 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n" 3201 "<!DOCTYPE doc SYSTEM 'foo'>\n" 3202 "<doc>&entity;</doc>"; 3203 3204 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3205 XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker); 3206 /* Set a handler arg that is not NULL and not parser (which is 3207 * what NULL would cause to be passed. 3208 */ 3209 XML_SetExternalEntityRefHandlerArg(g_parser, (void *)text); 3210 g_handler_data = text; 3211 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3212 == XML_STATUS_ERROR) 3213 xml_failure(g_parser); 3214 3215 /* Now try again with unset args */ 3216 XML_ParserReset(g_parser, NULL); 3217 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3218 XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker); 3219 XML_SetExternalEntityRefHandlerArg(g_parser, NULL); 3220 g_handler_data = g_parser; 3221 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3222 == XML_STATUS_ERROR) 3223 xml_failure(g_parser); 3224 } 3225 END_TEST 3226 3227 /* Test the parsing of an empty string */ 3228 START_TEST(test_empty_parse) { 3229 const char *text = "<doc></doc>"; 3230 const char *partial = "<doc>"; 3231 3232 if (XML_Parse(g_parser, NULL, 0, XML_FALSE) == XML_STATUS_ERROR) 3233 fail("Parsing empty string faulted"); 3234 if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR) 3235 fail("Parsing final empty string not faulted"); 3236 if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_ELEMENTS) 3237 fail("Parsing final empty string faulted for wrong reason"); 3238 3239 /* Now try with valid text before the empty end */ 3240 XML_ParserReset(g_parser, NULL); 3241 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE) 3242 == XML_STATUS_ERROR) 3243 xml_failure(g_parser); 3244 if (XML_Parse(g_parser, NULL, 0, XML_TRUE) == XML_STATUS_ERROR) 3245 fail("Parsing final empty string faulted"); 3246 3247 /* Now try with invalid text before the empty end */ 3248 XML_ParserReset(g_parser, NULL); 3249 if (_XML_Parse_SINGLE_BYTES(g_parser, partial, (int)strlen(partial), 3250 XML_FALSE) 3251 == XML_STATUS_ERROR) 3252 xml_failure(g_parser); 3253 if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR) 3254 fail("Parsing final incomplete empty string not faulted"); 3255 } 3256 END_TEST 3257 3258 /* Test XML_Parse for len < 0 */ 3259 START_TEST(test_negative_len_parse) { 3260 const char *const doc = "<root/>"; 3261 for (int isFinal = 0; isFinal < 2; isFinal++) { 3262 set_subtest("isFinal=%d", isFinal); 3263 3264 XML_Parser parser = XML_ParserCreate(NULL); 3265 3266 if (XML_GetErrorCode(parser) != XML_ERROR_NONE) 3267 fail("There was not supposed to be any initial parse error."); 3268 3269 const enum XML_Status status = XML_Parse(parser, doc, -1, isFinal); 3270 3271 if (status != XML_STATUS_ERROR) 3272 fail("Negative len was expected to fail the parse but did not."); 3273 3274 if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_ARGUMENT) 3275 fail("Parse error does not match XML_ERROR_INVALID_ARGUMENT."); 3276 3277 XML_ParserFree(parser); 3278 } 3279 } 3280 END_TEST 3281 3282 /* Test XML_ParseBuffer for len < 0 */ 3283 START_TEST(test_negative_len_parse_buffer) { 3284 const char *const doc = "<root/>"; 3285 for (int isFinal = 0; isFinal < 2; isFinal++) { 3286 set_subtest("isFinal=%d", isFinal); 3287 3288 XML_Parser parser = XML_ParserCreate(NULL); 3289 3290 if (XML_GetErrorCode(parser) != XML_ERROR_NONE) 3291 fail("There was not supposed to be any initial parse error."); 3292 3293 void *const buffer = XML_GetBuffer(parser, (int)strlen(doc)); 3294 3295 if (buffer == NULL) 3296 fail("XML_GetBuffer failed."); 3297 3298 memcpy(buffer, doc, strlen(doc)); 3299 3300 const enum XML_Status status = XML_ParseBuffer(parser, -1, isFinal); 3301 3302 if (status != XML_STATUS_ERROR) 3303 fail("Negative len was expected to fail the parse but did not."); 3304 3305 if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_ARGUMENT) 3306 fail("Parse error does not match XML_ERROR_INVALID_ARGUMENT."); 3307 3308 XML_ParserFree(parser); 3309 } 3310 } 3311 END_TEST 3312 3313 /* Test odd corners of the XML_GetBuffer interface */ 3314 static enum XML_Status 3315 get_feature(enum XML_FeatureEnum feature_id, long *presult) { 3316 const XML_Feature *feature = XML_GetFeatureList(); 3317 3318 if (feature == NULL) 3319 return XML_STATUS_ERROR; 3320 for (; feature->feature != XML_FEATURE_END; feature++) { 3321 if (feature->feature == feature_id) { 3322 *presult = feature->value; 3323 return XML_STATUS_OK; 3324 } 3325 } 3326 return XML_STATUS_ERROR; 3327 } 3328 3329 /* Test odd corners of the XML_GetBuffer interface */ 3330 START_TEST(test_get_buffer_1) { 3331 const char *text = get_buffer_test_text; 3332 long context_bytes; 3333 3334 /* Attempt to allocate a negative length buffer */ 3335 if (XML_GetBuffer(g_parser, -12) != NULL) 3336 fail("Negative length buffer not failed"); 3337 3338 /* Now get a small buffer and extend it past valid length */ 3339 void *const buffer = XML_GetBuffer(g_parser, 1536); 3340 if (buffer == NULL) 3341 fail("1.5K buffer failed"); 3342 assert(buffer != NULL); 3343 memcpy(buffer, text, strlen(text)); 3344 if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE) 3345 == XML_STATUS_ERROR) 3346 xml_failure(g_parser); 3347 if (XML_GetBuffer(g_parser, INT_MAX) != NULL) 3348 fail("INT_MAX buffer not failed"); 3349 3350 /* Now try extending it a more reasonable but still too large 3351 * amount. The allocator in XML_GetBuffer() doubles the buffer 3352 * size until it exceeds the requested amount or INT_MAX. If it 3353 * exceeds INT_MAX, it rejects the request, so we want a request 3354 * between INT_MAX and INT_MAX/2. A gap of 1K seems comfortable, 3355 * with an extra byte just to ensure that the request is off any 3356 * boundary. The request will be inflated internally by 3357 * XML_CONTEXT_BYTES (if >=1), so we subtract that from our 3358 * request. 3359 */ 3360 if (get_feature(XML_FEATURE_CONTEXT_BYTES, &context_bytes) != XML_STATUS_OK) 3361 context_bytes = 0; 3362 if (XML_GetBuffer(g_parser, INT_MAX - (context_bytes + 1025)) != NULL) 3363 fail("INT_MAX- buffer not failed"); 3364 3365 /* Now try extending it a carefully crafted amount */ 3366 if (XML_GetBuffer(g_parser, 1000) == NULL) 3367 fail("1000 buffer failed"); 3368 } 3369 END_TEST 3370 3371 /* Test more corners of the XML_GetBuffer interface */ 3372 START_TEST(test_get_buffer_2) { 3373 const char *text = get_buffer_test_text; 3374 3375 /* Now get a decent buffer */ 3376 void *const buffer = XML_GetBuffer(g_parser, 1536); 3377 if (buffer == NULL) 3378 fail("1.5K buffer failed"); 3379 assert(buffer != NULL); 3380 memcpy(buffer, text, strlen(text)); 3381 if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE) 3382 == XML_STATUS_ERROR) 3383 xml_failure(g_parser); 3384 3385 /* Extend it, to catch a different code path */ 3386 if (XML_GetBuffer(g_parser, 1024) == NULL) 3387 fail("1024 buffer failed"); 3388 } 3389 END_TEST 3390 3391 /* Test for signed integer overflow CVE-2022-23852 */ 3392 #if XML_CONTEXT_BYTES > 0 3393 START_TEST(test_get_buffer_3_overflow) { 3394 XML_Parser parser = XML_ParserCreate(NULL); 3395 assert(parser != NULL); 3396 3397 const char *const text = "\n"; 3398 const int expectedKeepValue = (int)strlen(text); 3399 3400 // After this call, variable "keep" in XML_GetBuffer will 3401 // have value expectedKeepValue 3402 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), 3403 XML_FALSE /* isFinal */) 3404 == XML_STATUS_ERROR) 3405 xml_failure(parser); 3406 3407 assert(expectedKeepValue > 0); 3408 if (XML_GetBuffer(parser, INT_MAX - expectedKeepValue + 1) != NULL) 3409 fail("enlarging buffer not failed"); 3410 3411 XML_ParserFree(parser); 3412 } 3413 END_TEST 3414 #endif // XML_CONTEXT_BYTES > 0 3415 3416 START_TEST(test_buffer_can_grow_to_max) { 3417 const char *const prefixes[] = { 3418 "", 3419 "<", 3420 "<x a='", 3421 "<doc><x a='", 3422 "<document><x a='", 3423 "<averylongelementnamesuchthatitwillhopefullystretchacrossmultiplelinesand" 3424 "lookprettyridiculousitsalsoveryhardtoreadandifyouredoingitihavetowonderif" 3425 "youreallydonthaveanythingbettertodoofcourseiguessicouldveputsomethingbadin" 3426 "herebutipromisethatididntheybtwhowgreatarespacesandpunctuationforhelping" 3427 "withreadabilityprettygreatithinkanywaysthisisprobablylongenoughbye><x a='"}; 3428 const int num_prefixes = sizeof(prefixes) / sizeof(prefixes[0]); 3429 int maxbuf = INT_MAX / 2 + (INT_MAX & 1); // round up without overflow 3430 #if defined(__MINGW32__) && ! defined(__MINGW64__) 3431 // workaround for mingw/wine32 on GitHub CI not being able to reach 1GiB 3432 // Can we make a big allocation? 3433 for (int i = 1; i <= 2; i++) { 3434 void *const big = malloc(maxbuf); 3435 if (big != NULL) { 3436 free(big); 3437 break; 3438 } 3439 // The big allocation failed. Let's be a little lenient. 3440 maxbuf = maxbuf / 2; 3441 fprintf(stderr, "Reducing maxbuf to %d...\n", maxbuf); 3442 } 3443 #endif 3444 3445 for (int i = 0; i < num_prefixes; ++i) { 3446 set_subtest("\"%s\"", prefixes[i]); 3447 XML_Parser parser = XML_ParserCreate(NULL); 3448 #if XML_GE == 1 3449 assert_true(XML_SetAllocTrackerActivationThreshold(parser, (size_t)-1) 3450 == XML_TRUE); // i.e. deactivate 3451 #endif 3452 const int prefix_len = (int)strlen(prefixes[i]); 3453 const enum XML_Status s 3454 = _XML_Parse_SINGLE_BYTES(parser, prefixes[i], prefix_len, XML_FALSE); 3455 if (s != XML_STATUS_OK) 3456 xml_failure(parser); 3457 3458 // Avoid running into "AddressSanitizer: out of memory" on 32bit Windows 3459 #if ! defined(_WIN32) || EXPAT_TESTS_ASAN == 0 || EXPAT_TESTS_64BIT == 1 3460 // XML_CONTEXT_BYTES of the prefix may remain in the buffer; 3461 // subtracting the whole prefix is easiest, and close enough. 3462 assert_true(XML_GetBuffer(parser, maxbuf - prefix_len) != NULL); 3463 // The limit should be consistent; no prefix should allow us to 3464 // reach above the max buffer size. 3465 assert_true(XML_GetBuffer(parser, maxbuf + 1) == NULL); 3466 #endif 3467 3468 XML_ParserFree(parser); 3469 } 3470 } 3471 END_TEST 3472 3473 START_TEST(test_getbuffer_allocates_on_zero_len) { 3474 for (int first_len = 1; first_len >= 0; first_len--) { 3475 set_subtest("with len=%d first", first_len); 3476 XML_Parser parser = XML_ParserCreate(NULL); 3477 assert_true(parser != NULL); 3478 assert_true(XML_GetBuffer(parser, first_len) != NULL); 3479 assert_true(XML_GetBuffer(parser, 0) != NULL); 3480 if (XML_ParseBuffer(parser, 0, XML_FALSE) != XML_STATUS_OK) 3481 xml_failure(parser); 3482 XML_ParserFree(parser); 3483 } 3484 } 3485 END_TEST 3486 3487 /* Test position information macros */ 3488 START_TEST(test_byte_info_at_end) { 3489 const char *text = "<doc></doc>"; 3490 3491 if (XML_GetCurrentByteIndex(g_parser) != -1 3492 || XML_GetCurrentByteCount(g_parser) != 0) 3493 fail("Byte index/count incorrect at start of parse"); 3494 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3495 == XML_STATUS_ERROR) 3496 xml_failure(g_parser); 3497 /* At end, the count will be zero and the index the end of string */ 3498 if (XML_GetCurrentByteCount(g_parser) != 0) 3499 fail("Terminal byte count incorrect"); 3500 if (XML_GetCurrentByteIndex(g_parser) != (XML_Index)strlen(text)) 3501 fail("Terminal byte index incorrect"); 3502 } 3503 END_TEST 3504 3505 /* Test position information from errors */ 3506 #define PRE_ERROR_STR "<doc></" 3507 #define POST_ERROR_STR "wombat></doc>" 3508 START_TEST(test_byte_info_at_error) { 3509 const char *text = PRE_ERROR_STR POST_ERROR_STR; 3510 3511 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3512 == XML_STATUS_OK) 3513 fail("Syntax error not faulted"); 3514 if (XML_GetCurrentByteCount(g_parser) != 0) 3515 fail("Error byte count incorrect"); 3516 if (XML_GetCurrentByteIndex(g_parser) != strlen(PRE_ERROR_STR)) 3517 fail("Error byte index incorrect"); 3518 } 3519 END_TEST 3520 #undef PRE_ERROR_STR 3521 #undef POST_ERROR_STR 3522 3523 /* Test position information in handler */ 3524 #define START_ELEMENT "<e>" 3525 #define CDATA_TEXT "Hello" 3526 #define END_ELEMENT "</e>" 3527 START_TEST(test_byte_info_at_cdata) { 3528 const char *text = START_ELEMENT CDATA_TEXT END_ELEMENT; 3529 int offset, size; 3530 ByteTestData data; 3531 3532 /* Check initial context is empty */ 3533 if (XML_GetInputContext(g_parser, &offset, &size) != NULL) 3534 fail("Unexpected context at start of parse"); 3535 3536 data.start_element_len = (int)strlen(START_ELEMENT); 3537 data.cdata_len = (int)strlen(CDATA_TEXT); 3538 data.total_string_len = (int)strlen(text); 3539 XML_SetCharacterDataHandler(g_parser, byte_character_handler); 3540 XML_SetUserData(g_parser, &data); 3541 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_OK) 3542 xml_failure(g_parser); 3543 } 3544 END_TEST 3545 #undef START_ELEMENT 3546 #undef CDATA_TEXT 3547 #undef END_ELEMENT 3548 3549 /* Test predefined entities are correctly recognised */ 3550 START_TEST(test_predefined_entities) { 3551 const char *text = "<doc><>&"'</doc>"; 3552 const XML_Char *expected = XCS("<doc><>&"'</doc>"); 3553 const XML_Char *result = XCS("<>&\"'"); 3554 CharData storage; 3555 3556 XML_SetDefaultHandler(g_parser, accumulate_characters); 3557 /* run_character_check uses XML_SetCharacterDataHandler(), which 3558 * unfortunately heads off a code path that we need to exercise. 3559 */ 3560 CharData_Init(&storage); 3561 XML_SetUserData(g_parser, &storage); 3562 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3563 == XML_STATUS_ERROR) 3564 xml_failure(g_parser); 3565 /* The default handler doesn't translate the entities */ 3566 CharData_CheckXMLChars(&storage, expected); 3567 3568 /* Now try again and check the translation */ 3569 XML_ParserReset(g_parser, NULL); 3570 run_character_check(text, result); 3571 } 3572 END_TEST 3573 3574 /* Regression test that an invalid tag in an external parameter 3575 * reference in an external DTD is correctly faulted. 3576 * 3577 * Only a few specific tags are legal in DTDs ignoring comments and 3578 * processing instructions, all of which begin with an exclamation 3579 * mark. "<el/>" is not one of them, so the parser should raise an 3580 * error on encountering it. 3581 */ 3582 START_TEST(test_invalid_tag_in_dtd) { 3583 const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n" 3584 "<doc></doc>\n"; 3585 3586 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3587 XML_SetExternalEntityRefHandler(g_parser, external_entity_param); 3588 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 3589 "Invalid tag IN DTD external param not rejected"); 3590 } 3591 END_TEST 3592 3593 /* Test entities not quite the predefined ones are not mis-recognised */ 3594 START_TEST(test_not_predefined_entities) { 3595 const char *text[] = {"<doc>&pt;</doc>", "<doc>&amo;</doc>", 3596 "<doc>&quid;</doc>", "<doc>&apod;</doc>", NULL}; 3597 int i = 0; 3598 3599 while (text[i] != NULL) { 3600 expect_failure(text[i], XML_ERROR_UNDEFINED_ENTITY, 3601 "Undefined entity not rejected"); 3602 XML_ParserReset(g_parser, NULL); 3603 i++; 3604 } 3605 } 3606 END_TEST 3607 3608 /* Test conditional inclusion (IGNORE) */ 3609 START_TEST(test_ignore_section) { 3610 const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n" 3611 "<doc><e>&entity;</e></doc>"; 3612 const XML_Char *expected 3613 = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&entity;"); 3614 CharData storage; 3615 3616 CharData_Init(&storage); 3617 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3618 XML_SetUserData(g_parser, &storage); 3619 XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore); 3620 XML_SetDefaultHandler(g_parser, accumulate_characters); 3621 XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler); 3622 XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler); 3623 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler); 3624 XML_SetStartElementHandler(g_parser, dummy_start_element); 3625 XML_SetEndElementHandler(g_parser, dummy_end_element); 3626 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3627 == XML_STATUS_ERROR) 3628 xml_failure(g_parser); 3629 CharData_CheckXMLChars(&storage, expected); 3630 } 3631 END_TEST 3632 3633 START_TEST(test_ignore_section_utf16) { 3634 const char text[] = 3635 /* <!DOCTYPE d SYSTEM 's'> */ 3636 "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 " 3637 "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n\0" 3638 /* <d><e>&en;</e></d> */ 3639 "<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>\0"; 3640 const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;"); 3641 CharData storage; 3642 3643 CharData_Init(&storage); 3644 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3645 XML_SetUserData(g_parser, &storage); 3646 XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore_utf16); 3647 XML_SetDefaultHandler(g_parser, accumulate_characters); 3648 XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler); 3649 XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler); 3650 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler); 3651 XML_SetStartElementHandler(g_parser, dummy_start_element); 3652 XML_SetEndElementHandler(g_parser, dummy_end_element); 3653 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 3654 == XML_STATUS_ERROR) 3655 xml_failure(g_parser); 3656 CharData_CheckXMLChars(&storage, expected); 3657 } 3658 END_TEST 3659 3660 START_TEST(test_ignore_section_utf16_be) { 3661 const char text[] = 3662 /* <!DOCTYPE d SYSTEM 's'> */ 3663 "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 " 3664 "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n" 3665 /* <d><e>&en;</e></d> */ 3666 "\0<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>"; 3667 const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;"); 3668 CharData storage; 3669 3670 CharData_Init(&storage); 3671 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3672 XML_SetUserData(g_parser, &storage); 3673 XML_SetExternalEntityRefHandler(g_parser, 3674 external_entity_load_ignore_utf16_be); 3675 XML_SetDefaultHandler(g_parser, accumulate_characters); 3676 XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler); 3677 XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler); 3678 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler); 3679 XML_SetStartElementHandler(g_parser, dummy_start_element); 3680 XML_SetEndElementHandler(g_parser, dummy_end_element); 3681 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 3682 == XML_STATUS_ERROR) 3683 xml_failure(g_parser); 3684 CharData_CheckXMLChars(&storage, expected); 3685 } 3686 END_TEST 3687 3688 /* Test mis-formatted conditional exclusion */ 3689 START_TEST(test_bad_ignore_section) { 3690 const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n" 3691 "<doc><e>&entity;</e></doc>"; 3692 ExtFaults faults[] 3693 = {{"<![IGNORE[<!ELEM", "Broken-off declaration not faulted", NULL, 3694 XML_ERROR_SYNTAX}, 3695 {"<![IGNORE[\x01]]>", "Invalid XML character not faulted", NULL, 3696 XML_ERROR_INVALID_TOKEN}, 3697 {/* FIrst two bytes of a three-byte char */ 3698 "<![IGNORE[\xe2\x82", "Partial XML character not faulted", NULL, 3699 XML_ERROR_PARTIAL_CHAR}, 3700 {NULL, NULL, NULL, XML_ERROR_NONE}}; 3701 ExtFaults *fault; 3702 3703 for (fault = &faults[0]; fault->parse_text != NULL; fault++) { 3704 set_subtest("%s", fault->parse_text); 3705 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3706 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter); 3707 XML_SetUserData(g_parser, fault); 3708 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 3709 "Incomplete IGNORE section not failed"); 3710 XML_ParserReset(g_parser, NULL); 3711 } 3712 } 3713 END_TEST 3714 3715 struct bom_testdata { 3716 const char *external; 3717 int split; 3718 XML_Bool nested_callback_happened; 3719 }; 3720 3721 static int XMLCALL 3722 external_bom_checker(XML_Parser parser, const XML_Char *context, 3723 const XML_Char *base, const XML_Char *systemId, 3724 const XML_Char *publicId) { 3725 const char *text; 3726 UNUSED_P(base); 3727 UNUSED_P(systemId); 3728 UNUSED_P(publicId); 3729 3730 XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); 3731 if (ext_parser == NULL) 3732 fail("Could not create external entity parser"); 3733 3734 if (! xcstrcmp(systemId, XCS("004-2.ent"))) { 3735 struct bom_testdata *const testdata = XML_GetUserData(parser); 3736 const char *const external = testdata->external; 3737 const int split = testdata->split; 3738 testdata->nested_callback_happened = XML_TRUE; 3739 3740 if (_XML_Parse_SINGLE_BYTES(ext_parser, external, split, XML_FALSE) 3741 != XML_STATUS_OK) { 3742 xml_failure(ext_parser); 3743 } 3744 text = external + split; // the parse below will continue where we left off. 3745 } else if (! xcstrcmp(systemId, XCS("004-1.ent"))) { 3746 text = "<!ELEMENT doc EMPTY>\n" 3747 "<!ENTITY % e1 SYSTEM '004-2.ent'>\n" 3748 "<!ENTITY % e2 '%e1;'>\n"; 3749 } else { 3750 fail("unknown systemId"); 3751 } 3752 3753 if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) 3754 != XML_STATUS_OK) 3755 xml_failure(ext_parser); 3756 3757 XML_ParserFree(ext_parser); 3758 return XML_STATUS_OK; 3759 } 3760 3761 /* regression test: BOM should be consumed when followed by a partial token. */ 3762 START_TEST(test_external_bom_consumed) { 3763 const char *const text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n" 3764 "<doc></doc>\n"; 3765 const char *const external = "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>"; 3766 const int len = (int)strlen(external); 3767 for (int split = 0; split <= len; ++split) { 3768 set_subtest("split at byte %d", split); 3769 3770 struct bom_testdata testdata; 3771 testdata.external = external; 3772 testdata.split = split; 3773 testdata.nested_callback_happened = XML_FALSE; 3774 3775 XML_Parser parser = XML_ParserCreate(NULL); 3776 if (parser == NULL) { 3777 fail("Couldn't create parser"); 3778 } 3779 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3780 XML_SetExternalEntityRefHandler(parser, external_bom_checker); 3781 XML_SetUserData(parser, &testdata); 3782 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 3783 == XML_STATUS_ERROR) 3784 xml_failure(parser); 3785 if (! testdata.nested_callback_happened) { 3786 fail("ref handler not called"); 3787 } 3788 XML_ParserFree(parser); 3789 } 3790 } 3791 END_TEST 3792 3793 /* Test recursive parsing */ 3794 START_TEST(test_external_entity_values) { 3795 const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n" 3796 "<doc></doc>\n"; 3797 ExtFaults data_004_2[] = { 3798 {"<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL, XML_ERROR_NONE}, 3799 {"<!ATTLIST $doc a1 CDATA 'value'>", "Invalid token not faulted", NULL, 3800 XML_ERROR_INVALID_TOKEN}, 3801 {"'wombat", "Unterminated string not faulted", NULL, 3802 XML_ERROR_UNCLOSED_TOKEN}, 3803 {"\xe2\x82", "Partial UTF-8 character not faulted", NULL, 3804 XML_ERROR_PARTIAL_CHAR}, 3805 {"<?xml version='1.0' encoding='utf-8'?>\n", NULL, NULL, XML_ERROR_NONE}, 3806 {"<?xml?>", "Malformed XML declaration not faulted", NULL, 3807 XML_ERROR_XML_DECL}, 3808 {/* UTF-8 BOM */ 3809 "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL, 3810 XML_ERROR_NONE}, 3811 {"<?xml version='1.0' encoding='utf-8'?>\n$", 3812 "Invalid token after text declaration not faulted", NULL, 3813 XML_ERROR_INVALID_TOKEN}, 3814 {"<?xml version='1.0' encoding='utf-8'?>\n'wombat", 3815 "Unterminated string after text decl not faulted", NULL, 3816 XML_ERROR_UNCLOSED_TOKEN}, 3817 {"<?xml version='1.0' encoding='utf-8'?>\n\xe2\x82", 3818 "Partial UTF-8 character after text decl not faulted", NULL, 3819 XML_ERROR_PARTIAL_CHAR}, 3820 {"%e1;", "Recursive parameter entity not faulted", NULL, 3821 XML_ERROR_RECURSIVE_ENTITY_REF}, 3822 {NULL, NULL, NULL, XML_ERROR_NONE}}; 3823 int i; 3824 3825 for (i = 0; data_004_2[i].parse_text != NULL; i++) { 3826 set_subtest("%s", data_004_2[i].parse_text); 3827 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3828 XML_SetExternalEntityRefHandler(g_parser, external_entity_valuer); 3829 XML_SetUserData(g_parser, &data_004_2[i]); 3830 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3831 == XML_STATUS_ERROR) 3832 xml_failure(g_parser); 3833 XML_ParserReset(g_parser, NULL); 3834 } 3835 } 3836 END_TEST 3837 3838 /* Test the recursive parse interacts with a not standalone handler */ 3839 START_TEST(test_ext_entity_not_standalone) { 3840 const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n" 3841 "<doc></doc>"; 3842 3843 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3844 XML_SetExternalEntityRefHandler(g_parser, external_entity_not_standalone); 3845 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 3846 "Standalone rejection not caught"); 3847 } 3848 END_TEST 3849 3850 START_TEST(test_ext_entity_value_abort) { 3851 const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n" 3852 "<doc></doc>\n"; 3853 3854 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3855 XML_SetExternalEntityRefHandler(g_parser, external_entity_value_aborter); 3856 g_resumable = XML_FALSE; 3857 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3858 == XML_STATUS_ERROR) 3859 xml_failure(g_parser); 3860 } 3861 END_TEST 3862 3863 START_TEST(test_bad_public_doctype) { 3864 const char *text = "<?xml version='1.0' encoding='utf-8'?>\n" 3865 "<!DOCTYPE doc PUBLIC '{BadName}' 'test'>\n" 3866 "<doc></doc>"; 3867 3868 /* Setting a handler provokes a particular code path */ 3869 XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler, 3870 dummy_end_doctype_handler); 3871 expect_failure(text, XML_ERROR_PUBLICID, "Bad Public ID not failed"); 3872 } 3873 END_TEST 3874 3875 /* Test based on ibm/valid/P32/ibm32v04.xml */ 3876 START_TEST(test_attribute_enum_value) { 3877 const char *text = "<?xml version='1.0' standalone='no'?>\n" 3878 "<!DOCTYPE animal SYSTEM 'test.dtd'>\n" 3879 "<animal>This is a \n <a/> \n\nyellow tiger</animal>"; 3880 ExtTest dtd_data 3881 = {"<!ELEMENT animal (#PCDATA|a)*>\n" 3882 "<!ELEMENT a EMPTY>\n" 3883 "<!ATTLIST animal xml:space (default|preserve) 'preserve'>", 3884 NULL, NULL}; 3885 const XML_Char *expected = XCS("This is a \n \n\nyellow tiger"); 3886 3887 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 3888 XML_SetUserData(g_parser, &dtd_data); 3889 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3890 /* An attribute list handler provokes a different code path */ 3891 XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler); 3892 run_ext_character_check(text, &dtd_data, expected); 3893 } 3894 END_TEST 3895 3896 /* Slightly bizarrely, the library seems to silently ignore entity 3897 * definitions for predefined entities, even when they are wrong. The 3898 * language of the XML 1.0 spec is somewhat unhelpful as to what ought 3899 * to happen, so this is currently treated as acceptable. 3900 */ 3901 START_TEST(test_predefined_entity_redefinition) { 3902 const char *text = "<!DOCTYPE doc [\n" 3903 "<!ENTITY apos 'foo'>\n" 3904 "]>\n" 3905 "<doc>'</doc>"; 3906 run_character_check(text, XCS("'")); 3907 } 3908 END_TEST 3909 3910 /* Test that the parser stops processing the DTD after an unresolved 3911 * parameter entity is encountered. 3912 */ 3913 START_TEST(test_dtd_stop_processing) { 3914 const char *text = "<!DOCTYPE doc [\n" 3915 "%foo;\n" 3916 "<!ENTITY bar 'bas'>\n" 3917 "]><doc/>"; 3918 3919 XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler); 3920 init_dummy_handlers(); 3921 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3922 == XML_STATUS_ERROR) 3923 xml_failure(g_parser); 3924 if (get_dummy_handler_flags() != 0) 3925 fail("DTD processing still going after undefined PE"); 3926 } 3927 END_TEST 3928 3929 /* Test public notations with no system ID */ 3930 START_TEST(test_public_notation_no_sysid) { 3931 const char *text = "<!DOCTYPE doc [\n" 3932 "<!NOTATION note PUBLIC 'foo'>\n" 3933 "<!ELEMENT doc EMPTY>\n" 3934 "]>\n<doc/>"; 3935 3936 init_dummy_handlers(); 3937 XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler); 3938 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3939 == XML_STATUS_ERROR) 3940 xml_failure(g_parser); 3941 if (get_dummy_handler_flags() != DUMMY_NOTATION_DECL_HANDLER_FLAG) 3942 fail("Notation declaration handler not called"); 3943 } 3944 END_TEST 3945 3946 START_TEST(test_nested_groups) { 3947 const char *text 3948 = "<!DOCTYPE doc [\n" 3949 "<!ELEMENT doc " 3950 /* Sixteen elements per line */ 3951 "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?," 3952 "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?" 3953 "))))))))))))))))))))))))))))))))>\n" 3954 "<!ELEMENT e EMPTY>" 3955 "]>\n" 3956 "<doc><e/></doc>"; 3957 CharData storage; 3958 3959 CharData_Init(&storage); 3960 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler); 3961 XML_SetStartElementHandler(g_parser, record_element_start_handler); 3962 XML_SetUserData(g_parser, &storage); 3963 init_dummy_handlers(); 3964 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3965 == XML_STATUS_ERROR) 3966 xml_failure(g_parser); 3967 CharData_CheckXMLChars(&storage, XCS("doce")); 3968 if (get_dummy_handler_flags() != DUMMY_ELEMENT_DECL_HANDLER_FLAG) 3969 fail("Element handler not fired"); 3970 } 3971 END_TEST 3972 3973 START_TEST(test_group_choice) { 3974 const char *text = "<!DOCTYPE doc [\n" 3975 "<!ELEMENT doc (a|b|c)+>\n" 3976 "<!ELEMENT a EMPTY>\n" 3977 "<!ELEMENT b (#PCDATA)>\n" 3978 "<!ELEMENT c ANY>\n" 3979 "]>\n" 3980 "<doc>\n" 3981 "<a/>\n" 3982 "<b attr='foo'>This is a foo</b>\n" 3983 "<c></c>\n" 3984 "</doc>\n"; 3985 3986 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler); 3987 init_dummy_handlers(); 3988 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 3989 == XML_STATUS_ERROR) 3990 xml_failure(g_parser); 3991 if (get_dummy_handler_flags() != DUMMY_ELEMENT_DECL_HANDLER_FLAG) 3992 fail("Element handler flag not raised"); 3993 } 3994 END_TEST 3995 3996 START_TEST(test_standalone_parameter_entity) { 3997 const char *text = "<?xml version='1.0' standalone='yes'?>\n" 3998 "<!DOCTYPE doc SYSTEM 'http://example.org/' [\n" 3999 "<!ENTITY % entity '<!ELEMENT doc (#PCDATA)>'>\n" 4000 "%entity;\n" 4001 "]>\n" 4002 "<doc></doc>"; 4003 char dtd_data[] = "<!ENTITY % e1 'foo'>\n"; 4004 4005 XML_SetUserData(g_parser, dtd_data); 4006 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4007 XML_SetExternalEntityRefHandler(g_parser, external_entity_public); 4008 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4009 == XML_STATUS_ERROR) 4010 xml_failure(g_parser); 4011 } 4012 END_TEST 4013 4014 /* Test skipping of parameter entity in an external DTD */ 4015 /* Derived from ibm/invalid/P69/ibm69i01.xml */ 4016 START_TEST(test_skipped_parameter_entity) { 4017 const char *text = "<?xml version='1.0'?>\n" 4018 "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n" 4019 "<!ELEMENT root (#PCDATA|a)* >\n" 4020 "]>\n" 4021 "<root></root>"; 4022 ExtTest dtd_data = {"%pe2;", NULL, NULL}; 4023 4024 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 4025 XML_SetUserData(g_parser, &dtd_data); 4026 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4027 XML_SetSkippedEntityHandler(g_parser, dummy_skip_handler); 4028 init_dummy_handlers(); 4029 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4030 == XML_STATUS_ERROR) 4031 xml_failure(g_parser); 4032 if (get_dummy_handler_flags() != DUMMY_SKIP_HANDLER_FLAG) 4033 fail("Skip handler not executed"); 4034 } 4035 END_TEST 4036 4037 /* Test recursive parameter entity definition rejected in external DTD */ 4038 START_TEST(test_recursive_external_parameter_entity) { 4039 const char *text = "<?xml version='1.0'?>\n" 4040 "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n" 4041 "<!ELEMENT root (#PCDATA|a)* >\n" 4042 "]>\n" 4043 "<root></root>"; 4044 ExtFaults dtd_data = {"<!ENTITY % pe2 '%pe2;'>\n%pe2;", 4045 "Recursive external parameter entity not faulted", NULL, 4046 XML_ERROR_RECURSIVE_ENTITY_REF}; 4047 4048 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter); 4049 XML_SetUserData(g_parser, &dtd_data); 4050 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4051 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 4052 "Recursive external parameter not spotted"); 4053 } 4054 END_TEST 4055 4056 /* Test undefined parameter entity in external entity handler */ 4057 START_TEST(test_undefined_ext_entity_in_external_dtd) { 4058 const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n" 4059 "<doc></doc>\n"; 4060 4061 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4062 XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer); 4063 XML_SetUserData(g_parser, NULL); 4064 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4065 == XML_STATUS_ERROR) 4066 xml_failure(g_parser); 4067 4068 /* Now repeat without the external entity ref handler invoking 4069 * another copy of itself. 4070 */ 4071 XML_ParserReset(g_parser, NULL); 4072 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4073 XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer); 4074 XML_SetUserData(g_parser, g_parser); /* Any non-NULL value will do */ 4075 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4076 == XML_STATUS_ERROR) 4077 xml_failure(g_parser); 4078 } 4079 END_TEST 4080 4081 /* Test suspending the parse on receiving an XML declaration works */ 4082 START_TEST(test_suspend_xdecl) { 4083 const char *text = long_character_data_text; 4084 4085 XML_SetXmlDeclHandler(g_parser, entity_suspending_xdecl_handler); 4086 XML_SetUserData(g_parser, g_parser); 4087 g_resumable = XML_TRUE; 4088 // can't use SINGLE_BYTES here, because it'll return early on suspension, and 4089 // we won't know exactly how much input we actually managed to give Expat. 4090 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) 4091 != XML_STATUS_SUSPENDED) 4092 xml_failure(g_parser); 4093 if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE) 4094 xml_failure(g_parser); 4095 /* Attempt to start a new parse while suspended */ 4096 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4097 != XML_STATUS_ERROR) 4098 fail("Attempt to parse while suspended not faulted"); 4099 if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED) 4100 fail("Suspended parse not faulted with correct error"); 4101 } 4102 END_TEST 4103 4104 /* Test aborting the parse in an epilog works */ 4105 START_TEST(test_abort_epilog) { 4106 const char *text = "<doc></doc>\n\r\n"; 4107 XML_Char trigger_char = XCS('\r'); 4108 4109 XML_SetDefaultHandler(g_parser, selective_aborting_default_handler); 4110 XML_SetUserData(g_parser, &trigger_char); 4111 g_resumable = XML_FALSE; 4112 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4113 != XML_STATUS_ERROR) 4114 fail("Abort not triggered"); 4115 if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED) 4116 xml_failure(g_parser); 4117 } 4118 END_TEST 4119 4120 /* Test a different code path for abort in the epilog */ 4121 START_TEST(test_abort_epilog_2) { 4122 const char *text = "<doc></doc>\n"; 4123 XML_Char trigger_char = XCS('\n'); 4124 4125 XML_SetDefaultHandler(g_parser, selective_aborting_default_handler); 4126 XML_SetUserData(g_parser, &trigger_char); 4127 g_resumable = XML_FALSE; 4128 expect_failure(text, XML_ERROR_ABORTED, "Abort not triggered"); 4129 } 4130 END_TEST 4131 4132 /* Test suspension from the epilog */ 4133 START_TEST(test_suspend_epilog) { 4134 const char *text = "<doc></doc>\n"; 4135 XML_Char trigger_char = XCS('\n'); 4136 4137 XML_SetDefaultHandler(g_parser, selective_aborting_default_handler); 4138 XML_SetUserData(g_parser, &trigger_char); 4139 g_resumable = XML_TRUE; 4140 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4141 != XML_STATUS_SUSPENDED) 4142 xml_failure(g_parser); 4143 } 4144 END_TEST 4145 4146 START_TEST(test_suspend_in_sole_empty_tag) { 4147 const char *text = "<doc/>"; 4148 enum XML_Status rc; 4149 4150 XML_SetEndElementHandler(g_parser, suspending_end_handler); 4151 XML_SetUserData(g_parser, g_parser); 4152 rc = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE); 4153 if (rc == XML_STATUS_ERROR) 4154 xml_failure(g_parser); 4155 else if (rc != XML_STATUS_SUSPENDED) 4156 fail("Suspend not triggered"); 4157 rc = XML_ResumeParser(g_parser); 4158 if (rc == XML_STATUS_ERROR) 4159 xml_failure(g_parser); 4160 else if (rc != XML_STATUS_OK) 4161 fail("Resume failed"); 4162 } 4163 END_TEST 4164 4165 START_TEST(test_unfinished_epilog) { 4166 const char *text = "<doc></doc><"; 4167 4168 expect_failure(text, XML_ERROR_UNCLOSED_TOKEN, 4169 "Incomplete epilog entry not faulted"); 4170 } 4171 END_TEST 4172 4173 START_TEST(test_partial_char_in_epilog) { 4174 const char *text = "<doc></doc>\xe2\x82"; 4175 4176 /* First check that no fault is raised if the parse is not finished */ 4177 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE) 4178 == XML_STATUS_ERROR) 4179 xml_failure(g_parser); 4180 /* Now check that it is faulted once we finish */ 4181 if (XML_ParseBuffer(g_parser, 0, XML_TRUE) != XML_STATUS_ERROR) 4182 fail("Partial character in epilog not faulted"); 4183 if (XML_GetErrorCode(g_parser) != XML_ERROR_PARTIAL_CHAR) 4184 xml_failure(g_parser); 4185 } 4186 END_TEST 4187 4188 /* Test resuming a parse suspended in entity substitution */ 4189 START_TEST(test_suspend_resume_internal_entity) { 4190 const char *text 4191 = "<!DOCTYPE doc [\n" 4192 "<!ENTITY foo '<suspend>Hi<suspend>Ho</suspend></suspend>'>\n" 4193 "]>\n" 4194 "<doc>&foo;</doc>\n"; 4195 const XML_Char *expected1 = XCS("Hi"); 4196 const XML_Char *expected2 = XCS("HiHo"); 4197 CharData storage; 4198 4199 CharData_Init(&storage); 4200 XML_SetStartElementHandler(g_parser, start_element_suspender); 4201 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 4202 XML_SetUserData(g_parser, &storage); 4203 // can't use SINGLE_BYTES here, because it'll return early on suspension, and 4204 // we won't know exactly how much input we actually managed to give Expat. 4205 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) 4206 != XML_STATUS_SUSPENDED) 4207 xml_failure(g_parser); 4208 CharData_CheckXMLChars(&storage, XCS("")); 4209 if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED) 4210 xml_failure(g_parser); 4211 CharData_CheckXMLChars(&storage, expected1); 4212 if (XML_ResumeParser(g_parser) != XML_STATUS_OK) 4213 xml_failure(g_parser); 4214 CharData_CheckXMLChars(&storage, expected2); 4215 } 4216 END_TEST 4217 4218 START_TEST(test_suspend_resume_internal_entity_issue_629) { 4219 const char *const text 4220 = "<!DOCTYPE a [<!ENTITY e '<!--COMMENT-->a'>]><a>&e;<b>\n" 4221 "<" 4222 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4223 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4224 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4225 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4226 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4227 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4228 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4229 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4230 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4231 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4232 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4233 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4234 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4235 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4236 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4237 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4238 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4239 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4240 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4241 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4242 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4243 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4244 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4245 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4246 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4247 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4248 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4249 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4250 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4251 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4252 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4253 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4254 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4255 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4256 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4257 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4258 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4259 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4260 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4261 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4262 "/>" 4263 "</b></a>"; 4264 const size_t firstChunkSizeBytes = 54; 4265 4266 XML_Parser parser = XML_ParserCreate(NULL); 4267 XML_SetUserData(parser, parser); 4268 XML_SetCommentHandler(parser, suspending_comment_handler); 4269 4270 if (XML_Parse(parser, text, (int)firstChunkSizeBytes, XML_FALSE) 4271 != XML_STATUS_SUSPENDED) 4272 xml_failure(parser); 4273 if (XML_ResumeParser(parser) != XML_STATUS_OK) 4274 xml_failure(parser); 4275 if (_XML_Parse_SINGLE_BYTES(parser, text + firstChunkSizeBytes, 4276 (int)(strlen(text) - firstChunkSizeBytes), 4277 XML_TRUE) 4278 != XML_STATUS_OK) 4279 xml_failure(parser); 4280 XML_ParserFree(parser); 4281 } 4282 END_TEST 4283 4284 /* Test syntax error is caught at parse resumption */ 4285 START_TEST(test_resume_entity_with_syntax_error) { 4286 if (g_chunkSize != 0) { 4287 // this test does not use SINGLE_BYTES, because of suspension 4288 return; 4289 } 4290 4291 const char *text = "<!DOCTYPE doc [\n" 4292 "<!ENTITY foo '<suspend>Hi</wombat>'>\n" 4293 "]>\n" 4294 "<doc>&foo;</doc>\n"; 4295 4296 XML_SetStartElementHandler(g_parser, start_element_suspender); 4297 // can't use SINGLE_BYTES here, because it'll return early on suspension, and 4298 // we won't know exactly how much input we actually managed to give Expat. 4299 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) 4300 != XML_STATUS_SUSPENDED) 4301 xml_failure(g_parser); 4302 if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR) 4303 fail("Syntax error in entity not faulted"); 4304 if (XML_GetErrorCode(g_parser) != XML_ERROR_TAG_MISMATCH) 4305 xml_failure(g_parser); 4306 } 4307 END_TEST 4308 4309 /* Test suspending and resuming in a parameter entity substitution */ 4310 START_TEST(test_suspend_resume_parameter_entity) { 4311 const char *text = "<!DOCTYPE doc [\n" 4312 "<!ENTITY % foo '<!ELEMENT doc (#PCDATA)*>'>\n" 4313 "%foo;\n" 4314 "]>\n" 4315 "<doc>Hello, world</doc>"; 4316 const XML_Char *expected = XCS("Hello, world"); 4317 CharData storage; 4318 4319 CharData_Init(&storage); 4320 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4321 XML_SetElementDeclHandler(g_parser, element_decl_suspender); 4322 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 4323 XML_SetUserData(g_parser, &storage); 4324 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) 4325 != XML_STATUS_SUSPENDED) 4326 xml_failure(g_parser); 4327 CharData_CheckXMLChars(&storage, XCS("")); 4328 if (XML_ResumeParser(g_parser) != XML_STATUS_OK) 4329 xml_failure(g_parser); 4330 CharData_CheckXMLChars(&storage, expected); 4331 } 4332 END_TEST 4333 4334 /* Test attempting to use parser after an error is faulted */ 4335 START_TEST(test_restart_on_error) { 4336 const char *text = "<$doc><doc></doc>"; 4337 4338 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4339 != XML_STATUS_ERROR) 4340 fail("Invalid tag name not faulted"); 4341 if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN) 4342 xml_failure(g_parser); 4343 if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR) 4344 fail("Restarting invalid parse not faulted"); 4345 if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN) 4346 xml_failure(g_parser); 4347 } 4348 END_TEST 4349 4350 /* Test that angle brackets in an attribute default value are faulted */ 4351 START_TEST(test_reject_lt_in_attribute_value) { 4352 const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '<bar>'>]>\n" 4353 "<doc></doc>"; 4354 4355 expect_failure(text, XML_ERROR_INVALID_TOKEN, 4356 "Bad attribute default not faulted"); 4357 } 4358 END_TEST 4359 4360 START_TEST(test_reject_unfinished_param_in_att_value) { 4361 const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '&foo'>]>\n" 4362 "<doc></doc>"; 4363 4364 expect_failure(text, XML_ERROR_INVALID_TOKEN, 4365 "Bad attribute default not faulted"); 4366 } 4367 END_TEST 4368 4369 START_TEST(test_trailing_cr_in_att_value) { 4370 const char *text = "<doc a='value\r'/>"; 4371 4372 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4373 == XML_STATUS_ERROR) 4374 xml_failure(g_parser); 4375 } 4376 END_TEST 4377 4378 /* Try parsing a general entity within a parameter entity in a 4379 * standalone internal DTD. Covers a corner case in the parser. 4380 */ 4381 START_TEST(test_standalone_internal_entity) { 4382 const char *text = "<?xml version='1.0' standalone='yes' ?>\n" 4383 "<!DOCTYPE doc [\n" 4384 " <!ELEMENT doc (#PCDATA)>\n" 4385 " <!ENTITY % pe '<!ATTLIST doc att2 CDATA \"≥\">'>\n" 4386 " <!ENTITY ge 'AttDefaultValue'>\n" 4387 " %pe;\n" 4388 "]>\n" 4389 "<doc att2='any'/>"; 4390 4391 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4392 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4393 == XML_STATUS_ERROR) 4394 xml_failure(g_parser); 4395 } 4396 END_TEST 4397 4398 /* Test that a reference to an unknown external entity is skipped */ 4399 START_TEST(test_skipped_external_entity) { 4400 const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n" 4401 "<doc></doc>\n"; 4402 ExtTest test_data = {"<!ELEMENT doc EMPTY>\n" 4403 "<!ENTITY % e2 '%e1;'>\n", 4404 NULL, NULL}; 4405 4406 XML_SetUserData(g_parser, &test_data); 4407 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4408 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 4409 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4410 == XML_STATUS_ERROR) 4411 xml_failure(g_parser); 4412 } 4413 END_TEST 4414 4415 START_TEST(test_scaff_index_shared_across_external_entity_parser) { 4416 const char text[] 4417 = "<!DOCTYPE doc [\n" 4418 "<!ELEMENT a " 4419 "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((b))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>\n" 4420 "<!ENTITY % e SYSTEM 'ext'>\n" 4421 "%e;\n" 4422 "<!ELEMENT c " 4423 "(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((d)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>\n" 4424 "]>\n" 4425 "<doc/>"; 4426 ExtOption options[] 4427 = {{XCS("ext"), 4428 "<!ELEMENT x " 4429 "((((((((((((((((((((((((((((((((y))))))))))))))))))))))))))))))))>"}, 4430 {NULL, NULL}}; 4431 4432 XML_Parser parser = XML_ParserCreate(NULL); 4433 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4434 XML_SetUserData(parser, options); 4435 XML_SetExternalEntityRefHandler(parser, external_entity_optioner); 4436 XML_SetElementDeclHandler(parser, dummy_element_decl_handler); 4437 4438 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 4439 == XML_STATUS_ERROR) 4440 xml_failure(parser); 4441 4442 XML_ParserFree(parser); 4443 } 4444 END_TEST 4445 4446 /* Test a different form of unknown external entity */ 4447 START_TEST(test_skipped_null_loaded_ext_entity) { 4448 const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n" 4449 "<doc />"; 4450 ExtHdlrData test_data 4451 = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n" 4452 "<!ENTITY % pe2 '%pe1;'>\n" 4453 "%pe2;\n", 4454 external_entity_null_loader, NULL}; 4455 4456 XML_SetUserData(g_parser, &test_data); 4457 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4458 XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader); 4459 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4460 == XML_STATUS_ERROR) 4461 xml_failure(g_parser); 4462 } 4463 END_TEST 4464 4465 START_TEST(test_skipped_unloaded_ext_entity) { 4466 const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n" 4467 "<doc />"; 4468 ExtHdlrData test_data 4469 = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n" 4470 "<!ENTITY % pe2 '%pe1;'>\n" 4471 "%pe2;\n", 4472 NULL, NULL}; 4473 4474 XML_SetUserData(g_parser, &test_data); 4475 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4476 XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader); 4477 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4478 == XML_STATUS_ERROR) 4479 xml_failure(g_parser); 4480 } 4481 END_TEST 4482 4483 /* Test that a parameter entity value ending with a carriage return 4484 * has it translated internally into a newline. 4485 */ 4486 START_TEST(test_param_entity_with_trailing_cr) { 4487 #define PARAM_ENTITY_NAME "pe" 4488 #define PARAM_ENTITY_CORE_VALUE "<!ATTLIST doc att CDATA \"default\">" 4489 const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n" 4490 "<doc/>"; 4491 ExtTest test_data 4492 = {"<!ENTITY % " PARAM_ENTITY_NAME " '" PARAM_ENTITY_CORE_VALUE "\r'>\n" 4493 "%" PARAM_ENTITY_NAME ";\n", 4494 NULL, NULL}; 4495 4496 XML_SetUserData(g_parser, &test_data); 4497 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 4498 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); 4499 XML_SetEntityDeclHandler(g_parser, param_entity_match_handler); 4500 param_entity_match_init(XCS(PARAM_ENTITY_NAME), 4501 XCS(PARAM_ENTITY_CORE_VALUE) XCS("\n")); 4502 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4503 == XML_STATUS_ERROR) 4504 xml_failure(g_parser); 4505 int entity_match_flag = get_param_entity_match_flag(); 4506 if (entity_match_flag == ENTITY_MATCH_FAIL) 4507 fail("Parameter entity CR->NEWLINE conversion failed"); 4508 else if (entity_match_flag == ENTITY_MATCH_NOT_FOUND) 4509 fail("Parameter entity not parsed"); 4510 } 4511 #undef PARAM_ENTITY_NAME 4512 #undef PARAM_ENTITY_CORE_VALUE 4513 END_TEST 4514 4515 START_TEST(test_invalid_character_entity) { 4516 const char *text = "<!DOCTYPE doc [\n" 4517 " <!ENTITY entity '�'>\n" 4518 "]>\n" 4519 "<doc>&entity;</doc>"; 4520 4521 expect_failure(text, XML_ERROR_BAD_CHAR_REF, 4522 "Out of range character reference not faulted"); 4523 } 4524 END_TEST 4525 4526 START_TEST(test_invalid_character_entity_2) { 4527 const char *text = "<!DOCTYPE doc [\n" 4528 " <!ENTITY entity '&#xg0;'>\n" 4529 "]>\n" 4530 "<doc>&entity;</doc>"; 4531 4532 expect_failure(text, XML_ERROR_INVALID_TOKEN, 4533 "Out of range character reference not faulted"); 4534 } 4535 END_TEST 4536 4537 START_TEST(test_invalid_character_entity_3) { 4538 const char text[] = 4539 /* <!DOCTYPE doc [\n */ 4540 "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n" 4541 /* U+0E04 = KHO KHWAI 4542 * U+0E08 = CHO CHAN */ 4543 /* <!ENTITY entity '&\u0e04\u0e08;'>\n */ 4544 "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0e\0n\0t\0i\0t\0y\0 " 4545 "\0'\0&\x0e\x04\x0e\x08\0;\0'\0>\0\n" 4546 /* ]>\n */ 4547 "\0]\0>\0\n" 4548 /* <doc>&entity;</doc> */ 4549 "\0<\0d\0o\0c\0>\0&\0e\0n\0t\0i\0t\0y\0;\0<\0/\0d\0o\0c\0>"; 4550 4551 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 4552 != XML_STATUS_ERROR) 4553 fail("Invalid start of entity name not faulted"); 4554 if (XML_GetErrorCode(g_parser) != XML_ERROR_UNDEFINED_ENTITY) 4555 xml_failure(g_parser); 4556 } 4557 END_TEST 4558 4559 START_TEST(test_invalid_character_entity_4) { 4560 const char *text = "<!DOCTYPE doc [\n" 4561 " <!ENTITY entity '�'>\n" /* = � */ 4562 "]>\n" 4563 "<doc>&entity;</doc>"; 4564 4565 expect_failure(text, XML_ERROR_BAD_CHAR_REF, 4566 "Out of range character reference not faulted"); 4567 } 4568 END_TEST 4569 4570 /* Test that processing instructions are picked up by a default handler */ 4571 START_TEST(test_pi_handled_in_default) { 4572 const char *text = "<?test processing instruction?>\n<doc/>"; 4573 const XML_Char *expected = XCS("<?test processing instruction?>\n<doc/>"); 4574 CharData storage; 4575 4576 CharData_Init(&storage); 4577 XML_SetDefaultHandler(g_parser, accumulate_characters); 4578 XML_SetUserData(g_parser, &storage); 4579 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4580 == XML_STATUS_ERROR) 4581 xml_failure(g_parser); 4582 CharData_CheckXMLChars(&storage, expected); 4583 } 4584 END_TEST 4585 4586 /* Test that comments are picked up by a default handler */ 4587 START_TEST(test_comment_handled_in_default) { 4588 const char *text = "<!-- This is a comment -->\n<doc/>"; 4589 const XML_Char *expected = XCS("<!-- This is a comment -->\n<doc/>"); 4590 CharData storage; 4591 4592 CharData_Init(&storage); 4593 XML_SetDefaultHandler(g_parser, accumulate_characters); 4594 XML_SetUserData(g_parser, &storage); 4595 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4596 == XML_STATUS_ERROR) 4597 xml_failure(g_parser); 4598 CharData_CheckXMLChars(&storage, expected); 4599 } 4600 END_TEST 4601 4602 /* Test PIs that look almost but not quite like XML declarations */ 4603 START_TEST(test_pi_yml) { 4604 const char *text = "<?yml something like data?><doc/>"; 4605 const XML_Char *expected = XCS("yml: something like data\n"); 4606 CharData storage; 4607 4608 CharData_Init(&storage); 4609 XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters); 4610 XML_SetUserData(g_parser, &storage); 4611 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4612 == XML_STATUS_ERROR) 4613 xml_failure(g_parser); 4614 CharData_CheckXMLChars(&storage, expected); 4615 } 4616 END_TEST 4617 4618 START_TEST(test_pi_xnl) { 4619 const char *text = "<?xnl nothing like data?><doc/>"; 4620 const XML_Char *expected = XCS("xnl: nothing like data\n"); 4621 CharData storage; 4622 4623 CharData_Init(&storage); 4624 XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters); 4625 XML_SetUserData(g_parser, &storage); 4626 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4627 == XML_STATUS_ERROR) 4628 xml_failure(g_parser); 4629 CharData_CheckXMLChars(&storage, expected); 4630 } 4631 END_TEST 4632 4633 START_TEST(test_pi_xmm) { 4634 const char *text = "<?xmm everything like data?><doc/>"; 4635 const XML_Char *expected = XCS("xmm: everything like data\n"); 4636 CharData storage; 4637 4638 CharData_Init(&storage); 4639 XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters); 4640 XML_SetUserData(g_parser, &storage); 4641 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4642 == XML_STATUS_ERROR) 4643 xml_failure(g_parser); 4644 CharData_CheckXMLChars(&storage, expected); 4645 } 4646 END_TEST 4647 4648 START_TEST(test_utf16_pi) { 4649 const char text[] = 4650 /* <?{KHO KHWAI}{CHO CHAN}?> 4651 * where {KHO KHWAI} = U+0E04 4652 * and {CHO CHAN} = U+0E08 4653 */ 4654 "<\0?\0\x04\x0e\x08\x0e?\0>\0" 4655 /* <q/> */ 4656 "<\0q\0/\0>\0"; 4657 #ifdef XML_UNICODE 4658 const XML_Char *expected = XCS("\x0e04\x0e08: \n"); 4659 #else 4660 const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n"); 4661 #endif 4662 CharData storage; 4663 4664 CharData_Init(&storage); 4665 XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters); 4666 XML_SetUserData(g_parser, &storage); 4667 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 4668 == XML_STATUS_ERROR) 4669 xml_failure(g_parser); 4670 CharData_CheckXMLChars(&storage, expected); 4671 } 4672 END_TEST 4673 4674 START_TEST(test_utf16_be_pi) { 4675 const char text[] = 4676 /* <?{KHO KHWAI}{CHO CHAN}?> 4677 * where {KHO KHWAI} = U+0E04 4678 * and {CHO CHAN} = U+0E08 4679 */ 4680 "\0<\0?\x0e\x04\x0e\x08\0?\0>" 4681 /* <q/> */ 4682 "\0<\0q\0/\0>"; 4683 #ifdef XML_UNICODE 4684 const XML_Char *expected = XCS("\x0e04\x0e08: \n"); 4685 #else 4686 const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n"); 4687 #endif 4688 CharData storage; 4689 4690 CharData_Init(&storage); 4691 XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters); 4692 XML_SetUserData(g_parser, &storage); 4693 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 4694 == XML_STATUS_ERROR) 4695 xml_failure(g_parser); 4696 CharData_CheckXMLChars(&storage, expected); 4697 } 4698 END_TEST 4699 4700 /* Test that comments can be picked up and translated */ 4701 START_TEST(test_utf16_be_comment) { 4702 const char text[] = 4703 /* <!-- Comment A --> */ 4704 "\0<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0A\0 \0-\0-\0>\0\n" 4705 /* <doc/> */ 4706 "\0<\0d\0o\0c\0/\0>"; 4707 const XML_Char *expected = XCS(" Comment A "); 4708 CharData storage; 4709 4710 CharData_Init(&storage); 4711 XML_SetCommentHandler(g_parser, accumulate_comment); 4712 XML_SetUserData(g_parser, &storage); 4713 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 4714 == XML_STATUS_ERROR) 4715 xml_failure(g_parser); 4716 CharData_CheckXMLChars(&storage, expected); 4717 } 4718 END_TEST 4719 4720 START_TEST(test_utf16_le_comment) { 4721 const char text[] = 4722 /* <!-- Comment B --> */ 4723 "<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0B\0 \0-\0-\0>\0\n\0" 4724 /* <doc/> */ 4725 "<\0d\0o\0c\0/\0>\0"; 4726 const XML_Char *expected = XCS(" Comment B "); 4727 CharData storage; 4728 4729 CharData_Init(&storage); 4730 XML_SetCommentHandler(g_parser, accumulate_comment); 4731 XML_SetUserData(g_parser, &storage); 4732 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 4733 == XML_STATUS_ERROR) 4734 xml_failure(g_parser); 4735 CharData_CheckXMLChars(&storage, expected); 4736 } 4737 END_TEST 4738 4739 /* Test that the unknown encoding handler with map entries that expect 4740 * conversion but no conversion function is faulted 4741 */ 4742 START_TEST(test_missing_encoding_conversion_fn) { 4743 const char *text = "<?xml version='1.0' encoding='no-conv'?>\n" 4744 "<doc>\x81</doc>"; 4745 4746 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4747 /* MiscEncodingHandler sets up an encoding with every top-bit-set 4748 * character introducing a two-byte sequence. For this, it 4749 * requires a convert function. The above function call doesn't 4750 * pass one through, so when BadEncodingHandler actually gets 4751 * called it should supply an invalid encoding. 4752 */ 4753 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING, 4754 "Encoding with missing convert() not faulted"); 4755 } 4756 END_TEST 4757 4758 START_TEST(test_failing_encoding_conversion_fn) { 4759 const char *text = "<?xml version='1.0' encoding='failing-conv'?>\n" 4760 "<doc>\x81</doc>"; 4761 4762 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4763 /* BadEncodingHandler sets up an encoding with every top-bit-set 4764 * character introducing a two-byte sequence. For this, it 4765 * requires a convert function. The above function call passes 4766 * one that insists all possible sequences are invalid anyway. 4767 */ 4768 expect_failure(text, XML_ERROR_INVALID_TOKEN, 4769 "Encoding with failing convert() not faulted"); 4770 } 4771 END_TEST 4772 4773 /* Test unknown encoding conversions */ 4774 START_TEST(test_unknown_encoding_success) { 4775 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n" 4776 /* Equivalent to <eoc>Hello, world</eoc> */ 4777 "<\x81\x64\x80oc>Hello, world</\x81\x64\x80oc>"; 4778 4779 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4780 run_character_check(text, XCS("Hello, world")); 4781 } 4782 END_TEST 4783 4784 /* Test bad name character in unknown encoding */ 4785 START_TEST(test_unknown_encoding_bad_name) { 4786 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n" 4787 "<\xff\x64oc>Hello, world</\xff\x64oc>"; 4788 4789 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4790 expect_failure(text, XML_ERROR_INVALID_TOKEN, 4791 "Bad name start in unknown encoding not faulted"); 4792 } 4793 END_TEST 4794 4795 /* Test bad mid-name character in unknown encoding */ 4796 START_TEST(test_unknown_encoding_bad_name_2) { 4797 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n" 4798 "<d\xffoc>Hello, world</d\xffoc>"; 4799 4800 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4801 expect_failure(text, XML_ERROR_INVALID_TOKEN, 4802 "Bad name in unknown encoding not faulted"); 4803 } 4804 END_TEST 4805 4806 /* Test element name that is long enough to fill the conversion buffer 4807 * in an unknown encoding, finishing with an encoded character. 4808 */ 4809 START_TEST(test_unknown_encoding_long_name_1) { 4810 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n" 4811 "<abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>" 4812 "Hi" 4813 "</abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>"; 4814 const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop"); 4815 CharData storage; 4816 4817 CharData_Init(&storage); 4818 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4819 XML_SetStartElementHandler(g_parser, record_element_start_handler); 4820 XML_SetUserData(g_parser, &storage); 4821 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4822 == XML_STATUS_ERROR) 4823 xml_failure(g_parser); 4824 CharData_CheckXMLChars(&storage, expected); 4825 } 4826 END_TEST 4827 4828 /* Test element name that is long enough to fill the conversion buffer 4829 * in an unknown encoding, finishing with an simple character. 4830 */ 4831 START_TEST(test_unknown_encoding_long_name_2) { 4832 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n" 4833 "<abcdefghabcdefghabcdefghijklmnop>" 4834 "Hi" 4835 "</abcdefghabcdefghabcdefghijklmnop>"; 4836 const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop"); 4837 CharData storage; 4838 4839 CharData_Init(&storage); 4840 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4841 XML_SetStartElementHandler(g_parser, record_element_start_handler); 4842 XML_SetUserData(g_parser, &storage); 4843 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4844 == XML_STATUS_ERROR) 4845 xml_failure(g_parser); 4846 CharData_CheckXMLChars(&storage, expected); 4847 } 4848 END_TEST 4849 4850 START_TEST(test_invalid_unknown_encoding) { 4851 const char *text = "<?xml version='1.0' encoding='invalid-9'?>\n" 4852 "<doc>Hello world</doc>"; 4853 4854 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4855 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING, 4856 "Invalid unknown encoding not faulted"); 4857 } 4858 END_TEST 4859 4860 START_TEST(test_unknown_ascii_encoding_ok) { 4861 const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n" 4862 "<doc>Hello, world</doc>"; 4863 4864 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4865 run_character_check(text, XCS("Hello, world")); 4866 } 4867 END_TEST 4868 4869 START_TEST(test_unknown_ascii_encoding_fail) { 4870 const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n" 4871 "<doc>Hello, \x80 world</doc>"; 4872 4873 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4874 expect_failure(text, XML_ERROR_INVALID_TOKEN, 4875 "Invalid character not faulted"); 4876 } 4877 END_TEST 4878 4879 START_TEST(test_unknown_encoding_invalid_length) { 4880 const char *text = "<?xml version='1.0' encoding='invalid-len'?>\n" 4881 "<doc>Hello, world</doc>"; 4882 4883 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4884 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING, 4885 "Invalid unknown encoding not faulted"); 4886 } 4887 END_TEST 4888 4889 START_TEST(test_unknown_encoding_invalid_topbit) { 4890 const char *text = "<?xml version='1.0' encoding='invalid-a'?>\n" 4891 "<doc>Hello, world</doc>"; 4892 4893 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4894 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING, 4895 "Invalid unknown encoding not faulted"); 4896 } 4897 END_TEST 4898 4899 START_TEST(test_unknown_encoding_invalid_surrogate) { 4900 const char *text = "<?xml version='1.0' encoding='invalid-surrogate'?>\n" 4901 "<doc>Hello, \x82 world</doc>"; 4902 4903 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4904 expect_failure(text, XML_ERROR_INVALID_TOKEN, 4905 "Invalid unknown encoding not faulted"); 4906 } 4907 END_TEST 4908 4909 START_TEST(test_unknown_encoding_invalid_high) { 4910 const char *text = "<?xml version='1.0' encoding='invalid-high'?>\n" 4911 "<doc>Hello, world</doc>"; 4912 4913 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4914 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING, 4915 "Invalid unknown encoding not faulted"); 4916 } 4917 END_TEST 4918 4919 START_TEST(test_unknown_encoding_invalid_attr_value) { 4920 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n" 4921 "<doc attr='\xff\x30'/>"; 4922 4923 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 4924 expect_failure(text, XML_ERROR_INVALID_TOKEN, 4925 "Invalid attribute valid not faulted"); 4926 } 4927 END_TEST 4928 4929 START_TEST(test_unknown_encoding_user_data_primary) { 4930 // This test is based on ideas contributed by Artiphishell Inc. 4931 const char *const text = "<?xml version='1.0' encoding='x-unk'?>\n" 4932 "<root />\n"; 4933 XML_Parser parser = XML_ParserCreate(NULL); 4934 XML_SetUnknownEncodingHandler(parser, 4935 user_data_checking_unknown_encoding_handler, 4936 (void *)(intptr_t)0xC0FFEE); 4937 4938 assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 4939 == XML_STATUS_OK); 4940 4941 XML_ParserFree(parser); 4942 } 4943 END_TEST 4944 4945 START_TEST(test_unknown_encoding_user_data_secondary) { 4946 // This test is based on ideas contributed by Artiphishell Inc. 4947 const char *const text_main = "<!DOCTYPE r [\n" 4948 " <!ENTITY ext SYSTEM 'ext.ent'>\n" 4949 "]>\n" 4950 "<r>&ext;</r>\n"; 4951 const char *const text_external = "<?xml version='1.0' encoding='x-unk'?>\n" 4952 "<e>data</e>"; 4953 ExtTest2 test_data = {text_external, (int)strlen(text_external), NULL, NULL}; 4954 XML_Parser parser = XML_ParserCreate(NULL); 4955 XML_SetExternalEntityRefHandler(parser, external_entity_loader2); 4956 XML_SetUnknownEncodingHandler(parser, 4957 user_data_checking_unknown_encoding_handler, 4958 (void *)(intptr_t)0xC0FFEE); 4959 XML_SetUserData(parser, &test_data); 4960 4961 assert_true(_XML_Parse_SINGLE_BYTES(parser, text_main, (int)strlen(text_main), 4962 XML_TRUE) 4963 == XML_STATUS_OK); 4964 4965 XML_ParserFree(parser); 4966 } 4967 END_TEST 4968 4969 /* Test an external entity parser set to use latin-1 detects UTF-16 4970 * BOMs correctly. 4971 */ 4972 /* Test that UTF-16 BOM does not select UTF-16 given explicit encoding */ 4973 START_TEST(test_ext_entity_latin1_utf16le_bom) { 4974 const char *text = "<!DOCTYPE doc [\n" 4975 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 4976 "]>\n" 4977 "<doc>&en;</doc>"; 4978 ExtTest2 test_data 4979 = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */ 4980 /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn, 4981 * 0x4c = L and 0x20 is a space 4982 */ 4983 "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL}; 4984 #ifdef XML_UNICODE 4985 const XML_Char *expected = XCS("\x00ff\x00feL "); 4986 #else 4987 /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */ 4988 const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL "); 4989 #endif 4990 CharData storage; 4991 4992 CharData_Init(&storage); 4993 test_data.storage = &storage; 4994 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2); 4995 XML_SetUserData(g_parser, &test_data); 4996 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters); 4997 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 4998 == XML_STATUS_ERROR) 4999 xml_failure(g_parser); 5000 CharData_CheckXMLChars(&storage, expected); 5001 } 5002 END_TEST 5003 5004 START_TEST(test_ext_entity_latin1_utf16be_bom) { 5005 const char *text = "<!DOCTYPE doc [\n" 5006 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 5007 "]>\n" 5008 "<doc>&en;</doc>"; 5009 ExtTest2 test_data 5010 = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */ 5011 /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn, 5012 * 0x4c = L and 0x20 is a space 5013 */ 5014 "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL}; 5015 #ifdef XML_UNICODE 5016 const XML_Char *expected = XCS("\x00fe\x00ff L"); 5017 #else 5018 /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */ 5019 const XML_Char *expected = XCS("\xc3\xbe\xc3\xbf L"); 5020 #endif 5021 CharData storage; 5022 5023 CharData_Init(&storage); 5024 test_data.storage = &storage; 5025 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2); 5026 XML_SetUserData(g_parser, &test_data); 5027 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters); 5028 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 5029 == XML_STATUS_ERROR) 5030 xml_failure(g_parser); 5031 CharData_CheckXMLChars(&storage, expected); 5032 } 5033 END_TEST 5034 5035 /* Parsing the full buffer rather than a byte at a time makes a 5036 * difference to the encoding scanning code, so repeat the above tests 5037 * without breaking them down by byte. 5038 */ 5039 START_TEST(test_ext_entity_latin1_utf16le_bom2) { 5040 const char *text = "<!DOCTYPE doc [\n" 5041 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 5042 "]>\n" 5043 "<doc>&en;</doc>"; 5044 ExtTest2 test_data 5045 = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */ 5046 /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn, 5047 * 0x4c = L and 0x20 is a space 5048 */ 5049 "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL}; 5050 #ifdef XML_UNICODE 5051 const XML_Char *expected = XCS("\x00ff\x00feL "); 5052 #else 5053 /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */ 5054 const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL "); 5055 #endif 5056 CharData storage; 5057 5058 CharData_Init(&storage); 5059 test_data.storage = &storage; 5060 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2); 5061 XML_SetUserData(g_parser, &test_data); 5062 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters); 5063 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 5064 == XML_STATUS_ERROR) 5065 xml_failure(g_parser); 5066 CharData_CheckXMLChars(&storage, expected); 5067 } 5068 END_TEST 5069 5070 START_TEST(test_ext_entity_latin1_utf16be_bom2) { 5071 const char *text = "<!DOCTYPE doc [\n" 5072 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 5073 "]>\n" 5074 "<doc>&en;</doc>"; 5075 ExtTest2 test_data 5076 = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */ 5077 /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn, 5078 * 0x4c = L and 0x20 is a space 5079 */ 5080 "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL}; 5081 #ifdef XML_UNICODE 5082 const XML_Char *expected = XCS("\x00fe\x00ff L"); 5083 #else 5084 /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */ 5085 const XML_Char *expected = "\xc3\xbe\xc3\xbf L"; 5086 #endif 5087 CharData storage; 5088 5089 CharData_Init(&storage); 5090 test_data.storage = &storage; 5091 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2); 5092 XML_SetUserData(g_parser, &test_data); 5093 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters); 5094 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 5095 == XML_STATUS_ERROR) 5096 xml_failure(g_parser); 5097 CharData_CheckXMLChars(&storage, expected); 5098 } 5099 END_TEST 5100 5101 /* Test little-endian UTF-16 given an explicit big-endian encoding */ 5102 START_TEST(test_ext_entity_utf16_be) { 5103 const char *text = "<!DOCTYPE doc [\n" 5104 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 5105 "]>\n" 5106 "<doc>&en;</doc>"; 5107 ExtTest2 test_data = {"<\0e\0/\0>\0", 8, XCS("utf-16be"), NULL}; 5108 #ifdef XML_UNICODE 5109 const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00"); 5110 #else 5111 const XML_Char *expected = XCS("\xe3\xb0\x80" /* U+3C00 */ 5112 "\xe6\x94\x80" /* U+6500 */ 5113 "\xe2\xbc\x80" /* U+2F00 */ 5114 "\xe3\xb8\x80"); /* U+3E00 */ 5115 #endif 5116 CharData storage; 5117 5118 CharData_Init(&storage); 5119 test_data.storage = &storage; 5120 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2); 5121 XML_SetUserData(g_parser, &test_data); 5122 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters); 5123 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 5124 == XML_STATUS_ERROR) 5125 xml_failure(g_parser); 5126 CharData_CheckXMLChars(&storage, expected); 5127 } 5128 END_TEST 5129 5130 /* Test big-endian UTF-16 given an explicit little-endian encoding */ 5131 START_TEST(test_ext_entity_utf16_le) { 5132 const char *text = "<!DOCTYPE doc [\n" 5133 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 5134 "]>\n" 5135 "<doc>&en;</doc>"; 5136 ExtTest2 test_data = {"\0<\0e\0/\0>", 8, XCS("utf-16le"), NULL}; 5137 #ifdef XML_UNICODE 5138 const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00"); 5139 #else 5140 const XML_Char *expected = XCS("\xe3\xb0\x80" /* U+3C00 */ 5141 "\xe6\x94\x80" /* U+6500 */ 5142 "\xe2\xbc\x80" /* U+2F00 */ 5143 "\xe3\xb8\x80"); /* U+3E00 */ 5144 #endif 5145 CharData storage; 5146 5147 CharData_Init(&storage); 5148 test_data.storage = &storage; 5149 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2); 5150 XML_SetUserData(g_parser, &test_data); 5151 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters); 5152 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 5153 == XML_STATUS_ERROR) 5154 xml_failure(g_parser); 5155 CharData_CheckXMLChars(&storage, expected); 5156 } 5157 END_TEST 5158 5159 /* Test little-endian UTF-16 given no explicit encoding. 5160 * The existing default encoding (UTF-8) is assumed to hold without a 5161 * BOM to contradict it, so the entity value will in fact provoke an 5162 * error because 0x00 is not a valid XML character. We parse the 5163 * whole buffer in one go rather than feeding it in byte by byte to 5164 * exercise different code paths in the initial scanning routines. 5165 */ 5166 START_TEST(test_ext_entity_utf16_unknown) { 5167 const char *text = "<!DOCTYPE doc [\n" 5168 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 5169 "]>\n" 5170 "<doc>&en;</doc>"; 5171 ExtFaults2 test_data 5172 = {"a\0b\0c\0", 6, "Invalid character in entity not faulted", NULL, 5173 XML_ERROR_INVALID_TOKEN}; 5174 5175 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter2); 5176 XML_SetUserData(g_parser, &test_data); 5177 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 5178 "Invalid character should not have been accepted"); 5179 } 5180 END_TEST 5181 5182 /* Test not-quite-UTF-8 BOM (0xEF 0xBB 0xBF) */ 5183 START_TEST(test_ext_entity_utf8_non_bom) { 5184 const char *text = "<!DOCTYPE doc [\n" 5185 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n" 5186 "]>\n" 5187 "<doc>&en;</doc>"; 5188 ExtTest2 test_data 5189 = {"\xef\xbb\x80", /* Arabic letter DAD medial form, U+FEC0 */ 5190 3, NULL, NULL}; 5191 #ifdef XML_UNICODE 5192 const XML_Char *expected = XCS("\xfec0"); 5193 #else 5194 const XML_Char *expected = XCS("\xef\xbb\x80"); 5195 #endif 5196 CharData storage; 5197 5198 CharData_Init(&storage); 5199 test_data.storage = &storage; 5200 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2); 5201 XML_SetUserData(g_parser, &test_data); 5202 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters); 5203 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 5204 == XML_STATUS_ERROR) 5205 xml_failure(g_parser); 5206 CharData_CheckXMLChars(&storage, expected); 5207 } 5208 END_TEST 5209 5210 /* Test that UTF-8 in a CDATA section is correctly passed through */ 5211 START_TEST(test_utf8_in_cdata_section) { 5212 const char *text = "<doc><![CDATA[one \xc3\xa9 two]]></doc>"; 5213 #ifdef XML_UNICODE 5214 const XML_Char *expected = XCS("one \x00e9 two"); 5215 #else 5216 const XML_Char *expected = XCS("one \xc3\xa9 two"); 5217 #endif 5218 5219 run_character_check(text, expected); 5220 } 5221 END_TEST 5222 5223 /* Test that little-endian UTF-16 in a CDATA section is handled */ 5224 START_TEST(test_utf8_in_cdata_section_2) { 5225 const char *text = "<doc><![CDATA[\xc3\xa9]\xc3\xa9two]]></doc>"; 5226 #ifdef XML_UNICODE 5227 const XML_Char *expected = XCS("\x00e9]\x00e9two"); 5228 #else 5229 const XML_Char *expected = XCS("\xc3\xa9]\xc3\xa9two"); 5230 #endif 5231 5232 run_character_check(text, expected); 5233 } 5234 END_TEST 5235 5236 START_TEST(test_utf8_in_start_tags) { 5237 struct test_case { 5238 bool goodName; 5239 bool goodNameStart; 5240 const char *tagName; 5241 }; 5242 5243 // The idea with the tests below is this: 5244 // We want to cover 1-, 2- and 3-byte sequences, 4-byte sequences 5245 // go to isNever and are hence not a concern. 5246 // 5247 // We start with a character that is a valid name character 5248 // (or even name-start character, see XML 1.0r4 spec) and then we flip 5249 // single bits at places where (1) the result leaves the UTF-8 encoding space 5250 // and (2) we stay in the same n-byte sequence family. 5251 // 5252 // The flipped bits are highlighted in angle brackets in comments, 5253 // e.g. "[<1>011 1001]" means we had [0011 1001] but we now flipped 5254 // the most significant bit to 1 to leave UTF-8 encoding space. 5255 struct test_case cases[] = { 5256 // 1-byte UTF-8: [0xxx xxxx] 5257 {true, true, "\x3A"}, // [0011 1010] = ASCII colon ':' 5258 {false, false, "\xBA"}, // [<1>011 1010] 5259 {true, false, "\x39"}, // [0011 1001] = ASCII nine '9' 5260 {false, false, "\xB9"}, // [<1>011 1001] 5261 5262 // 2-byte UTF-8: [110x xxxx] [10xx xxxx] 5263 {true, true, "\xDB\xA5"}, // [1101 1011] [1010 0101] = 5264 // Arabic small waw U+06E5 5265 {false, false, "\x9B\xA5"}, // [1<0>01 1011] [1010 0101] 5266 {false, false, "\xDB\x25"}, // [1101 1011] [<0>010 0101] 5267 {false, false, "\xDB\xE5"}, // [1101 1011] [1<1>10 0101] 5268 {true, false, "\xCC\x81"}, // [1100 1100] [1000 0001] = 5269 // combining char U+0301 5270 {false, false, "\x8C\x81"}, // [1<0>00 1100] [1000 0001] 5271 {false, false, "\xCC\x01"}, // [1100 1100] [<0>000 0001] 5272 {false, false, "\xCC\xC1"}, // [1100 1100] [1<1>00 0001] 5273 5274 // 3-byte UTF-8: [1110 xxxx] [10xx xxxx] [10xxxxxx] 5275 {true, true, "\xE0\xA4\x85"}, // [1110 0000] [1010 0100] [1000 0101] = 5276 // Devanagari Letter A U+0905 5277 {false, false, "\xA0\xA4\x85"}, // [1<0>10 0000] [1010 0100] [1000 0101] 5278 {false, false, "\xE0\x24\x85"}, // [1110 0000] [<0>010 0100] [1000 0101] 5279 {false, false, "\xE0\xE4\x85"}, // [1110 0000] [1<1>10 0100] [1000 0101] 5280 {false, false, "\xE0\xA4\x05"}, // [1110 0000] [1010 0100] [<0>000 0101] 5281 {false, false, "\xE0\xA4\xC5"}, // [1110 0000] [1010 0100] [1<1>00 0101] 5282 {true, false, "\xE0\xA4\x81"}, // [1110 0000] [1010 0100] [1000 0001] = 5283 // combining char U+0901 5284 {false, false, "\xA0\xA4\x81"}, // [1<0>10 0000] [1010 0100] [1000 0001] 5285 {false, false, "\xE0\x24\x81"}, // [1110 0000] [<0>010 0100] [1000 0001] 5286 {false, false, "\xE0\xE4\x81"}, // [1110 0000] [1<1>10 0100] [1000 0001] 5287 {false, false, "\xE0\xA4\x01"}, // [1110 0000] [1010 0100] [<0>000 0001] 5288 {false, false, "\xE0\xA4\xC1"}, // [1110 0000] [1010 0100] [1<1>00 0001] 5289 }; 5290 const bool atNameStart[] = {true, false}; 5291 5292 size_t i = 0; 5293 char doc[1024]; 5294 size_t failCount = 0; 5295 5296 // we need all the bytes to be parsed, but we don't want the errors that can 5297 // trigger on isFinal=XML_TRUE, so we skip the test if the heuristic is on. 5298 if (g_reparseDeferralEnabledDefault) { 5299 return; 5300 } 5301 5302 for (; i < sizeof(cases) / sizeof(cases[0]); i++) { 5303 size_t j = 0; 5304 for (; j < sizeof(atNameStart) / sizeof(atNameStart[0]); j++) { 5305 const bool expectedSuccess 5306 = atNameStart[j] ? cases[i].goodNameStart : cases[i].goodName; 5307 snprintf(doc, sizeof(doc), "<%s%s><!--", atNameStart[j] ? "" : "a", 5308 cases[i].tagName); 5309 XML_Parser parser = XML_ParserCreate(NULL); 5310 5311 const enum XML_Status status = _XML_Parse_SINGLE_BYTES( 5312 parser, doc, (int)strlen(doc), /*isFinal=*/XML_FALSE); 5313 5314 bool success = true; 5315 if ((status == XML_STATUS_OK) != expectedSuccess) { 5316 success = false; 5317 } 5318 if ((status == XML_STATUS_ERROR) 5319 && (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)) { 5320 success = false; 5321 } 5322 5323 if (! success) { 5324 fprintf( 5325 stderr, 5326 "FAIL case %2u (%sat name start, %u-byte sequence, error code %d)\n", 5327 (unsigned)i + 1u, atNameStart[j] ? " " : "not ", 5328 (unsigned)strlen(cases[i].tagName), XML_GetErrorCode(parser)); 5329 failCount++; 5330 } 5331 5332 XML_ParserFree(parser); 5333 } 5334 } 5335 5336 if (failCount > 0) { 5337 fail("UTF-8 regression detected"); 5338 } 5339 } 5340 END_TEST 5341 5342 /* Test trailing spaces in elements are accepted */ 5343 START_TEST(test_trailing_spaces_in_elements) { 5344 const char *text = "<doc >Hi</doc >"; 5345 const XML_Char *expected = XCS("doc/doc"); 5346 CharData storage; 5347 5348 CharData_Init(&storage); 5349 XML_SetElementHandler(g_parser, record_element_start_handler, 5350 record_element_end_handler); 5351 XML_SetUserData(g_parser, &storage); 5352 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 5353 == XML_STATUS_ERROR) 5354 xml_failure(g_parser); 5355 CharData_CheckXMLChars(&storage, expected); 5356 } 5357 END_TEST 5358 5359 START_TEST(test_utf16_attribute) { 5360 const char text[] = 5361 /* <d {KHO KHWAI}{CHO CHAN}='a'/> 5362 * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8 5363 * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8 5364 */ 5365 "<\0d\0 \0\x04\x0e\x08\x0e=\0'\0a\0'\0/\0>\0"; 5366 const XML_Char *expected = XCS("a"); 5367 CharData storage; 5368 5369 CharData_Init(&storage); 5370 XML_SetStartElementHandler(g_parser, accumulate_attribute); 5371 XML_SetUserData(g_parser, &storage); 5372 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 5373 == XML_STATUS_ERROR) 5374 xml_failure(g_parser); 5375 CharData_CheckXMLChars(&storage, expected); 5376 } 5377 END_TEST 5378 5379 START_TEST(test_utf16_second_attr) { 5380 /* <d a='1' {KHO KHWAI}{CHO CHAN}='2'/> 5381 * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8 5382 * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8 5383 */ 5384 const char text[] = "<\0d\0 \0a\0=\0'\0\x31\0'\0 \0" 5385 "\x04\x0e\x08\x0e=\0'\0\x32\0'\0/\0>\0"; 5386 const XML_Char *expected = XCS("1"); 5387 CharData storage; 5388 5389 CharData_Init(&storage); 5390 XML_SetStartElementHandler(g_parser, accumulate_attribute); 5391 XML_SetUserData(g_parser, &storage); 5392 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 5393 == XML_STATUS_ERROR) 5394 xml_failure(g_parser); 5395 CharData_CheckXMLChars(&storage, expected); 5396 } 5397 END_TEST 5398 5399 START_TEST(test_attr_after_solidus) { 5400 const char *text = "<doc attr1='a' / attr2='b'>"; 5401 5402 expect_failure(text, XML_ERROR_INVALID_TOKEN, "Misplaced / not faulted"); 5403 } 5404 END_TEST 5405 5406 START_TEST(test_utf16_pe) { 5407 /* <!DOCTYPE doc [ 5408 * <!ENTITY % {KHO KHWAI}{CHO CHAN} '<!ELEMENT doc (#PCDATA)>'> 5409 * %{KHO KHWAI}{CHO CHAN}; 5410 * ]> 5411 * <doc></doc> 5412 * 5413 * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8 5414 * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8 5415 */ 5416 const char text[] = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n" 5417 "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \x0e\x04\x0e\x08\0 " 5418 "\0'\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 " 5419 "\0d\0o\0c\0 \0(\0#\0P\0C\0D\0A\0T\0A\0)\0>\0'\0>\0\n" 5420 "\0%\x0e\x04\x0e\x08\0;\0\n" 5421 "\0]\0>\0\n" 5422 "\0<\0d\0o\0c\0>\0<\0/\0d\0o\0c\0>"; 5423 #ifdef XML_UNICODE 5424 const XML_Char *expected = XCS("\x0e04\x0e08=<!ELEMENT doc (#PCDATA)>\n"); 5425 #else 5426 const XML_Char *expected 5427 = XCS("\xe0\xb8\x84\xe0\xb8\x88=<!ELEMENT doc (#PCDATA)>\n"); 5428 #endif 5429 CharData storage; 5430 5431 CharData_Init(&storage); 5432 XML_SetUserData(g_parser, &storage); 5433 XML_SetEntityDeclHandler(g_parser, accumulate_entity_decl); 5434 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 5435 == XML_STATUS_ERROR) 5436 xml_failure(g_parser); 5437 CharData_CheckXMLChars(&storage, expected); 5438 } 5439 END_TEST 5440 5441 /* Test that duff attribute description keywords are rejected */ 5442 START_TEST(test_bad_attr_desc_keyword) { 5443 const char *text = "<!DOCTYPE doc [\n" 5444 " <!ATTLIST doc attr CDATA #!IMPLIED>\n" 5445 "]>\n" 5446 "<doc />"; 5447 5448 expect_failure(text, XML_ERROR_INVALID_TOKEN, 5449 "Bad keyword !IMPLIED not faulted"); 5450 } 5451 END_TEST 5452 5453 /* Test that an invalid attribute description keyword consisting of 5454 * UTF-16 characters with their top bytes non-zero are correctly 5455 * faulted 5456 */ 5457 START_TEST(test_bad_attr_desc_keyword_utf16) { 5458 /* <!DOCTYPE d [ 5459 * <!ATTLIST d a CDATA #{KHO KHWAI}{CHO CHAN}> 5460 * ]><d/> 5461 * 5462 * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8 5463 * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8 5464 */ 5465 const char text[] 5466 = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n" 5467 "\0<\0!\0A\0T\0T\0L\0I\0S\0T\0 \0d\0 \0a\0 \0C\0D\0A\0T\0A\0 " 5468 "\0#\x0e\x04\x0e\x08\0>\0\n" 5469 "\0]\0>\0<\0d\0/\0>"; 5470 5471 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 5472 != XML_STATUS_ERROR) 5473 fail("Invalid UTF16 attribute keyword not faulted"); 5474 if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX) 5475 xml_failure(g_parser); 5476 } 5477 END_TEST 5478 5479 /* Test that invalid syntax in a <!DOCTYPE> is rejected. Do this 5480 * using prefix-encoding (see above) to trigger specific code paths 5481 */ 5482 START_TEST(test_bad_doctype) { 5483 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n" 5484 "<!DOCTYPE doc [ \x80\x44 ]><doc/>"; 5485 5486 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 5487 expect_failure(text, XML_ERROR_SYNTAX, 5488 "Invalid bytes in DOCTYPE not faulted"); 5489 } 5490 END_TEST 5491 5492 START_TEST(test_bad_doctype_utf8) { 5493 const char *text = "<!DOCTYPE \xDB\x25" 5494 "doc><doc/>"; // [1101 1011] [<0>010 0101] 5495 expect_failure(text, XML_ERROR_INVALID_TOKEN, 5496 "Invalid UTF-8 in DOCTYPE not faulted"); 5497 } 5498 END_TEST 5499 5500 START_TEST(test_bad_doctype_utf16) { 5501 const char text[] = 5502 /* <!DOCTYPE doc [ \x06f2 ]><doc/> 5503 * 5504 * U+06F2 = EXTENDED ARABIC-INDIC DIGIT TWO, a valid number 5505 * (name character) but not a valid letter (name start character) 5506 */ 5507 "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0 " 5508 "\x06\xf2" 5509 "\0 \0]\0>\0<\0d\0o\0c\0/\0>"; 5510 5511 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 5512 != XML_STATUS_ERROR) 5513 fail("Invalid bytes in DOCTYPE not faulted"); 5514 if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX) 5515 xml_failure(g_parser); 5516 } 5517 END_TEST 5518 5519 START_TEST(test_bad_doctype_plus) { 5520 const char *text = "<!DOCTYPE 1+ [ <!ENTITY foo 'bar'> ]>\n" 5521 "<1+>&foo;</1+>"; 5522 5523 expect_failure(text, XML_ERROR_INVALID_TOKEN, 5524 "'+' in document name not faulted"); 5525 } 5526 END_TEST 5527 5528 START_TEST(test_bad_doctype_star) { 5529 const char *text = "<!DOCTYPE 1* [ <!ENTITY foo 'bar'> ]>\n" 5530 "<1*>&foo;</1*>"; 5531 5532 expect_failure(text, XML_ERROR_INVALID_TOKEN, 5533 "'*' in document name not faulted"); 5534 } 5535 END_TEST 5536 5537 START_TEST(test_bad_doctype_query) { 5538 const char *text = "<!DOCTYPE 1? [ <!ENTITY foo 'bar'> ]>\n" 5539 "<1?>&foo;</1?>"; 5540 5541 expect_failure(text, XML_ERROR_INVALID_TOKEN, 5542 "'?' in document name not faulted"); 5543 } 5544 END_TEST 5545 5546 START_TEST(test_unknown_encoding_bad_ignore) { 5547 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>" 5548 "<!DOCTYPE doc SYSTEM 'foo'>" 5549 "<doc><e>&entity;</e></doc>"; 5550 ExtFaults fault = {"<![IGNORE[<!ELEMENT \xffG (#PCDATA)*>]]>", 5551 "Invalid character not faulted", XCS("prefix-conv"), 5552 XML_ERROR_INVALID_TOKEN}; 5553 5554 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL); 5555 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 5556 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter); 5557 XML_SetUserData(g_parser, &fault); 5558 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING, 5559 "Bad IGNORE section with unknown encoding not failed"); 5560 } 5561 END_TEST 5562 5563 START_TEST(test_entity_in_utf16_be_attr) { 5564 const char text[] = 5565 /* <e a='ä ä'></e> */ 5566 "\0<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 " 5567 "\0&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>"; 5568 #ifdef XML_UNICODE 5569 const XML_Char *expected = XCS("\x00e4 \x00e4"); 5570 #else 5571 const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4"); 5572 #endif 5573 CharData storage; 5574 5575 CharData_Init(&storage); 5576 XML_SetUserData(g_parser, &storage); 5577 XML_SetStartElementHandler(g_parser, accumulate_attribute); 5578 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 5579 == XML_STATUS_ERROR) 5580 xml_failure(g_parser); 5581 CharData_CheckXMLChars(&storage, expected); 5582 } 5583 END_TEST 5584 5585 START_TEST(test_entity_in_utf16_le_attr) { 5586 const char text[] = 5587 /* <e a='ä ä'></e> */ 5588 "<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 \0" 5589 "&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>\0"; 5590 #ifdef XML_UNICODE 5591 const XML_Char *expected = XCS("\x00e4 \x00e4"); 5592 #else 5593 const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4"); 5594 #endif 5595 CharData storage; 5596 5597 CharData_Init(&storage); 5598 XML_SetUserData(g_parser, &storage); 5599 XML_SetStartElementHandler(g_parser, accumulate_attribute); 5600 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 5601 == XML_STATUS_ERROR) 5602 xml_failure(g_parser); 5603 CharData_CheckXMLChars(&storage, expected); 5604 } 5605 END_TEST 5606 5607 START_TEST(test_entity_public_utf16_be) { 5608 const char text[] = 5609 /* <!DOCTYPE d [ */ 5610 "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n" 5611 /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */ 5612 "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 " 5613 "\0'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n" 5614 /* %e; */ 5615 "\0%\0e\0;\0\n" 5616 /* ]> */ 5617 "\0]\0>\0\n" 5618 /* <d>&j;</d> */ 5619 "\0<\0d\0>\0&\0j\0;\0<\0/\0d\0>"; 5620 ExtTest2 test_data 5621 = {/* <!ENTITY j 'baz'> */ 5622 "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>", 34, NULL, NULL}; 5623 const XML_Char *expected = XCS("baz"); 5624 CharData storage; 5625 5626 CharData_Init(&storage); 5627 test_data.storage = &storage; 5628 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 5629 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2); 5630 XML_SetUserData(g_parser, &test_data); 5631 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters); 5632 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 5633 == XML_STATUS_ERROR) 5634 xml_failure(g_parser); 5635 CharData_CheckXMLChars(&storage, expected); 5636 } 5637 END_TEST 5638 5639 START_TEST(test_entity_public_utf16_le) { 5640 const char text[] = 5641 /* <!DOCTYPE d [ */ 5642 "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n\0" 5643 /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */ 5644 "<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 \0" 5645 "'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n\0" 5646 /* %e; */ 5647 "%\0e\0;\0\n\0" 5648 /* ]> */ 5649 "]\0>\0\n\0" 5650 /* <d>&j;</d> */ 5651 "<\0d\0>\0&\0j\0;\0<\0/\0d\0>\0"; 5652 ExtTest2 test_data 5653 = {/* <!ENTITY j 'baz'> */ 5654 "<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>\0", 34, NULL, NULL}; 5655 const XML_Char *expected = XCS("baz"); 5656 CharData storage; 5657 5658 CharData_Init(&storage); 5659 test_data.storage = &storage; 5660 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 5661 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2); 5662 XML_SetUserData(g_parser, &test_data); 5663 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters); 5664 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 5665 == XML_STATUS_ERROR) 5666 xml_failure(g_parser); 5667 CharData_CheckXMLChars(&storage, expected); 5668 } 5669 END_TEST 5670 5671 /* Test that a doctype with neither an internal nor external subset is 5672 * faulted 5673 */ 5674 START_TEST(test_short_doctype) { 5675 const char *text = "<!DOCTYPE doc></doc>"; 5676 expect_failure(text, XML_ERROR_INVALID_TOKEN, 5677 "DOCTYPE without subset not rejected"); 5678 } 5679 END_TEST 5680 5681 START_TEST(test_short_doctype_2) { 5682 const char *text = "<!DOCTYPE doc PUBLIC></doc>"; 5683 expect_failure(text, XML_ERROR_SYNTAX, 5684 "DOCTYPE without Public ID not rejected"); 5685 } 5686 END_TEST 5687 5688 START_TEST(test_short_doctype_3) { 5689 const char *text = "<!DOCTYPE doc SYSTEM></doc>"; 5690 expect_failure(text, XML_ERROR_SYNTAX, 5691 "DOCTYPE without System ID not rejected"); 5692 } 5693 END_TEST 5694 5695 START_TEST(test_long_doctype) { 5696 const char *text = "<!DOCTYPE doc PUBLIC 'foo' 'bar' 'baz'></doc>"; 5697 expect_failure(text, XML_ERROR_SYNTAX, "DOCTYPE with extra ID not rejected"); 5698 } 5699 END_TEST 5700 5701 START_TEST(test_bad_entity) { 5702 const char *text = "<!DOCTYPE doc [\n" 5703 " <!ENTITY foo PUBLIC>\n" 5704 "]>\n" 5705 "<doc/>"; 5706 expect_failure(text, XML_ERROR_SYNTAX, 5707 "ENTITY without Public ID is not rejected"); 5708 } 5709 END_TEST 5710 5711 /* Test unquoted value is faulted */ 5712 START_TEST(test_bad_entity_2) { 5713 const char *text = "<!DOCTYPE doc [\n" 5714 " <!ENTITY % foo bar>\n" 5715 "]>\n" 5716 "<doc/>"; 5717 expect_failure(text, XML_ERROR_SYNTAX, 5718 "ENTITY without Public ID is not rejected"); 5719 } 5720 END_TEST 5721 5722 START_TEST(test_bad_entity_3) { 5723 const char *text = "<!DOCTYPE doc [\n" 5724 " <!ENTITY % foo PUBLIC>\n" 5725 "]>\n" 5726 "<doc/>"; 5727 expect_failure(text, XML_ERROR_SYNTAX, 5728 "Parameter ENTITY without Public ID is not rejected"); 5729 } 5730 END_TEST 5731 5732 START_TEST(test_bad_entity_4) { 5733 const char *text = "<!DOCTYPE doc [\n" 5734 " <!ENTITY % foo SYSTEM>\n" 5735 "]>\n" 5736 "<doc/>"; 5737 expect_failure(text, XML_ERROR_SYNTAX, 5738 "Parameter ENTITY without Public ID is not rejected"); 5739 } 5740 END_TEST 5741 5742 START_TEST(test_bad_notation) { 5743 const char *text = "<!DOCTYPE doc [\n" 5744 " <!NOTATION n SYSTEM>\n" 5745 "]>\n" 5746 "<doc/>"; 5747 expect_failure(text, XML_ERROR_SYNTAX, 5748 "Notation without System ID is not rejected"); 5749 } 5750 END_TEST 5751 5752 /* Test for issue #11, wrongly suppressed default handler */ 5753 START_TEST(test_default_doctype_handler) { 5754 const char *text = "<!DOCTYPE doc PUBLIC 'pubname' 'test.dtd' [\n" 5755 " <!ENTITY foo 'bar'>\n" 5756 "]>\n" 5757 "<doc>&foo;</doc>"; 5758 DefaultCheck test_data[] = {{XCS("'pubname'"), 9, XML_FALSE}, 5759 {XCS("'test.dtd'"), 10, XML_FALSE}, 5760 {NULL, 0, XML_FALSE}}; 5761 int i; 5762 5763 XML_SetUserData(g_parser, &test_data); 5764 XML_SetDefaultHandler(g_parser, checking_default_handler); 5765 XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler); 5766 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 5767 == XML_STATUS_ERROR) 5768 xml_failure(g_parser); 5769 for (i = 0; test_data[i].expected != NULL; i++) 5770 if (! test_data[i].seen) 5771 fail("Default handler not run for public !DOCTYPE"); 5772 } 5773 END_TEST 5774 5775 START_TEST(test_empty_element_abort) { 5776 const char *text = "<abort/>"; 5777 5778 XML_SetStartElementHandler(g_parser, start_element_suspender); 5779 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 5780 != XML_STATUS_ERROR) 5781 fail("Expected to error on abort"); 5782 } 5783 END_TEST 5784 5785 /* Regression test for GH issue #612: unfinished m_declAttributeType 5786 * allocation in ->m_tempPool can corrupt following allocation. 5787 */ 5788 START_TEST(test_pool_integrity_with_unfinished_attr) { 5789 const char *text = "<?xml version='1.0' encoding='UTF-8'?>\n" 5790 "<!DOCTYPE foo [\n" 5791 "<!ELEMENT foo ANY>\n" 5792 "<!ENTITY % entp SYSTEM \"external.dtd\">\n" 5793 "%entp;\n" 5794 "]>\n" 5795 "<a></a>\n"; 5796 const XML_Char *expected = XCS("COMMENT"); 5797 CharData storage; 5798 5799 CharData_Init(&storage); 5800 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 5801 XML_SetExternalEntityRefHandler(g_parser, external_entity_unfinished_attlist); 5802 XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler); 5803 XML_SetCommentHandler(g_parser, accumulate_comment); 5804 XML_SetUserData(g_parser, &storage); 5805 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 5806 == XML_STATUS_ERROR) 5807 xml_failure(g_parser); 5808 CharData_CheckXMLChars(&storage, expected); 5809 } 5810 END_TEST 5811 5812 /* Test a possible early return location in internalEntityProcessor */ 5813 START_TEST(test_entity_ref_no_elements) { 5814 const char *const text = "<!DOCTYPE foo [\n" 5815 "<!ENTITY e1 \"test\">\n" 5816 "]> <foo>&e1;"; // intentionally missing newline 5817 5818 XML_Parser parser = XML_ParserCreate(NULL); 5819 assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 5820 == XML_STATUS_ERROR); 5821 assert_true(XML_GetErrorCode(parser) == XML_ERROR_NO_ELEMENTS); 5822 XML_ParserFree(parser); 5823 } 5824 END_TEST 5825 5826 /* Tests if chained entity references lead to unbounded recursion */ 5827 START_TEST(test_deep_nested_entity) { 5828 const size_t N_LINES = 60000; 5829 const size_t SIZE_PER_LINE = 50; 5830 5831 char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE); 5832 if (text == NULL) { 5833 fail("malloc failed"); 5834 } 5835 5836 char *textPtr = text; 5837 5838 // Create the XML 5839 textPtr += snprintf(textPtr, SIZE_PER_LINE, 5840 "<!DOCTYPE foo [\n" 5841 " <!ENTITY s0 'deepText'>\n"); 5842 5843 for (size_t i = 1; i < N_LINES; ++i) { 5844 textPtr += snprintf(textPtr, SIZE_PER_LINE, " <!ENTITY s%lu '&s%lu;'>\n", 5845 (long unsigned)i, (long unsigned)(i - 1)); 5846 } 5847 5848 snprintf(textPtr, SIZE_PER_LINE, "]> <foo>&s%lu;</foo>\n", 5849 (long unsigned)(N_LINES - 1)); 5850 5851 const XML_Char *const expected = XCS("deepText"); 5852 5853 CharData storage; 5854 CharData_Init(&storage); 5855 5856 XML_Parser parser = XML_ParserCreate(NULL); 5857 5858 XML_SetCharacterDataHandler(parser, accumulate_characters); 5859 XML_SetUserData(parser, &storage); 5860 5861 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 5862 == XML_STATUS_ERROR) 5863 xml_failure(parser); 5864 5865 CharData_CheckXMLChars(&storage, expected); 5866 XML_ParserFree(parser); 5867 free(text); 5868 } 5869 END_TEST 5870 5871 /* Tests if chained entity references in attributes 5872 lead to unbounded recursion */ 5873 START_TEST(test_deep_nested_attribute_entity) { 5874 const size_t N_LINES = 60000; 5875 const size_t SIZE_PER_LINE = 100; 5876 5877 char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE); 5878 if (text == NULL) { 5879 fail("malloc failed"); 5880 } 5881 5882 char *textPtr = text; 5883 5884 // Create the XML 5885 textPtr += snprintf(textPtr, SIZE_PER_LINE, 5886 "<!DOCTYPE foo [\n" 5887 " <!ENTITY s0 'deepText'>\n"); 5888 5889 for (size_t i = 1; i < N_LINES; ++i) { 5890 textPtr += snprintf(textPtr, SIZE_PER_LINE, " <!ENTITY s%lu '&s%lu;'>\n", 5891 (long unsigned)i, (long unsigned)(i - 1)); 5892 } 5893 5894 snprintf(textPtr, SIZE_PER_LINE, "]> <foo name='&s%lu;'>mainText</foo>\n", 5895 (long unsigned)(N_LINES - 1)); 5896 5897 AttrInfo doc_info[] = {{XCS("name"), XCS("deepText")}, {NULL, NULL}}; 5898 ElementInfo info[] 5899 = {{XCS("foo"), 1, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}}; 5900 5901 XML_Parser parser = XML_ParserCreate(NULL); 5902 ParserAndElementInfo parserPlusElemenInfo = {parser, info}; 5903 5904 XML_SetStartElementHandler(parser, counting_start_element_handler); 5905 XML_SetUserData(parser, &parserPlusElemenInfo); 5906 5907 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 5908 == XML_STATUS_ERROR) 5909 xml_failure(parser); 5910 5911 XML_ParserFree(parser); 5912 free(text); 5913 } 5914 END_TEST 5915 5916 START_TEST(test_deep_nested_entity_delayed_interpretation) { 5917 const size_t N_LINES = 70000; 5918 const size_t SIZE_PER_LINE = 100; 5919 5920 char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE); 5921 if (text == NULL) { 5922 fail("malloc failed"); 5923 } 5924 5925 char *textPtr = text; 5926 5927 // Create the XML 5928 textPtr += snprintf(textPtr, SIZE_PER_LINE, 5929 "<!DOCTYPE foo [\n" 5930 " <!ENTITY %% s0 'deepText'>\n"); 5931 5932 for (size_t i = 1; i < N_LINES; ++i) { 5933 textPtr += snprintf(textPtr, SIZE_PER_LINE, 5934 " <!ENTITY %% s%lu '%s%lu;'>\n", (long unsigned)i, 5935 (long unsigned)(i - 1)); 5936 } 5937 5938 snprintf(textPtr, SIZE_PER_LINE, 5939 " <!ENTITY %% define_g \"<!ENTITY g '%s%lu;'>\">\n" 5940 " %%define_g;\n" 5941 "]>\n" 5942 "<foo/>\n", 5943 (long unsigned)(N_LINES - 1)); 5944 5945 XML_Parser parser = XML_ParserCreate(NULL); 5946 5947 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 5948 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 5949 == XML_STATUS_ERROR) 5950 xml_failure(parser); 5951 5952 XML_ParserFree(parser); 5953 free(text); 5954 } 5955 END_TEST 5956 5957 START_TEST(test_nested_entity_suspend) { 5958 const char *const text = "<!DOCTYPE a [\n" 5959 " <!ENTITY e1 '<!--e1-->'>\n" 5960 " <!ENTITY e2 '<!--e2 head-->&e1;<!--e2 tail-->'>\n" 5961 " <!ENTITY e3 '<!--e3 head-->&e2;<!--e3 tail-->'>\n" 5962 "]>\n" 5963 "<a><!--start-->&e3;<!--end--></a>"; 5964 const XML_Char *const expected = XCS("start") XCS("e3 head") XCS("e2 head") 5965 XCS("e1") XCS("e2 tail") XCS("e3 tail") XCS("end"); 5966 CharData storage; 5967 CharData_Init(&storage); 5968 XML_Parser parser = XML_ParserCreate(NULL); 5969 ParserPlusStorage parserPlusStorage = {parser, &storage}; 5970 5971 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 5972 XML_SetCommentHandler(parser, accumulate_and_suspend_comment_handler); 5973 XML_SetUserData(parser, &parserPlusStorage); 5974 5975 enum XML_Status status = XML_Parse(parser, text, (int)strlen(text), XML_TRUE); 5976 while (status == XML_STATUS_SUSPENDED) { 5977 status = XML_ResumeParser(parser); 5978 } 5979 if (status != XML_STATUS_OK) 5980 xml_failure(parser); 5981 5982 CharData_CheckXMLChars(&storage, expected); 5983 XML_ParserFree(parser); 5984 } 5985 END_TEST 5986 5987 START_TEST(test_nested_entity_suspend_2) { 5988 const char *const text = "<!DOCTYPE doc [\n" 5989 " <!ENTITY ge1 'head1Ztail1'>\n" 5990 " <!ENTITY ge2 'head2&ge1;tail2'>\n" 5991 " <!ENTITY ge3 'head3&ge2;tail3'>\n" 5992 "]>\n" 5993 "<doc>&ge3;</doc>"; 5994 const XML_Char *const expected = XCS("head3") XCS("head2") XCS("head1") 5995 XCS("Z") XCS("tail1") XCS("tail2") XCS("tail3"); 5996 CharData storage; 5997 CharData_Init(&storage); 5998 XML_Parser parser = XML_ParserCreate(NULL); 5999 ParserPlusStorage parserPlusStorage = {parser, &storage}; 6000 6001 XML_SetCharacterDataHandler(parser, accumulate_char_data_and_suspend); 6002 XML_SetUserData(parser, &parserPlusStorage); 6003 6004 enum XML_Status status = XML_Parse(parser, text, (int)strlen(text), XML_TRUE); 6005 while (status == XML_STATUS_SUSPENDED) { 6006 status = XML_ResumeParser(parser); 6007 } 6008 if (status != XML_STATUS_OK) 6009 xml_failure(parser); 6010 6011 CharData_CheckXMLChars(&storage, expected); 6012 XML_ParserFree(parser); 6013 } 6014 END_TEST 6015 6016 /* Regression test for quadratic parsing on large tokens */ 6017 START_TEST(test_big_tokens_scale_linearly) { 6018 const struct { 6019 const char *pre; 6020 const char *post; 6021 } text[] = { 6022 {"<a>", "</a>"}, // assumed good, used as baseline 6023 {"<b><![CDATA[ value: ", " ]]></b>"}, // CDATA, performed OK before patch 6024 {"<c attr='", "'></c>"}, // big attribute, used to be O(N²) 6025 {"<d><!-- ", " --></d>"}, // long comment, used to be O(N²) 6026 {"<e><", "/></e>"}, // big elem name, used to be O(N²) 6027 }; 6028 const int num_cases = sizeof(text) / sizeof(text[0]); 6029 char aaaaaa[4096]; 6030 const int fillsize = (int)sizeof(aaaaaa); 6031 const int fillcount = 100; 6032 const unsigned approx_bytes = fillsize * fillcount; // ignore pre/post. 6033 const unsigned max_factor = 4; 6034 const unsigned max_scanned = max_factor * approx_bytes; 6035 6036 memset(aaaaaa, 'a', fillsize); 6037 6038 if (! g_reparseDeferralEnabledDefault) { 6039 return; // heuristic is disabled; we would get O(n^2) and fail. 6040 } 6041 6042 for (int i = 0; i < num_cases; ++i) { 6043 XML_Parser parser = XML_ParserCreate(NULL); 6044 assert_true(parser != NULL); 6045 enum XML_Status status; 6046 set_subtest("text=\"%saaaaaa%s\"", text[i].pre, text[i].post); 6047 6048 // parse the start text 6049 g_bytesScanned = 0; 6050 status = _XML_Parse_SINGLE_BYTES(parser, text[i].pre, 6051 (int)strlen(text[i].pre), XML_FALSE); 6052 if (status != XML_STATUS_OK) { 6053 xml_failure(parser); 6054 } 6055 6056 // parse lots of 'a', failing the test early if it takes too long 6057 unsigned past_max_count = 0; 6058 for (int f = 0; f < fillcount; ++f) { 6059 status = _XML_Parse_SINGLE_BYTES(parser, aaaaaa, fillsize, XML_FALSE); 6060 if (status != XML_STATUS_OK) { 6061 xml_failure(parser); 6062 } 6063 if (g_bytesScanned > max_scanned) { 6064 // We're not done, and have already passed the limit -- the test will 6065 // definitely fail. This block allows us to save time by failing early. 6066 const unsigned pushed 6067 = (unsigned)strlen(text[i].pre) + (f + 1) * fillsize; 6068 fprintf( 6069 stderr, 6070 "after %d/%d loops: pushed=%u scanned=%u (factor ~%.2f) max_scanned: %u (factor ~%u)\n", 6071 f + 1, fillcount, pushed, g_bytesScanned, 6072 g_bytesScanned / (double)pushed, max_scanned, max_factor); 6073 past_max_count++; 6074 // We are failing, but allow a few log prints first. If we don't reach 6075 // a count of five, the test will fail after the loop instead. 6076 assert_true(past_max_count < 5); 6077 } 6078 } 6079 6080 // parse the end text 6081 status = _XML_Parse_SINGLE_BYTES(parser, text[i].post, 6082 (int)strlen(text[i].post), XML_TRUE); 6083 if (status != XML_STATUS_OK) { 6084 xml_failure(parser); 6085 } 6086 6087 assert_true(g_bytesScanned > approx_bytes); // or the counter isn't working 6088 if (g_bytesScanned > max_scanned) { 6089 fprintf( 6090 stderr, 6091 "after all input: scanned=%u (factor ~%.2f) max_scanned: %u (factor ~%u)\n", 6092 g_bytesScanned, g_bytesScanned / (double)approx_bytes, max_scanned, 6093 max_factor); 6094 fail("scanned too many bytes"); 6095 } 6096 6097 XML_ParserFree(parser); 6098 } 6099 } 6100 END_TEST 6101 6102 START_TEST(test_set_reparse_deferral) { 6103 const char *const pre = "<d>"; 6104 const char *const start = "<x attr='"; 6105 const char *const end = "'></x>"; 6106 char eeeeee[100]; 6107 const int fillsize = (int)sizeof(eeeeee); 6108 memset(eeeeee, 'e', fillsize); 6109 6110 for (int enabled = 0; enabled <= 1; enabled += 1) { 6111 set_subtest("deferral=%d", enabled); 6112 6113 XML_Parser parser = XML_ParserCreate(NULL); 6114 assert_true(parser != NULL); 6115 assert_true(XML_SetReparseDeferralEnabled(parser, enabled)); 6116 // pre-grow the buffer to avoid reparsing due to almost-fullness 6117 assert_true(XML_GetBuffer(parser, fillsize * 10103) != NULL); 6118 6119 CharData storage; 6120 CharData_Init(&storage); 6121 XML_SetUserData(parser, &storage); 6122 XML_SetStartElementHandler(parser, start_element_event_handler); 6123 6124 enum XML_Status status; 6125 // parse the start text 6126 status = XML_Parse(parser, pre, (int)strlen(pre), XML_FALSE); 6127 if (status != XML_STATUS_OK) { 6128 xml_failure(parser); 6129 } 6130 CharData_CheckXMLChars(&storage, XCS("d")); // first element should be done 6131 6132 // ..and the start of the token 6133 status = XML_Parse(parser, start, (int)strlen(start), XML_FALSE); 6134 if (status != XML_STATUS_OK) { 6135 xml_failure(parser); 6136 } 6137 CharData_CheckXMLChars(&storage, XCS("d")); // still just the first one 6138 6139 // try to parse lots of 'e', but the token isn't finished 6140 for (int c = 0; c < 100; ++c) { 6141 status = XML_Parse(parser, eeeeee, fillsize, XML_FALSE); 6142 if (status != XML_STATUS_OK) { 6143 xml_failure(parser); 6144 } 6145 } 6146 CharData_CheckXMLChars(&storage, XCS("d")); // *still* just the first one 6147 6148 // end the <x> token. 6149 status = XML_Parse(parser, end, (int)strlen(end), XML_FALSE); 6150 if (status != XML_STATUS_OK) { 6151 xml_failure(parser); 6152 } 6153 6154 if (enabled) { 6155 // In general, we may need to push more data to trigger a reparse attempt, 6156 // but in this test, the data is constructed to always require it. 6157 CharData_CheckXMLChars(&storage, XCS("d")); // or the test is incorrect 6158 // 2x the token length should suffice; the +1 covers the start and end. 6159 for (int c = 0; c < 101; ++c) { 6160 status = XML_Parse(parser, eeeeee, fillsize, XML_FALSE); 6161 if (status != XML_STATUS_OK) { 6162 xml_failure(parser); 6163 } 6164 } 6165 } 6166 CharData_CheckXMLChars(&storage, XCS("dx")); // the <x> should be done 6167 6168 XML_ParserFree(parser); 6169 } 6170 } 6171 END_TEST 6172 6173 struct element_decl_data { 6174 XML_Parser parser; 6175 int count; 6176 }; 6177 6178 static void 6179 element_decl_counter(void *userData, const XML_Char *name, XML_Content *model) { 6180 UNUSED_P(name); 6181 struct element_decl_data *testdata = (struct element_decl_data *)userData; 6182 testdata->count += 1; 6183 XML_FreeContentModel(testdata->parser, model); 6184 } 6185 6186 static int 6187 external_inherited_parser(XML_Parser p, const XML_Char *context, 6188 const XML_Char *base, const XML_Char *systemId, 6189 const XML_Char *publicId) { 6190 UNUSED_P(base); 6191 UNUSED_P(systemId); 6192 UNUSED_P(publicId); 6193 const char *const pre = "<!ELEMENT document ANY>\n"; 6194 const char *const start = "<!ELEMENT "; 6195 const char *const end = " ANY>\n"; 6196 const char *const post = "<!ELEMENT xyz ANY>\n"; 6197 const int enabled = *(int *)XML_GetUserData(p); 6198 char eeeeee[100]; 6199 char spaces[100]; 6200 const int fillsize = (int)sizeof(eeeeee); 6201 assert_true(fillsize == (int)sizeof(spaces)); 6202 memset(eeeeee, 'e', fillsize); 6203 memset(spaces, ' ', fillsize); 6204 6205 XML_Parser parser = XML_ExternalEntityParserCreate(p, context, NULL); 6206 assert_true(parser != NULL); 6207 // pre-grow the buffer to avoid reparsing due to almost-fullness 6208 assert_true(XML_GetBuffer(parser, fillsize * 10103) != NULL); 6209 6210 struct element_decl_data testdata; 6211 testdata.parser = parser; 6212 testdata.count = 0; 6213 XML_SetUserData(parser, &testdata); 6214 XML_SetElementDeclHandler(parser, element_decl_counter); 6215 6216 enum XML_Status status; 6217 // parse the initial text 6218 status = XML_Parse(parser, pre, (int)strlen(pre), XML_FALSE); 6219 if (status != XML_STATUS_OK) { 6220 xml_failure(parser); 6221 } 6222 assert_true(testdata.count == 1); // first element should be done 6223 6224 // ..and the start of the big token 6225 status = XML_Parse(parser, start, (int)strlen(start), XML_FALSE); 6226 if (status != XML_STATUS_OK) { 6227 xml_failure(parser); 6228 } 6229 assert_true(testdata.count == 1); // still just the first one 6230 6231 // try to parse lots of 'e', but the token isn't finished 6232 for (int c = 0; c < 100; ++c) { 6233 status = XML_Parse(parser, eeeeee, fillsize, XML_FALSE); 6234 if (status != XML_STATUS_OK) { 6235 xml_failure(parser); 6236 } 6237 } 6238 assert_true(testdata.count == 1); // *still* just the first one 6239 6240 // end the big token. 6241 status = XML_Parse(parser, end, (int)strlen(end), XML_FALSE); 6242 if (status != XML_STATUS_OK) { 6243 xml_failure(parser); 6244 } 6245 6246 if (enabled) { 6247 // In general, we may need to push more data to trigger a reparse attempt, 6248 // but in this test, the data is constructed to always require it. 6249 assert_true(testdata.count == 1); // or the test is incorrect 6250 // 2x the token length should suffice; the +1 covers the start and end. 6251 for (int c = 0; c < 101; ++c) { 6252 status = XML_Parse(parser, spaces, fillsize, XML_FALSE); 6253 if (status != XML_STATUS_OK) { 6254 xml_failure(parser); 6255 } 6256 } 6257 } 6258 assert_true(testdata.count == 2); // the big token should be done 6259 6260 // parse the final text 6261 status = XML_Parse(parser, post, (int)strlen(post), XML_TRUE); 6262 if (status != XML_STATUS_OK) { 6263 xml_failure(parser); 6264 } 6265 assert_true(testdata.count == 3); // after isFinal=XML_TRUE, all must be done 6266 6267 XML_ParserFree(parser); 6268 return XML_STATUS_OK; 6269 } 6270 6271 START_TEST(test_reparse_deferral_is_inherited) { 6272 const char *const text 6273 = "<!DOCTYPE document SYSTEM 'something.ext'><document/>"; 6274 for (int enabled = 0; enabled <= 1; ++enabled) { 6275 set_subtest("deferral=%d", enabled); 6276 6277 XML_Parser parser = XML_ParserCreate(NULL); 6278 assert_true(parser != NULL); 6279 XML_SetUserData(parser, (void *)&enabled); 6280 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 6281 // this handler creates a sub-parser and checks that its deferral behavior 6282 // is what we expected, based on the value of `enabled` (in userdata). 6283 XML_SetExternalEntityRefHandler(parser, external_inherited_parser); 6284 assert_true(XML_SetReparseDeferralEnabled(parser, enabled)); 6285 if (XML_Parse(parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_OK) 6286 xml_failure(parser); 6287 6288 XML_ParserFree(parser); 6289 } 6290 } 6291 END_TEST 6292 6293 START_TEST(test_set_reparse_deferral_on_null_parser) { 6294 assert_true(XML_SetReparseDeferralEnabled(NULL, 0) == XML_FALSE); 6295 assert_true(XML_SetReparseDeferralEnabled(NULL, 1) == XML_FALSE); 6296 assert_true(XML_SetReparseDeferralEnabled(NULL, 10) == XML_FALSE); 6297 assert_true(XML_SetReparseDeferralEnabled(NULL, 100) == XML_FALSE); 6298 assert_true(XML_SetReparseDeferralEnabled(NULL, (XML_Bool)INT_MIN) 6299 == XML_FALSE); 6300 assert_true(XML_SetReparseDeferralEnabled(NULL, (XML_Bool)INT_MAX) 6301 == XML_FALSE); 6302 } 6303 END_TEST 6304 6305 START_TEST(test_set_reparse_deferral_on_the_fly) { 6306 const char *const pre = "<d><x attr='"; 6307 const char *const end = "'></x>"; 6308 char iiiiii[100]; 6309 const int fillsize = (int)sizeof(iiiiii); 6310 memset(iiiiii, 'i', fillsize); 6311 6312 XML_Parser parser = XML_ParserCreate(NULL); 6313 assert_true(parser != NULL); 6314 assert_true(XML_SetReparseDeferralEnabled(parser, XML_TRUE)); 6315 6316 CharData storage; 6317 CharData_Init(&storage); 6318 XML_SetUserData(parser, &storage); 6319 XML_SetStartElementHandler(parser, start_element_event_handler); 6320 6321 enum XML_Status status; 6322 // parse the start text 6323 status = XML_Parse(parser, pre, (int)strlen(pre), XML_FALSE); 6324 if (status != XML_STATUS_OK) { 6325 xml_failure(parser); 6326 } 6327 CharData_CheckXMLChars(&storage, XCS("d")); // first element should be done 6328 6329 // try to parse some 'i', but the token isn't finished 6330 status = XML_Parse(parser, iiiiii, fillsize, XML_FALSE); 6331 if (status != XML_STATUS_OK) { 6332 xml_failure(parser); 6333 } 6334 CharData_CheckXMLChars(&storage, XCS("d")); // *still* just the first one 6335 6336 // end the <x> token. 6337 status = XML_Parse(parser, end, (int)strlen(end), XML_FALSE); 6338 if (status != XML_STATUS_OK) { 6339 xml_failure(parser); 6340 } 6341 CharData_CheckXMLChars(&storage, XCS("d")); // not yet. 6342 6343 // now change the heuristic setting and add *no* data 6344 assert_true(XML_SetReparseDeferralEnabled(parser, XML_FALSE)); 6345 // we avoid isFinal=XML_TRUE, because that would force-bypass the heuristic. 6346 status = XML_Parse(parser, "", 0, XML_FALSE); 6347 if (status != XML_STATUS_OK) { 6348 xml_failure(parser); 6349 } 6350 CharData_CheckXMLChars(&storage, XCS("dx")); 6351 6352 XML_ParserFree(parser); 6353 } 6354 END_TEST 6355 6356 START_TEST(test_set_bad_reparse_option) { 6357 XML_Parser parser = XML_ParserCreate(NULL); 6358 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 2)); 6359 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 3)); 6360 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 99)); 6361 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 127)); 6362 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 128)); 6363 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 129)); 6364 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 255)); 6365 assert_true(XML_TRUE == XML_SetReparseDeferralEnabled(parser, 0)); 6366 assert_true(XML_TRUE == XML_SetReparseDeferralEnabled(parser, 1)); 6367 XML_ParserFree(parser); 6368 } 6369 END_TEST 6370 6371 static size_t g_totalAlloc = 0; 6372 static size_t g_biggestAlloc = 0; 6373 6374 static void * 6375 counting_realloc(void *ptr, size_t size) { 6376 g_totalAlloc += size; 6377 if (size > g_biggestAlloc) { 6378 g_biggestAlloc = size; 6379 } 6380 return realloc(ptr, size); 6381 } 6382 6383 static void * 6384 counting_malloc(size_t size) { 6385 return counting_realloc(NULL, size); 6386 } 6387 6388 START_TEST(test_bypass_heuristic_when_close_to_bufsize) { 6389 if (g_chunkSize != 0) { 6390 // this test does not use SINGLE_BYTES, because it depends on very precise 6391 // buffer fills. 6392 return; 6393 } 6394 if (! g_reparseDeferralEnabledDefault) { 6395 return; // this test is irrelevant when the deferral heuristic is disabled. 6396 } 6397 6398 const int document_length = 65536; 6399 char *const document = malloc(document_length); 6400 assert_true(document != NULL); 6401 6402 const XML_Memory_Handling_Suite memfuncs = { 6403 counting_malloc, 6404 counting_realloc, 6405 free, 6406 }; 6407 6408 const int leading_list[] = {0, 3, 61, 96, 400, 401, 4000, 4010, 4099, -1}; 6409 const int bigtoken_list[] = {3000, 4000, 4001, 4096, 4099, 5000, 20000, -1}; 6410 const int fillsize_list[] = {131, 256, 399, 400, 401, 1025, 4099, 4321, -1}; 6411 6412 for (const int *leading = leading_list; *leading >= 0; leading++) { 6413 for (const int *bigtoken = bigtoken_list; *bigtoken >= 0; bigtoken++) { 6414 for (const int *fillsize = fillsize_list; *fillsize >= 0; fillsize++) { 6415 set_subtest("leading=%d bigtoken=%d fillsize=%d", *leading, *bigtoken, 6416 *fillsize); 6417 // start by checking that the test looks reasonably valid 6418 assert_true(*leading + *bigtoken <= document_length); 6419 6420 // put 'x' everywhere; some will be overwritten by elements. 6421 memset(document, 'x', document_length); 6422 // maybe add an initial tag 6423 if (*leading) { 6424 assert_true(*leading >= 3); // or the test case is invalid 6425 memcpy(document, "<a>", 3); 6426 } 6427 // add the large token 6428 document[*leading + 0] = '<'; 6429 document[*leading + 1] = 'b'; 6430 memset(&document[*leading + 2], ' ', *bigtoken - 2); // a spacy token 6431 document[*leading + *bigtoken - 1] = '>'; 6432 6433 // 1 for 'b', plus 1 or 0 depending on the presence of 'a' 6434 const int expected_elem_total = 1 + (*leading ? 1 : 0); 6435 6436 XML_Parser parser = XML_ParserCreate_MM(NULL, &memfuncs, NULL); 6437 assert_true(parser != NULL); 6438 6439 CharData storage; 6440 CharData_Init(&storage); 6441 XML_SetUserData(parser, &storage); 6442 XML_SetStartElementHandler(parser, start_element_event_handler); 6443 6444 g_biggestAlloc = 0; 6445 g_totalAlloc = 0; 6446 int offset = 0; 6447 // fill data until the big token is covered (but not necessarily parsed) 6448 while (offset < *leading + *bigtoken) { 6449 assert_true(offset + *fillsize <= document_length); 6450 const enum XML_Status status 6451 = XML_Parse(parser, &document[offset], *fillsize, XML_FALSE); 6452 if (status != XML_STATUS_OK) { 6453 xml_failure(parser); 6454 } 6455 offset += *fillsize; 6456 } 6457 // Now, check that we've had a buffer allocation that could fit the 6458 // context bytes and our big token. In order to detect a special case, 6459 // we need to know how many bytes of our big token were included in the 6460 // first push that contained _any_ bytes of the big token: 6461 const int bigtok_first_chunk_bytes = *fillsize - (*leading % *fillsize); 6462 if (bigtok_first_chunk_bytes >= *bigtoken && XML_CONTEXT_BYTES == 0) { 6463 // Special case: we aren't saving any context, and the whole big token 6464 // was covered by a single fill, so Expat may have parsed directly 6465 // from our input pointer, without allocating an internal buffer. 6466 } else if (*leading < XML_CONTEXT_BYTES) { 6467 assert_true(g_biggestAlloc >= *leading + (size_t)*bigtoken); 6468 } else { 6469 assert_true(g_biggestAlloc >= XML_CONTEXT_BYTES + (size_t)*bigtoken); 6470 } 6471 // fill data until the big token is actually parsed 6472 while (storage.count < expected_elem_total) { 6473 const size_t alloc_before = g_totalAlloc; 6474 assert_true(offset + *fillsize <= document_length); 6475 const enum XML_Status status 6476 = XML_Parse(parser, &document[offset], *fillsize, XML_FALSE); 6477 if (status != XML_STATUS_OK) { 6478 xml_failure(parser); 6479 } 6480 offset += *fillsize; 6481 // since all the bytes of the big token are already in the buffer, 6482 // the bufsize ceiling should make us finish its parsing without any 6483 // further buffer allocations. We assume that there will be no other 6484 // large allocations in this test. 6485 assert_true(g_totalAlloc - alloc_before < 4096); 6486 } 6487 // test-the-test: was our alloc even called? 6488 assert_true(g_totalAlloc > 0); 6489 // test-the-test: there shouldn't be any extra start elements 6490 assert_true(storage.count == expected_elem_total); 6491 6492 XML_ParserFree(parser); 6493 } 6494 } 6495 } 6496 free(document); 6497 } 6498 END_TEST 6499 6500 START_TEST(test_varying_buffer_fills) { 6501 const int KiB = 1024; 6502 const int MiB = 1024 * KiB; 6503 const int document_length = 16 * MiB; 6504 const int big = 7654321; // arbitrarily chosen between 4 and 8 MiB 6505 6506 if (g_chunkSize != 0) { 6507 return; // this test is slow, and doesn't use _XML_Parse_SINGLE_BYTES(). 6508 } 6509 6510 char *const document = malloc(document_length); 6511 assert_true(document != NULL); 6512 memset(document, 'x', document_length); 6513 document[0] = '<'; 6514 document[1] = 't'; 6515 memset(&document[2], ' ', big - 2); // a very spacy token 6516 document[big - 1] = '>'; 6517 6518 // Each testcase is a list of buffer fill sizes, terminated by a value < 0. 6519 // When reparse deferral is enabled, the final (negated) value is the expected 6520 // maximum number of bytes scanned in parse attempts. 6521 const int testcases[][30] = { 6522 {8 * MiB, -8 * MiB}, 6523 {4 * MiB, 4 * MiB, -12 * MiB}, // try at 4MB, then 8MB = 12 MB total 6524 // zero-size fills shouldn't trigger the bypass 6525 {4 * MiB, 0, 4 * MiB, -12 * MiB}, 6526 {4 * MiB, 0, 0, 4 * MiB, -12 * MiB}, 6527 {4 * MiB, 0, 1 * MiB, 0, 3 * MiB, -12 * MiB}, 6528 // try to hit the buffer ceiling only once (at the end) 6529 {4 * MiB, 2 * MiB, 1 * MiB, 512 * KiB, 256 * KiB, 256 * KiB, -12 * MiB}, 6530 // try to hit the same buffer ceiling multiple times 6531 {4 * MiB + 1, 2 * MiB, 1 * MiB, 512 * KiB, -25 * MiB}, 6532 6533 // try to hit every ceiling, by always landing 1K shy of the buffer size 6534 {1 * KiB, 2 * KiB, 4 * KiB, 8 * KiB, 16 * KiB, 32 * KiB, 64 * KiB, 6535 128 * KiB, 256 * KiB, 512 * KiB, 1 * MiB, 2 * MiB, 4 * MiB, -16 * MiB}, 6536 6537 // try to avoid every ceiling, by always landing 1B past the buffer size 6538 // the normal 2x heuristic threshold still forces parse attempts. 6539 {2 * KiB + 1, // will attempt 2KiB + 1 ==> total 2KiB + 1 6540 2 * KiB, 4 * KiB, // will attempt 8KiB + 1 ==> total 10KiB + 2 6541 8 * KiB, 16 * KiB, // will attempt 32KiB + 1 ==> total 42KiB + 3 6542 32 * KiB, 64 * KiB, // will attempt 128KiB + 1 ==> total 170KiB + 4 6543 128 * KiB, 256 * KiB, // will attempt 512KiB + 1 ==> total 682KiB + 5 6544 512 * KiB, 1 * MiB, // will attempt 2MiB + 1 ==> total 2M + 682K + 6 6545 2 * MiB, 4 * MiB, // will attempt 8MiB + 1 ==> total 10M + 682K + 7 6546 -(10 * MiB + 682 * KiB + 7)}, 6547 // try to avoid every ceiling again, except on our last fill. 6548 {2 * KiB + 1, // will attempt 2KiB + 1 ==> total 2KiB + 1 6549 2 * KiB, 4 * KiB, // will attempt 8KiB + 1 ==> total 10KiB + 2 6550 8 * KiB, 16 * KiB, // will attempt 32KiB + 1 ==> total 42KiB + 3 6551 32 * KiB, 64 * KiB, // will attempt 128KiB + 1 ==> total 170KiB + 4 6552 128 * KiB, 256 * KiB, // will attempt 512KiB + 1 ==> total 682KiB + 5 6553 512 * KiB, 1 * MiB, // will attempt 2MiB + 1 ==> total 2M + 682K + 6 6554 2 * MiB, 4 * MiB - 1, // will attempt 8MiB ==> total 10M + 682K + 6 6555 -(10 * MiB + 682 * KiB + 6)}, 6556 6557 // try to hit ceilings on the way multiple times 6558 {512 * KiB + 1, 256 * KiB, 128 * KiB, 128 * KiB - 1, // 1 MiB buffer 6559 512 * KiB + 1, 256 * KiB, 128 * KiB, 128 * KiB - 1, // 2 MiB buffer 6560 1 * MiB + 1, 512 * KiB, 256 * KiB, 256 * KiB - 1, // 4 MiB buffer 6561 2 * MiB + 1, 1 * MiB, 512 * KiB, // 8 MiB buffer 6562 // we'll make a parse attempt at every parse call 6563 -(45 * MiB + 12)}, 6564 }; 6565 const int testcount = sizeof(testcases) / sizeof(testcases[0]); 6566 for (int test_i = 0; test_i < testcount; test_i++) { 6567 const int *fillsize = testcases[test_i]; 6568 set_subtest("#%d {%d %d %d %d ...}", test_i, fillsize[0], fillsize[1], 6569 fillsize[2], fillsize[3]); 6570 XML_Parser parser = XML_ParserCreate(NULL); 6571 assert_true(parser != NULL); 6572 6573 CharData storage; 6574 CharData_Init(&storage); 6575 XML_SetUserData(parser, &storage); 6576 XML_SetStartElementHandler(parser, start_element_event_handler); 6577 6578 g_bytesScanned = 0; 6579 int worstcase_bytes = 0; // sum of (buffered bytes at each XML_Parse call) 6580 int offset = 0; 6581 while (*fillsize >= 0) { 6582 assert_true(offset + *fillsize <= document_length); // or test is invalid 6583 const enum XML_Status status 6584 = XML_Parse(parser, &document[offset], *fillsize, XML_FALSE); 6585 if (status != XML_STATUS_OK) { 6586 xml_failure(parser); 6587 } 6588 offset += *fillsize; 6589 fillsize++; 6590 assert_true(offset <= INT_MAX - worstcase_bytes); // avoid overflow 6591 worstcase_bytes += offset; // we might've tried to parse all pending bytes 6592 } 6593 assert_true(storage.count == 1); // the big token should've been parsed 6594 assert_true(g_bytesScanned > 0); // test-the-test: does our counter work? 6595 if (g_reparseDeferralEnabledDefault) { 6596 // heuristic is enabled; some XML_Parse calls may have deferred reparsing 6597 const unsigned max_bytes_scanned = -*fillsize; 6598 if (g_bytesScanned > max_bytes_scanned) { 6599 fprintf(stderr, 6600 "bytes scanned in parse attempts: actual=%u limit=%u \n", 6601 g_bytesScanned, max_bytes_scanned); 6602 fail("too many bytes scanned in parse attempts"); 6603 } 6604 } 6605 assert_true(g_bytesScanned <= (unsigned)worstcase_bytes); 6606 6607 XML_ParserFree(parser); 6608 } 6609 free(document); 6610 } 6611 END_TEST 6612 6613 START_TEST(test_empty_ext_param_entity_in_value) { 6614 const char *text = "<!DOCTYPE r SYSTEM \"ext.dtd\"><r/>"; 6615 ExtOption options[] = { 6616 {XCS("ext.dtd"), "<!ENTITY % pe SYSTEM \"empty\">" 6617 "<!ENTITY ge \"%pe;\">"}, 6618 {XCS("empty"), ""}, 6619 {NULL, NULL}, 6620 }; 6621 6622 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 6623 XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner); 6624 XML_SetUserData(g_parser, options); 6625 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 6626 == XML_STATUS_ERROR) 6627 xml_failure(g_parser); 6628 } 6629 END_TEST 6630 6631 void 6632 make_basic_test_case(Suite *s) { 6633 TCase *tc_basic = tcase_create("basic tests"); 6634 6635 suite_add_tcase(s, tc_basic); 6636 tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown); 6637 6638 tcase_add_test(tc_basic, test_nul_byte); 6639 tcase_add_test(tc_basic, test_u0000_char); 6640 tcase_add_test(tc_basic, test_siphash_self); 6641 tcase_add_test(tc_basic, test_siphash_spec); 6642 tcase_add_test(tc_basic, test_bom_utf8); 6643 tcase_add_test(tc_basic, test_bom_utf16_be); 6644 tcase_add_test(tc_basic, test_bom_utf16_le); 6645 tcase_add_test(tc_basic, test_nobom_utf16_le); 6646 tcase_add_test(tc_basic, test_hash_collision); 6647 tcase_add_test(tc_basic, test_hash_salt_setter); 6648 tcase_add_test(tc_basic, test_illegal_utf8); 6649 tcase_add_test(tc_basic, test_utf8_auto_align); 6650 tcase_add_test(tc_basic, test_utf16); 6651 tcase_add_test(tc_basic, test_utf16_le_epilog_newline); 6652 tcase_add_test(tc_basic, test_not_utf16); 6653 tcase_add_test(tc_basic, test_bad_encoding); 6654 tcase_add_test(tc_basic, test_latin1_umlauts); 6655 tcase_add_test(tc_basic, test_long_utf8_character); 6656 tcase_add_test(tc_basic, test_long_latin1_attribute); 6657 tcase_add_test(tc_basic, test_long_ascii_attribute); 6658 /* Regression test for SF bug #491986. */ 6659 tcase_add_test(tc_basic, test_danish_latin1); 6660 /* Regression test for SF bug #514281. */ 6661 tcase_add_test(tc_basic, test_french_charref_hexidecimal); 6662 tcase_add_test(tc_basic, test_french_charref_decimal); 6663 tcase_add_test(tc_basic, test_french_latin1); 6664 tcase_add_test(tc_basic, test_french_utf8); 6665 tcase_add_test(tc_basic, test_utf8_false_rejection); 6666 tcase_add_test(tc_basic, test_line_number_after_parse); 6667 tcase_add_test(tc_basic, test_column_number_after_parse); 6668 tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers); 6669 tcase_add_test(tc_basic, test_line_number_after_error); 6670 tcase_add_test(tc_basic, test_column_number_after_error); 6671 tcase_add_test(tc_basic, test_really_long_lines); 6672 tcase_add_test(tc_basic, test_really_long_encoded_lines); 6673 tcase_add_test(tc_basic, test_end_element_events); 6674 tcase_add_test(tc_basic, test_helper_is_whitespace_normalized); 6675 tcase_add_test(tc_basic, test_attr_whitespace_normalization); 6676 tcase_add_test(tc_basic, test_xmldecl_misplaced); 6677 tcase_add_test(tc_basic, test_xmldecl_invalid); 6678 tcase_add_test(tc_basic, test_xmldecl_missing_attr); 6679 tcase_add_test(tc_basic, test_xmldecl_missing_value); 6680 tcase_add_test(tc_basic, test_xmldecl_empty_version); 6681 tcase_add_test__if_xml_ge(tc_basic, test_unknown_encoding_internal_entity); 6682 tcase_add_test(tc_basic, test_unrecognised_encoding_internal_entity); 6683 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_encoding); 6684 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_no_handler); 6685 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_bom); 6686 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_bad_encoding); 6687 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_bad_encoding_2); 6688 tcase_add_test(tc_basic, test_wfc_undeclared_entity_unread_external_subset); 6689 tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset); 6690 tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone); 6691 tcase_add_test(tc_basic, 6692 test_wfc_undeclared_entity_with_external_subset_standalone); 6693 tcase_add_test(tc_basic, test_entity_with_external_subset_unless_standalone); 6694 tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset); 6695 tcase_add_test(tc_basic, test_not_standalone_handler_reject); 6696 tcase_add_test(tc_basic, test_not_standalone_handler_accept); 6697 tcase_add_test(tc_basic, test_entity_start_tag_level_greater_than_one); 6698 tcase_add_test__if_xml_ge(tc_basic, test_wfc_no_recursive_entity_refs); 6699 tcase_add_test(tc_basic, test_no_indirectly_recursive_entity_refs); 6700 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_invalid_parse); 6701 tcase_add_test__if_xml_ge(tc_basic, test_dtd_default_handling); 6702 tcase_add_test(tc_basic, test_dtd_attr_handling); 6703 tcase_add_test(tc_basic, test_empty_ns_without_namespaces); 6704 tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces); 6705 tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls); 6706 tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls); 6707 tcase_add_test(tc_basic, test_repeated_stop_parser_between_char_data_calls); 6708 tcase_add_test(tc_basic, test_good_cdata_ascii); 6709 tcase_add_test(tc_basic, test_good_cdata_utf16); 6710 tcase_add_test(tc_basic, test_good_cdata_utf16_le); 6711 tcase_add_test(tc_basic, test_long_cdata_utf16); 6712 tcase_add_test(tc_basic, test_multichar_cdata_utf16); 6713 tcase_add_test(tc_basic, test_utf16_bad_surrogate_pair); 6714 tcase_add_test(tc_basic, test_bad_cdata); 6715 tcase_add_test(tc_basic, test_bad_cdata_utf16); 6716 tcase_add_test(tc_basic, test_stop_parser_between_cdata_calls); 6717 tcase_add_test(tc_basic, test_suspend_parser_between_cdata_calls); 6718 tcase_add_test(tc_basic, test_memory_allocation); 6719 tcase_add_test__if_xml_ge(tc_basic, test_default_current); 6720 tcase_add_test(tc_basic, test_dtd_elements); 6721 tcase_add_test(tc_basic, test_dtd_elements_nesting); 6722 tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd); 6723 tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_not_standalone); 6724 tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_foreign_dtd); 6725 tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_with_doctype); 6726 tcase_add_test__ifdef_xml_dtd(tc_basic, 6727 test_foreign_dtd_without_external_subset); 6728 tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_foreign_dtd); 6729 tcase_add_test(tc_basic, test_set_base); 6730 tcase_add_test(tc_basic, test_attributes); 6731 tcase_add_test(tc_basic, test_duplicate_cdata_attribute); 6732 tcase_add_test(tc_basic, test_duplicate_id_attribute_1); 6733 tcase_add_test(tc_basic, test_duplicate_id_attribute_2); 6734 tcase_add_test(tc_basic, test_duplicate_cdata_attribute_multiple_attlistdecl); 6735 tcase_add_test(tc_basic, 6736 test_duplicate_cdata_attribute_multiple_attlistdecl_2); 6737 tcase_add_test(tc_basic, 6738 test_duplicate_cdata_attribute_multiple_attlistdecl_3); 6739 tcase_add_test(tc_basic, test_duplicate_id_attribute_multiple_attlistdecl); 6740 tcase_add_test__if_xml_ge(tc_basic, test_reset_in_entity); 6741 tcase_add_test(tc_basic, test_resume_invalid_parse); 6742 tcase_add_test(tc_basic, test_resume_resuspended); 6743 tcase_add_test(tc_basic, test_cdata_default); 6744 tcase_add_test(tc_basic, test_subordinate_reset); 6745 tcase_add_test(tc_basic, test_subordinate_suspend); 6746 tcase_add_test__if_xml_ge(tc_basic, test_subordinate_xdecl_suspend); 6747 tcase_add_test__if_xml_ge(tc_basic, test_subordinate_xdecl_abort); 6748 tcase_add_test__ifdef_xml_dtd(tc_basic, 6749 test_ext_entity_invalid_suspended_parse); 6750 tcase_add_test(tc_basic, test_explicit_encoding); 6751 tcase_add_test(tc_basic, test_trailing_cr); 6752 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_trailing_cr); 6753 tcase_add_test(tc_basic, test_trailing_rsqb); 6754 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_trailing_rsqb); 6755 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_good_cdata); 6756 tcase_add_test__ifdef_xml_dtd(tc_basic, test_user_parameters); 6757 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_ref_parameter); 6758 tcase_add_test(tc_basic, test_empty_parse); 6759 tcase_add_test(tc_basic, test_negative_len_parse); 6760 tcase_add_test(tc_basic, test_negative_len_parse_buffer); 6761 tcase_add_test(tc_basic, test_get_buffer_1); 6762 tcase_add_test(tc_basic, test_get_buffer_2); 6763 #if XML_CONTEXT_BYTES > 0 6764 tcase_add_test(tc_basic, test_get_buffer_3_overflow); 6765 #endif 6766 tcase_add_test(tc_basic, test_buffer_can_grow_to_max); 6767 tcase_add_test(tc_basic, test_getbuffer_allocates_on_zero_len); 6768 tcase_add_test(tc_basic, test_byte_info_at_end); 6769 tcase_add_test(tc_basic, test_byte_info_at_error); 6770 tcase_add_test(tc_basic, test_byte_info_at_cdata); 6771 tcase_add_test(tc_basic, test_predefined_entities); 6772 tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_tag_in_dtd); 6773 tcase_add_test(tc_basic, test_not_predefined_entities); 6774 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section); 6775 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section_utf16); 6776 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section_utf16_be); 6777 tcase_add_test__ifdef_xml_dtd(tc_basic, test_bad_ignore_section); 6778 tcase_add_test__ifdef_xml_dtd(tc_basic, test_external_bom_consumed); 6779 tcase_add_test__ifdef_xml_dtd(tc_basic, test_external_entity_values); 6780 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_not_standalone); 6781 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_value_abort); 6782 tcase_add_test(tc_basic, test_bad_public_doctype); 6783 tcase_add_test(tc_basic, test_attribute_enum_value); 6784 tcase_add_test(tc_basic, test_predefined_entity_redefinition); 6785 tcase_add_test__ifdef_xml_dtd(tc_basic, test_dtd_stop_processing); 6786 tcase_add_test(tc_basic, test_public_notation_no_sysid); 6787 tcase_add_test(tc_basic, test_nested_groups); 6788 tcase_add_test(tc_basic, test_group_choice); 6789 tcase_add_test(tc_basic, test_standalone_parameter_entity); 6790 tcase_add_test__ifdef_xml_dtd(tc_basic, test_skipped_parameter_entity); 6791 tcase_add_test__ifdef_xml_dtd(tc_basic, 6792 test_recursive_external_parameter_entity); 6793 tcase_add_test__ifdef_xml_dtd(tc_basic, 6794 test_recursive_external_parameter_entity_2); 6795 tcase_add_test(tc_basic, test_undefined_ext_entity_in_external_dtd); 6796 tcase_add_test(tc_basic, test_suspend_xdecl); 6797 tcase_add_test(tc_basic, test_abort_epilog); 6798 tcase_add_test(tc_basic, test_abort_epilog_2); 6799 tcase_add_test(tc_basic, test_suspend_epilog); 6800 tcase_add_test(tc_basic, test_suspend_in_sole_empty_tag); 6801 tcase_add_test(tc_basic, test_unfinished_epilog); 6802 tcase_add_test(tc_basic, test_partial_char_in_epilog); 6803 tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_internal_entity); 6804 tcase_add_test__ifdef_xml_dtd(tc_basic, 6805 test_suspend_resume_internal_entity_issue_629); 6806 tcase_add_test__ifdef_xml_dtd(tc_basic, test_resume_entity_with_syntax_error); 6807 tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_parameter_entity); 6808 tcase_add_test(tc_basic, test_restart_on_error); 6809 tcase_add_test(tc_basic, test_reject_lt_in_attribute_value); 6810 tcase_add_test(tc_basic, test_reject_unfinished_param_in_att_value); 6811 tcase_add_test(tc_basic, test_trailing_cr_in_att_value); 6812 tcase_add_test(tc_basic, test_standalone_internal_entity); 6813 tcase_add_test(tc_basic, test_skipped_external_entity); 6814 tcase_add_test__ifdef_xml_dtd( 6815 tc_basic, test_scaff_index_shared_across_external_entity_parser); 6816 tcase_add_test(tc_basic, test_skipped_null_loaded_ext_entity); 6817 tcase_add_test(tc_basic, test_skipped_unloaded_ext_entity); 6818 tcase_add_test__ifdef_xml_dtd(tc_basic, test_param_entity_with_trailing_cr); 6819 tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity); 6820 tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_2); 6821 tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_3); 6822 tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_4); 6823 tcase_add_test(tc_basic, test_pi_handled_in_default); 6824 tcase_add_test(tc_basic, test_comment_handled_in_default); 6825 tcase_add_test(tc_basic, test_pi_yml); 6826 tcase_add_test(tc_basic, test_pi_xnl); 6827 tcase_add_test(tc_basic, test_pi_xmm); 6828 tcase_add_test(tc_basic, test_utf16_pi); 6829 tcase_add_test(tc_basic, test_utf16_be_pi); 6830 tcase_add_test(tc_basic, test_utf16_be_comment); 6831 tcase_add_test(tc_basic, test_utf16_le_comment); 6832 tcase_add_test(tc_basic, test_missing_encoding_conversion_fn); 6833 tcase_add_test(tc_basic, test_failing_encoding_conversion_fn); 6834 tcase_add_test(tc_basic, test_unknown_encoding_success); 6835 tcase_add_test(tc_basic, test_unknown_encoding_bad_name); 6836 tcase_add_test(tc_basic, test_unknown_encoding_bad_name_2); 6837 tcase_add_test(tc_basic, test_unknown_encoding_long_name_1); 6838 tcase_add_test(tc_basic, test_unknown_encoding_long_name_2); 6839 tcase_add_test(tc_basic, test_invalid_unknown_encoding); 6840 tcase_add_test(tc_basic, test_unknown_ascii_encoding_ok); 6841 tcase_add_test(tc_basic, test_unknown_ascii_encoding_fail); 6842 tcase_add_test(tc_basic, test_unknown_encoding_invalid_length); 6843 tcase_add_test(tc_basic, test_unknown_encoding_invalid_topbit); 6844 tcase_add_test(tc_basic, test_unknown_encoding_invalid_surrogate); 6845 tcase_add_test(tc_basic, test_unknown_encoding_invalid_high); 6846 tcase_add_test(tc_basic, test_unknown_encoding_invalid_attr_value); 6847 tcase_add_test(tc_basic, test_unknown_encoding_user_data_primary); 6848 tcase_add_test(tc_basic, test_unknown_encoding_user_data_secondary); 6849 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16le_bom); 6850 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16be_bom); 6851 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16le_bom2); 6852 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16be_bom2); 6853 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_be); 6854 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_le); 6855 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_unknown); 6856 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf8_non_bom); 6857 tcase_add_test(tc_basic, test_utf8_in_cdata_section); 6858 tcase_add_test(tc_basic, test_utf8_in_cdata_section_2); 6859 tcase_add_test(tc_basic, test_utf8_in_start_tags); 6860 tcase_add_test(tc_basic, test_trailing_spaces_in_elements); 6861 tcase_add_test(tc_basic, test_utf16_attribute); 6862 tcase_add_test(tc_basic, test_utf16_second_attr); 6863 tcase_add_test(tc_basic, test_attr_after_solidus); 6864 tcase_add_test__ifdef_xml_dtd(tc_basic, test_utf16_pe); 6865 tcase_add_test(tc_basic, test_bad_attr_desc_keyword); 6866 tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16); 6867 tcase_add_test(tc_basic, test_bad_doctype); 6868 tcase_add_test(tc_basic, test_bad_doctype_utf8); 6869 tcase_add_test(tc_basic, test_bad_doctype_utf16); 6870 tcase_add_test(tc_basic, test_bad_doctype_plus); 6871 tcase_add_test(tc_basic, test_bad_doctype_star); 6872 tcase_add_test(tc_basic, test_bad_doctype_query); 6873 tcase_add_test__ifdef_xml_dtd(tc_basic, test_unknown_encoding_bad_ignore); 6874 tcase_add_test(tc_basic, test_entity_in_utf16_be_attr); 6875 tcase_add_test(tc_basic, test_entity_in_utf16_le_attr); 6876 tcase_add_test__ifdef_xml_dtd(tc_basic, test_entity_public_utf16_be); 6877 tcase_add_test__ifdef_xml_dtd(tc_basic, test_entity_public_utf16_le); 6878 tcase_add_test(tc_basic, test_short_doctype); 6879 tcase_add_test(tc_basic, test_short_doctype_2); 6880 tcase_add_test(tc_basic, test_short_doctype_3); 6881 tcase_add_test(tc_basic, test_long_doctype); 6882 tcase_add_test(tc_basic, test_bad_entity); 6883 tcase_add_test(tc_basic, test_bad_entity_2); 6884 tcase_add_test(tc_basic, test_bad_entity_3); 6885 tcase_add_test(tc_basic, test_bad_entity_4); 6886 tcase_add_test(tc_basic, test_bad_notation); 6887 tcase_add_test(tc_basic, test_default_doctype_handler); 6888 tcase_add_test(tc_basic, test_empty_element_abort); 6889 tcase_add_test__ifdef_xml_dtd(tc_basic, 6890 test_pool_integrity_with_unfinished_attr); 6891 tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_ext_param_entity_in_value); 6892 tcase_add_test__if_xml_ge(tc_basic, test_entity_ref_no_elements); 6893 tcase_add_test__if_xml_ge(tc_basic, test_deep_nested_entity); 6894 tcase_add_test__if_xml_ge(tc_basic, test_deep_nested_attribute_entity); 6895 tcase_add_test__if_xml_ge(tc_basic, 6896 test_deep_nested_entity_delayed_interpretation); 6897 tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend); 6898 tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend_2); 6899 tcase_add_test(tc_basic, test_big_tokens_scale_linearly); 6900 tcase_add_test(tc_basic, test_set_reparse_deferral); 6901 tcase_add_test(tc_basic, test_reparse_deferral_is_inherited); 6902 tcase_add_test(tc_basic, test_set_reparse_deferral_on_null_parser); 6903 tcase_add_test(tc_basic, test_set_reparse_deferral_on_the_fly); 6904 tcase_add_test(tc_basic, test_set_bad_reparse_option); 6905 tcase_add_test(tc_basic, test_bypass_heuristic_when_close_to_bufsize); 6906 tcase_add_test(tc_basic, test_varying_buffer_fills); 6907 } 6908