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