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