xref: /freebsd/contrib/expat/tests/runtests.c (revision 13ec1e3155c7e9bf037b12af186351b7fa9b9450)
1 /* Run 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 <ssolie@users.sourceforge.net>
12    Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
13    Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
14    Copyright (c) 2017-2018 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      Dong-hee Na <donghee.na@python.org>
21    Licensed under the MIT license:
22 
23    Permission is  hereby granted,  free of charge,  to any  person obtaining
24    a  copy  of  this  software   and  associated  documentation  files  (the
25    "Software"),  to  deal in  the  Software  without restriction,  including
26    without  limitation the  rights  to use,  copy,  modify, merge,  publish,
27    distribute, sublicense, and/or sell copies of the Software, and to permit
28    persons  to whom  the Software  is  furnished to  do so,  subject to  the
29    following conditions:
30 
31    The above copyright  notice and this permission notice  shall be included
32    in all copies or substantial portions of the Software.
33 
34    THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
35    EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
36    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
37    NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
38    DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
39    OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
40    USE OR OTHER DEALINGS IN THE SOFTWARE.
41 */
42 
43 #include <expat_config.h>
44 
45 #if defined(NDEBUG)
46 #  undef NDEBUG /* because test suite relies on assert(...) at the moment */
47 #endif
48 
49 #include <assert.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <stddef.h> /* ptrdiff_t */
54 #include <ctype.h>
55 #include <limits.h>
56 #include <stdint.h> /* intptr_t uint64_t */
57 #include <math.h>   /* NAN, INFINITY, isnan */
58 
59 #if ! defined(__cplusplus)
60 #  include <stdbool.h>
61 #endif
62 
63 #include "expat.h"
64 #include "chardata.h"
65 #include "structdata.h"
66 #include "internal.h"
67 #include "minicheck.h"
68 #include "memcheck.h"
69 #include "siphash.h"
70 #include "ascii.h" /* for ASCII_xxx */
71 
72 #ifdef XML_LARGE_SIZE
73 #  define XML_FMT_INT_MOD "ll"
74 #else
75 #  define XML_FMT_INT_MOD "l"
76 #endif
77 
78 #ifdef XML_UNICODE_WCHAR_T
79 #  define XML_FMT_CHAR "lc"
80 #  define XML_FMT_STR "ls"
81 #  include <wchar.h>
82 #  define xcstrlen(s) wcslen(s)
83 #  define xcstrcmp(s, t) wcscmp((s), (t))
84 #  define xcstrncmp(s, t, n) wcsncmp((s), (t), (n))
85 #  define XCS(s) _XCS(s)
86 #  define _XCS(s) L##s
87 #else
88 #  ifdef XML_UNICODE
89 #    error "No support for UTF-16 character without wchar_t in tests"
90 #  else
91 #    define XML_FMT_CHAR "c"
92 #    define XML_FMT_STR "s"
93 #    define xcstrlen(s) strlen(s)
94 #    define xcstrcmp(s, t) strcmp((s), (t))
95 #    define xcstrncmp(s, t, n) strncmp((s), (t), (n))
96 #    define XCS(s) s
97 #  endif /* XML_UNICODE */
98 #endif   /* XML_UNICODE_WCHAR_T */
99 
100 static XML_Parser g_parser = NULL;
101 
102 static void
103 tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test) {
104 #ifdef XML_DTD
105   tcase_add_test(tc, test);
106 #else
107   UNUSED_P(tc);
108   UNUSED_P(test);
109 #endif
110 }
111 
112 static void
113 basic_setup(void) {
114   g_parser = XML_ParserCreate(NULL);
115   if (g_parser == NULL)
116     fail("Parser not created.");
117 }
118 
119 static void
120 basic_teardown(void) {
121   if (g_parser != NULL) {
122     XML_ParserFree(g_parser);
123     g_parser = NULL;
124   }
125 }
126 
127 /* Generate a failure using the parser state to create an error message;
128    this should be used when the parser reports an error we weren't
129    expecting.
130 */
131 static void
132 _xml_failure(XML_Parser parser, const char *file, int line) {
133   char buffer[1024];
134   enum XML_Error err = XML_GetErrorCode(parser);
135   sprintf(buffer,
136           "    %d: %" XML_FMT_STR " (line %" XML_FMT_INT_MOD
137           "u, offset %" XML_FMT_INT_MOD "u)\n    reported from %s, line %d\n",
138           err, XML_ErrorString(err), XML_GetCurrentLineNumber(parser),
139           XML_GetCurrentColumnNumber(parser), file, line);
140   _fail_unless(0, file, line, buffer);
141 }
142 
143 static enum XML_Status
144 _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len,
145                         int isFinal) {
146   enum XML_Status res = XML_STATUS_ERROR;
147   int offset = 0;
148 
149   if (len == 0) {
150     return XML_Parse(parser, s, len, isFinal);
151   }
152 
153   for (; offset < len; offset++) {
154     const int innerIsFinal = (offset == len - 1) && isFinal;
155     const char c = s[offset]; /* to help out-of-bounds detection */
156     res = XML_Parse(parser, &c, sizeof(char), innerIsFinal);
157     if (res != XML_STATUS_OK) {
158       return res;
159     }
160   }
161   return res;
162 }
163 
164 #define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
165 
166 static void
167 _expect_failure(const char *text, enum XML_Error errorCode,
168                 const char *errorMessage, const char *file, int lineno) {
169   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
170       == XML_STATUS_OK)
171     /* Hackish use of _fail_unless() macro, but let's us report
172        the right filename and line number. */
173     _fail_unless(0, file, lineno, errorMessage);
174   if (XML_GetErrorCode(g_parser) != errorCode)
175     _xml_failure(g_parser, file, lineno);
176 }
177 
178 #define expect_failure(text, errorCode, errorMessage)                          \
179   _expect_failure((text), (errorCode), (errorMessage), __FILE__, __LINE__)
180 
181 /* Dummy handlers for when we need to set a handler to tickle a bug,
182    but it doesn't need to do anything.
183 */
184 static unsigned long dummy_handler_flags = 0;
185 
186 #define DUMMY_START_DOCTYPE_HANDLER_FLAG (1UL << 0)
187 #define DUMMY_END_DOCTYPE_HANDLER_FLAG (1UL << 1)
188 #define DUMMY_ENTITY_DECL_HANDLER_FLAG (1UL << 2)
189 #define DUMMY_NOTATION_DECL_HANDLER_FLAG (1UL << 3)
190 #define DUMMY_ELEMENT_DECL_HANDLER_FLAG (1UL << 4)
191 #define DUMMY_ATTLIST_DECL_HANDLER_FLAG (1UL << 5)
192 #define DUMMY_COMMENT_HANDLER_FLAG (1UL << 6)
193 #define DUMMY_PI_HANDLER_FLAG (1UL << 7)
194 #define DUMMY_START_ELEMENT_HANDLER_FLAG (1UL << 8)
195 #define DUMMY_START_CDATA_HANDLER_FLAG (1UL << 9)
196 #define DUMMY_END_CDATA_HANDLER_FLAG (1UL << 10)
197 #define DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG (1UL << 11)
198 #define DUMMY_START_NS_DECL_HANDLER_FLAG (1UL << 12)
199 #define DUMMY_END_NS_DECL_HANDLER_FLAG (1UL << 13)
200 #define DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG (1UL << 14)
201 #define DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG (1UL << 15)
202 #define DUMMY_SKIP_HANDLER_FLAG (1UL << 16)
203 #define DUMMY_DEFAULT_HANDLER_FLAG (1UL << 17)
204 
205 static void XMLCALL
206 dummy_xdecl_handler(void *userData, const XML_Char *version,
207                     const XML_Char *encoding, int standalone) {
208   UNUSED_P(userData);
209   UNUSED_P(version);
210   UNUSED_P(encoding);
211   UNUSED_P(standalone);
212 }
213 
214 static void XMLCALL
215 dummy_start_doctype_handler(void *userData, const XML_Char *doctypeName,
216                             const XML_Char *sysid, const XML_Char *pubid,
217                             int has_internal_subset) {
218   UNUSED_P(userData);
219   UNUSED_P(doctypeName);
220   UNUSED_P(sysid);
221   UNUSED_P(pubid);
222   UNUSED_P(has_internal_subset);
223   dummy_handler_flags |= DUMMY_START_DOCTYPE_HANDLER_FLAG;
224 }
225 
226 static void XMLCALL
227 dummy_end_doctype_handler(void *userData) {
228   UNUSED_P(userData);
229   dummy_handler_flags |= DUMMY_END_DOCTYPE_HANDLER_FLAG;
230 }
231 
232 static void XMLCALL
233 dummy_entity_decl_handler(void *userData, const XML_Char *entityName,
234                           int is_parameter_entity, const XML_Char *value,
235                           int value_length, const XML_Char *base,
236                           const XML_Char *systemId, const XML_Char *publicId,
237                           const XML_Char *notationName) {
238   UNUSED_P(userData);
239   UNUSED_P(entityName);
240   UNUSED_P(is_parameter_entity);
241   UNUSED_P(value);
242   UNUSED_P(value_length);
243   UNUSED_P(base);
244   UNUSED_P(systemId);
245   UNUSED_P(publicId);
246   UNUSED_P(notationName);
247   dummy_handler_flags |= DUMMY_ENTITY_DECL_HANDLER_FLAG;
248 }
249 
250 static void XMLCALL
251 dummy_notation_decl_handler(void *userData, const XML_Char *notationName,
252                             const XML_Char *base, const XML_Char *systemId,
253                             const XML_Char *publicId) {
254   UNUSED_P(userData);
255   UNUSED_P(notationName);
256   UNUSED_P(base);
257   UNUSED_P(systemId);
258   UNUSED_P(publicId);
259   dummy_handler_flags |= DUMMY_NOTATION_DECL_HANDLER_FLAG;
260 }
261 
262 static void XMLCALL
263 dummy_element_decl_handler(void *userData, const XML_Char *name,
264                            XML_Content *model) {
265   UNUSED_P(userData);
266   UNUSED_P(name);
267   /* The content model must be freed by the handler.  Unfortunately
268    * we cannot pass the parser as the userData because this is used
269    * with other handlers that require other userData.
270    */
271   XML_FreeContentModel(g_parser, model);
272   dummy_handler_flags |= DUMMY_ELEMENT_DECL_HANDLER_FLAG;
273 }
274 
275 static void XMLCALL
276 dummy_attlist_decl_handler(void *userData, const XML_Char *elname,
277                            const XML_Char *attname, const XML_Char *att_type,
278                            const XML_Char *dflt, int isrequired) {
279   UNUSED_P(userData);
280   UNUSED_P(elname);
281   UNUSED_P(attname);
282   UNUSED_P(att_type);
283   UNUSED_P(dflt);
284   UNUSED_P(isrequired);
285   dummy_handler_flags |= DUMMY_ATTLIST_DECL_HANDLER_FLAG;
286 }
287 
288 static void XMLCALL
289 dummy_comment_handler(void *userData, const XML_Char *data) {
290   UNUSED_P(userData);
291   UNUSED_P(data);
292   dummy_handler_flags |= DUMMY_COMMENT_HANDLER_FLAG;
293 }
294 
295 static void XMLCALL
296 dummy_pi_handler(void *userData, const XML_Char *target, const XML_Char *data) {
297   UNUSED_P(userData);
298   UNUSED_P(target);
299   UNUSED_P(data);
300   dummy_handler_flags |= DUMMY_PI_HANDLER_FLAG;
301 }
302 
303 static void XMLCALL
304 dummy_start_element(void *userData, const XML_Char *name,
305                     const XML_Char **atts) {
306   UNUSED_P(userData);
307   UNUSED_P(name);
308   UNUSED_P(atts);
309   dummy_handler_flags |= DUMMY_START_ELEMENT_HANDLER_FLAG;
310 }
311 
312 static void XMLCALL
313 dummy_end_element(void *userData, const XML_Char *name) {
314   UNUSED_P(userData);
315   UNUSED_P(name);
316 }
317 
318 static void XMLCALL
319 dummy_start_cdata_handler(void *userData) {
320   UNUSED_P(userData);
321   dummy_handler_flags |= DUMMY_START_CDATA_HANDLER_FLAG;
322 }
323 
324 static void XMLCALL
325 dummy_end_cdata_handler(void *userData) {
326   UNUSED_P(userData);
327   dummy_handler_flags |= DUMMY_END_CDATA_HANDLER_FLAG;
328 }
329 
330 static void XMLCALL
331 dummy_cdata_handler(void *userData, const XML_Char *s, int len) {
332   UNUSED_P(userData);
333   UNUSED_P(s);
334   UNUSED_P(len);
335 }
336 
337 static void XMLCALL
338 dummy_start_namespace_decl_handler(void *userData, const XML_Char *prefix,
339                                    const XML_Char *uri) {
340   UNUSED_P(userData);
341   UNUSED_P(prefix);
342   UNUSED_P(uri);
343   dummy_handler_flags |= DUMMY_START_NS_DECL_HANDLER_FLAG;
344 }
345 
346 static void XMLCALL
347 dummy_end_namespace_decl_handler(void *userData, const XML_Char *prefix) {
348   UNUSED_P(userData);
349   UNUSED_P(prefix);
350   dummy_handler_flags |= DUMMY_END_NS_DECL_HANDLER_FLAG;
351 }
352 
353 /* This handler is obsolete, but while the code exists we should
354  * ensure that dealing with the handler is covered by tests.
355  */
356 static void XMLCALL
357 dummy_unparsed_entity_decl_handler(void *userData, const XML_Char *entityName,
358                                    const XML_Char *base,
359                                    const XML_Char *systemId,
360                                    const XML_Char *publicId,
361                                    const XML_Char *notationName) {
362   UNUSED_P(userData);
363   UNUSED_P(entityName);
364   UNUSED_P(base);
365   UNUSED_P(systemId);
366   UNUSED_P(publicId);
367   UNUSED_P(notationName);
368   dummy_handler_flags |= DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG;
369 }
370 
371 static void XMLCALL
372 dummy_default_handler(void *userData, const XML_Char *s, int len) {
373   UNUSED_P(userData);
374   UNUSED_P(s);
375   UNUSED_P(len);
376 }
377 
378 static void XMLCALL
379 dummy_start_doctype_decl_handler(void *userData, const XML_Char *doctypeName,
380                                  const XML_Char *sysid, const XML_Char *pubid,
381                                  int has_internal_subset) {
382   UNUSED_P(userData);
383   UNUSED_P(doctypeName);
384   UNUSED_P(sysid);
385   UNUSED_P(pubid);
386   UNUSED_P(has_internal_subset);
387   dummy_handler_flags |= DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG;
388 }
389 
390 static void XMLCALL
391 dummy_end_doctype_decl_handler(void *userData) {
392   UNUSED_P(userData);
393   dummy_handler_flags |= DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG;
394 }
395 
396 static void XMLCALL
397 dummy_skip_handler(void *userData, const XML_Char *entityName,
398                    int is_parameter_entity) {
399   UNUSED_P(userData);
400   UNUSED_P(entityName);
401   UNUSED_P(is_parameter_entity);
402   dummy_handler_flags |= DUMMY_SKIP_HANDLER_FLAG;
403 }
404 
405 /* Useful external entity handler */
406 typedef struct ExtOption {
407   const XML_Char *system_id;
408   const char *parse_text;
409 } ExtOption;
410 
411 static int XMLCALL
412 external_entity_optioner(XML_Parser parser, const XML_Char *context,
413                          const XML_Char *base, const XML_Char *systemId,
414                          const XML_Char *publicId) {
415   ExtOption *options = (ExtOption *)XML_GetUserData(parser);
416   XML_Parser ext_parser;
417 
418   UNUSED_P(base);
419   UNUSED_P(publicId);
420   while (options->parse_text != NULL) {
421     if (! xcstrcmp(systemId, options->system_id)) {
422       enum XML_Status rc;
423       ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
424       if (ext_parser == NULL)
425         return XML_STATUS_ERROR;
426       rc = _XML_Parse_SINGLE_BYTES(ext_parser, options->parse_text,
427                                    (int)strlen(options->parse_text), XML_TRUE);
428       XML_ParserFree(ext_parser);
429       return rc;
430     }
431     options++;
432   }
433   fail("No suitable option found");
434   return XML_STATUS_ERROR;
435 }
436 
437 /*
438  * Parameter entity evaluation support.
439  */
440 #define ENTITY_MATCH_FAIL (-1)
441 #define ENTITY_MATCH_NOT_FOUND (0)
442 #define ENTITY_MATCH_SUCCESS (1)
443 static const XML_Char *entity_name_to_match = NULL;
444 static const XML_Char *entity_value_to_match = NULL;
445 static int entity_match_flag = ENTITY_MATCH_NOT_FOUND;
446 
447 static void XMLCALL
448 param_entity_match_handler(void *userData, const XML_Char *entityName,
449                            int is_parameter_entity, const XML_Char *value,
450                            int value_length, const XML_Char *base,
451                            const XML_Char *systemId, const XML_Char *publicId,
452                            const XML_Char *notationName) {
453   UNUSED_P(userData);
454   UNUSED_P(base);
455   UNUSED_P(systemId);
456   UNUSED_P(publicId);
457   UNUSED_P(notationName);
458   if (! is_parameter_entity || entity_name_to_match == NULL
459       || entity_value_to_match == NULL) {
460     return;
461   }
462   if (! xcstrcmp(entityName, entity_name_to_match)) {
463     /* The cast here is safe because we control the horizontal and
464      * the vertical, and we therefore know our strings are never
465      * going to overflow an int.
466      */
467     if (value_length != (int)xcstrlen(entity_value_to_match)
468         || xcstrncmp(value, entity_value_to_match, value_length)) {
469       entity_match_flag = ENTITY_MATCH_FAIL;
470     } else {
471       entity_match_flag = ENTITY_MATCH_SUCCESS;
472     }
473   }
474   /* Else leave the match flag alone */
475 }
476 
477 /*
478  * Character & encoding tests.
479  */
480 
481 START_TEST(test_nul_byte) {
482   char text[] = "<doc>\0</doc>";
483 
484   /* test that a NUL byte (in US-ASCII data) is an error */
485   if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
486       == XML_STATUS_OK)
487     fail("Parser did not report error on NUL-byte.");
488   if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
489     xml_failure(g_parser);
490 }
491 END_TEST
492 
493 START_TEST(test_u0000_char) {
494   /* test that a NUL byte (in US-ASCII data) is an error */
495   expect_failure("<doc>&#0;</doc>", XML_ERROR_BAD_CHAR_REF,
496                  "Parser did not report error on NUL-byte.");
497 }
498 END_TEST
499 
500 START_TEST(test_siphash_self) {
501   if (! sip24_valid())
502     fail("SipHash self-test failed");
503 }
504 END_TEST
505 
506 START_TEST(test_siphash_spec) {
507   /* https://131002.net/siphash/siphash.pdf (page 19, "Test values") */
508   const char message[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
509                          "\x0a\x0b\x0c\x0d\x0e";
510   const size_t len = sizeof(message) - 1;
511   const uint64_t expected = _SIP_ULL(0xa129ca61U, 0x49be45e5U);
512   struct siphash state;
513   struct sipkey key;
514 
515   sip_tokey(&key, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
516                   "\x0a\x0b\x0c\x0d\x0e\x0f");
517   sip24_init(&state, &key);
518 
519   /* Cover spread across calls */
520   sip24_update(&state, message, 4);
521   sip24_update(&state, message + 4, len - 4);
522 
523   /* Cover null length */
524   sip24_update(&state, message, 0);
525 
526   if (sip24_final(&state) != expected)
527     fail("sip24_final failed spec test\n");
528 
529   /* Cover wrapper */
530   if (siphash24(message, len, &key) != expected)
531     fail("siphash24 failed spec test\n");
532 }
533 END_TEST
534 
535 START_TEST(test_bom_utf8) {
536   /* This test is really just making sure we don't core on a UTF-8 BOM. */
537   const char *text = "\357\273\277<e/>";
538 
539   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
540       == XML_STATUS_ERROR)
541     xml_failure(g_parser);
542 }
543 END_TEST
544 
545 START_TEST(test_bom_utf16_be) {
546   char text[] = "\376\377\0<\0e\0/\0>";
547 
548   if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
549       == XML_STATUS_ERROR)
550     xml_failure(g_parser);
551 }
552 END_TEST
553 
554 START_TEST(test_bom_utf16_le) {
555   char text[] = "\377\376<\0e\0/\0>\0";
556 
557   if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
558       == XML_STATUS_ERROR)
559     xml_failure(g_parser);
560 }
561 END_TEST
562 
563 /* Parse whole buffer at once to exercise a different code path */
564 START_TEST(test_nobom_utf16_le) {
565   char text[] = " \0<\0e\0/\0>\0";
566 
567   if (XML_Parse(g_parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
568     xml_failure(g_parser);
569 }
570 END_TEST
571 
572 static void XMLCALL
573 accumulate_characters(void *userData, const XML_Char *s, int len) {
574   CharData_AppendXMLChars((CharData *)userData, s, len);
575 }
576 
577 static void XMLCALL
578 accumulate_attribute(void *userData, const XML_Char *name,
579                      const XML_Char **atts) {
580   CharData *storage = (CharData *)userData;
581   UNUSED_P(name);
582   /* Check there are attributes to deal with */
583   if (atts == NULL)
584     return;
585 
586   while (storage->count < 0 && atts[0] != NULL) {
587     /* "accumulate" the value of the first attribute we see */
588     CharData_AppendXMLChars(storage, atts[1], -1);
589     atts += 2;
590   }
591 }
592 
593 static void
594 _run_character_check(const char *text, const XML_Char *expected,
595                      const char *file, int line) {
596   CharData storage;
597 
598   CharData_Init(&storage);
599   XML_SetUserData(g_parser, &storage);
600   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
601   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
602       == XML_STATUS_ERROR)
603     _xml_failure(g_parser, file, line);
604   CharData_CheckXMLChars(&storage, expected);
605 }
606 
607 #define run_character_check(text, expected)                                    \
608   _run_character_check(text, expected, __FILE__, __LINE__)
609 
610 static void
611 _run_attribute_check(const char *text, const XML_Char *expected,
612                      const char *file, int line) {
613   CharData storage;
614 
615   CharData_Init(&storage);
616   XML_SetUserData(g_parser, &storage);
617   XML_SetStartElementHandler(g_parser, accumulate_attribute);
618   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
619       == XML_STATUS_ERROR)
620     _xml_failure(g_parser, file, line);
621   CharData_CheckXMLChars(&storage, expected);
622 }
623 
624 #define run_attribute_check(text, expected)                                    \
625   _run_attribute_check(text, expected, __FILE__, __LINE__)
626 
627 typedef struct ExtTest {
628   const char *parse_text;
629   const XML_Char *encoding;
630   CharData *storage;
631 } ExtTest;
632 
633 static void XMLCALL
634 ext_accumulate_characters(void *userData, const XML_Char *s, int len) {
635   ExtTest *test_data = (ExtTest *)userData;
636   accumulate_characters(test_data->storage, s, len);
637 }
638 
639 static void
640 _run_ext_character_check(const char *text, ExtTest *test_data,
641                          const XML_Char *expected, const char *file, int line) {
642   CharData *const storage = (CharData *)malloc(sizeof(CharData));
643 
644   CharData_Init(storage);
645   test_data->storage = storage;
646   XML_SetUserData(g_parser, test_data);
647   XML_SetCharacterDataHandler(g_parser, ext_accumulate_characters);
648   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
649       == XML_STATUS_ERROR)
650     _xml_failure(g_parser, file, line);
651   CharData_CheckXMLChars(storage, expected);
652 
653   free(storage);
654 }
655 
656 #define run_ext_character_check(text, test_data, expected)                     \
657   _run_ext_character_check(text, test_data, expected, __FILE__, __LINE__)
658 
659 /* Regression test for SF bug #491986. */
660 START_TEST(test_danish_latin1) {
661   const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
662                      "<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>";
663 #ifdef XML_UNICODE
664   const XML_Char *expected
665       = XCS("J\x00f8rgen \x00e6\x00f8\x00e5\x00c6\x00d8\x00c5");
666 #else
667   const XML_Char *expected
668       = XCS("J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
669 #endif
670   run_character_check(text, expected);
671 }
672 END_TEST
673 
674 /* Regression test for SF bug #514281. */
675 START_TEST(test_french_charref_hexidecimal) {
676   const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
677                      "<doc>&#xE9;&#xE8;&#xE0;&#xE7;&#xEA;&#xC8;</doc>";
678 #ifdef XML_UNICODE
679   const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
680 #else
681   const XML_Char *expected
682       = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
683 #endif
684   run_character_check(text, expected);
685 }
686 END_TEST
687 
688 START_TEST(test_french_charref_decimal) {
689   const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
690                      "<doc>&#233;&#232;&#224;&#231;&#234;&#200;</doc>";
691 #ifdef XML_UNICODE
692   const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
693 #else
694   const XML_Char *expected
695       = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
696 #endif
697   run_character_check(text, expected);
698 }
699 END_TEST
700 
701 START_TEST(test_french_latin1) {
702   const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
703                      "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
704 #ifdef XML_UNICODE
705   const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
706 #else
707   const XML_Char *expected
708       = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
709 #endif
710   run_character_check(text, expected);
711 }
712 END_TEST
713 
714 START_TEST(test_french_utf8) {
715   const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
716                      "<doc>\xC3\xA9</doc>";
717 #ifdef XML_UNICODE
718   const XML_Char *expected = XCS("\x00e9");
719 #else
720   const XML_Char *expected = XCS("\xC3\xA9");
721 #endif
722   run_character_check(text, expected);
723 }
724 END_TEST
725 
726 /* Regression test for SF bug #600479.
727    XXX There should be a test that exercises all legal XML Unicode
728    characters as PCDATA and attribute value content, and XML Name
729    characters as part of element and attribute names.
730 */
731 START_TEST(test_utf8_false_rejection) {
732   const char *text = "<doc>\xEF\xBA\xBF</doc>";
733 #ifdef XML_UNICODE
734   const XML_Char *expected = XCS("\xfebf");
735 #else
736   const XML_Char *expected = XCS("\xEF\xBA\xBF");
737 #endif
738   run_character_check(text, expected);
739 }
740 END_TEST
741 
742 /* Regression test for SF bug #477667.
743    This test assures that any 8-bit character followed by a 7-bit
744    character will not be mistakenly interpreted as a valid UTF-8
745    sequence.
746 */
747 START_TEST(test_illegal_utf8) {
748   char text[100];
749   int i;
750 
751   for (i = 128; i <= 255; ++i) {
752     sprintf(text, "<e>%ccd</e>", i);
753     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
754         == XML_STATUS_OK) {
755       sprintf(text, "expected token error for '%c' (ordinal %d) in UTF-8 text",
756               i, i);
757       fail(text);
758     } else if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
759       xml_failure(g_parser);
760     /* Reset the parser since we use the same parser repeatedly. */
761     XML_ParserReset(g_parser, NULL);
762   }
763 }
764 END_TEST
765 
766 /* Examples, not masks: */
767 #define UTF8_LEAD_1 "\x7f" /* 0b01111111 */
768 #define UTF8_LEAD_2 "\xdf" /* 0b11011111 */
769 #define UTF8_LEAD_3 "\xef" /* 0b11101111 */
770 #define UTF8_LEAD_4 "\xf7" /* 0b11110111 */
771 #define UTF8_FOLLOW "\xbf" /* 0b10111111 */
772 
773 START_TEST(test_utf8_auto_align) {
774   struct TestCase {
775     ptrdiff_t expectedMovementInChars;
776     const char *input;
777   };
778 
779   struct TestCase cases[] = {
780       {00, ""},
781 
782       {00, UTF8_LEAD_1},
783 
784       {-1, UTF8_LEAD_2},
785       {00, UTF8_LEAD_2 UTF8_FOLLOW},
786 
787       {-1, UTF8_LEAD_3},
788       {-2, UTF8_LEAD_3 UTF8_FOLLOW},
789       {00, UTF8_LEAD_3 UTF8_FOLLOW UTF8_FOLLOW},
790 
791       {-1, UTF8_LEAD_4},
792       {-2, UTF8_LEAD_4 UTF8_FOLLOW},
793       {-3, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW},
794       {00, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW UTF8_FOLLOW},
795   };
796 
797   size_t i = 0;
798   bool success = true;
799   for (; i < sizeof(cases) / sizeof(*cases); i++) {
800     const char *fromLim = cases[i].input + strlen(cases[i].input);
801     const char *const fromLimInitially = fromLim;
802     ptrdiff_t actualMovementInChars;
803 
804     _INTERNAL_trim_to_complete_utf8_characters(cases[i].input, &fromLim);
805 
806     actualMovementInChars = (fromLim - fromLimInitially);
807     if (actualMovementInChars != cases[i].expectedMovementInChars) {
808       size_t j = 0;
809       success = false;
810       printf("[-] UTF-8 case %2u: Expected movement by %2d chars"
811              ", actually moved by %2d chars: \"",
812              (unsigned)(i + 1), (int)cases[i].expectedMovementInChars,
813              (int)actualMovementInChars);
814       for (; j < strlen(cases[i].input); j++) {
815         printf("\\x%02x", (unsigned char)cases[i].input[j]);
816       }
817       printf("\"\n");
818     }
819   }
820 
821   if (! success) {
822     fail("UTF-8 auto-alignment is not bullet-proof\n");
823   }
824 }
825 END_TEST
826 
827 START_TEST(test_utf16) {
828   /* <?xml version="1.0" encoding="UTF-16"?>
829    *  <doc a='123'>some {A} text</doc>
830    *
831    * where {A} is U+FF21, FULLWIDTH LATIN CAPITAL LETTER A
832    */
833   char text[]
834       = "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
835         "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o"
836         "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066"
837         "\000'\000?\000>\000\n"
838         "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'\000>"
839         "\000s\000o\000m\000e\000 \xff\x21\000 \000t\000e\000x\000t\000"
840         "<\000/\000d\000o\000c\000>";
841 #ifdef XML_UNICODE
842   const XML_Char *expected = XCS("some \xff21 text");
843 #else
844   const XML_Char *expected = XCS("some \357\274\241 text");
845 #endif
846   CharData storage;
847 
848   CharData_Init(&storage);
849   XML_SetUserData(g_parser, &storage);
850   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
851   if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
852       == XML_STATUS_ERROR)
853     xml_failure(g_parser);
854   CharData_CheckXMLChars(&storage, expected);
855 }
856 END_TEST
857 
858 START_TEST(test_utf16_le_epilog_newline) {
859   unsigned int first_chunk_bytes = 17;
860   char text[] = "\xFF\xFE"                  /* BOM */
861                 "<\000e\000/\000>\000"      /* document element */
862                 "\r\000\n\000\r\000\n\000"; /* epilog */
863 
864   if (first_chunk_bytes >= sizeof(text) - 1)
865     fail("bad value of first_chunk_bytes");
866   if (_XML_Parse_SINGLE_BYTES(g_parser, text, first_chunk_bytes, XML_FALSE)
867       == XML_STATUS_ERROR)
868     xml_failure(g_parser);
869   else {
870     enum XML_Status rc;
871     rc = _XML_Parse_SINGLE_BYTES(g_parser, text + first_chunk_bytes,
872                                  sizeof(text) - first_chunk_bytes - 1,
873                                  XML_TRUE);
874     if (rc == XML_STATUS_ERROR)
875       xml_failure(g_parser);
876   }
877 }
878 END_TEST
879 
880 /* Test that an outright lie in the encoding is faulted */
881 START_TEST(test_not_utf16) {
882   const char *text = "<?xml version='1.0' encoding='utf-16'?>"
883                      "<doc>Hi</doc>";
884 
885   /* Use a handler to provoke the appropriate code paths */
886   XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
887   expect_failure(text, XML_ERROR_INCORRECT_ENCODING,
888                  "UTF-16 declared in UTF-8 not faulted");
889 }
890 END_TEST
891 
892 /* Test that an unknown encoding is rejected */
893 START_TEST(test_bad_encoding) {
894   const char *text = "<doc>Hi</doc>";
895 
896   if (! XML_SetEncoding(g_parser, XCS("unknown-encoding")))
897     fail("XML_SetEncoding failed");
898   expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
899                  "Unknown encoding not faulted");
900 }
901 END_TEST
902 
903 /* Regression test for SF bug #481609, #774028. */
904 START_TEST(test_latin1_umlauts) {
905   const char *text
906       = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
907         "<e a='\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; >'\n"
908         "  >\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; ></e>";
909 #ifdef XML_UNICODE
910   /* Expected results in UTF-16 */
911   const XML_Char *expected = XCS("\x00e4 \x00f6 \x00fc ")
912       XCS("\x00e4 \x00f6 \x00fc ") XCS("\x00e4 \x00f6 \x00fc >");
913 #else
914   /* Expected results in UTF-8 */
915   const XML_Char *expected = XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ")
916       XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ") XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC >");
917 #endif
918 
919   run_character_check(text, expected);
920   XML_ParserReset(g_parser, NULL);
921   run_attribute_check(text, expected);
922   /* Repeat with a default handler */
923   XML_ParserReset(g_parser, NULL);
924   XML_SetDefaultHandler(g_parser, dummy_default_handler);
925   run_character_check(text, expected);
926   XML_ParserReset(g_parser, NULL);
927   XML_SetDefaultHandler(g_parser, dummy_default_handler);
928   run_attribute_check(text, expected);
929 }
930 END_TEST
931 
932 /* Test that an element name with a 4-byte UTF-8 character is rejected */
933 START_TEST(test_long_utf8_character) {
934   const char *text
935       = "<?xml version='1.0' encoding='utf-8'?>\n"
936         /* 0xf0 0x90 0x80 0x80 = U+10000, the first Linear B character */
937         "<do\xf0\x90\x80\x80/>";
938   expect_failure(text, XML_ERROR_INVALID_TOKEN,
939                  "4-byte UTF-8 character in element name not faulted");
940 }
941 END_TEST
942 
943 /* Test that a long latin-1 attribute (too long to convert in one go)
944  * is correctly converted
945  */
946 START_TEST(test_long_latin1_attribute) {
947   const char *text
948       = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
949         "<doc att='"
950         /* 64 characters per line */
951         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
952         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
953         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
954         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
955         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
956         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
957         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
958         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
959         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
960         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
961         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
962         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
963         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
964         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
965         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
966         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
967         /* Last character splits across a buffer boundary */
968         "\xe4'>\n</doc>";
969 
970   const XML_Char *expected =
971       /* 64 characters per line */
972       /* clang-format off */
973         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
974         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
975         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
976         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
977         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
978         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
979         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
980         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
981         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
982         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
983         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
984         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
985         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
986         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
987         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
988         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO")
989   /* clang-format on */
990 #ifdef XML_UNICODE
991                                                   XCS("\x00e4");
992 #else
993                                                   XCS("\xc3\xa4");
994 #endif
995 
996   run_attribute_check(text, expected);
997 }
998 END_TEST
999 
1000 /* Test that a long ASCII attribute (too long to convert in one go)
1001  * is correctly converted
1002  */
1003 START_TEST(test_long_ascii_attribute) {
1004   const char *text
1005       = "<?xml version='1.0' encoding='us-ascii'?>\n"
1006         "<doc att='"
1007         /* 64 characters per line */
1008         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1009         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1010         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1011         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1012         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1013         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1014         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1015         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1016         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1017         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1018         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1019         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1020         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1021         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1022         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1023         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
1024         "01234'>\n</doc>";
1025   const XML_Char *expected =
1026       /* 64 characters per line */
1027       /* clang-format off */
1028         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1029         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1030         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1031         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1032         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1033         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1034         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1035         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1036         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1037         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1038         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1039         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1040         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1041         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1042         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1043         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1044         XCS("01234");
1045   /* clang-format on */
1046 
1047   run_attribute_check(text, expected);
1048 }
1049 END_TEST
1050 
1051 /* Regression test #1 for SF bug #653180. */
1052 START_TEST(test_line_number_after_parse) {
1053   const char *text = "<tag>\n"
1054                      "\n"
1055                      "\n</tag>";
1056   XML_Size lineno;
1057 
1058   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
1059       == XML_STATUS_ERROR)
1060     xml_failure(g_parser);
1061   lineno = XML_GetCurrentLineNumber(g_parser);
1062   if (lineno != 4) {
1063     char buffer[100];
1064     sprintf(buffer, "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno);
1065     fail(buffer);
1066   }
1067 }
1068 END_TEST
1069 
1070 /* Regression test #2 for SF bug #653180. */
1071 START_TEST(test_column_number_after_parse) {
1072   const char *text = "<tag></tag>";
1073   XML_Size colno;
1074 
1075   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
1076       == XML_STATUS_ERROR)
1077     xml_failure(g_parser);
1078   colno = XML_GetCurrentColumnNumber(g_parser);
1079   if (colno != 11) {
1080     char buffer[100];
1081     sprintf(buffer, "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno);
1082     fail(buffer);
1083   }
1084 }
1085 END_TEST
1086 
1087 #define STRUCT_START_TAG 0
1088 #define STRUCT_END_TAG 1
1089 static void XMLCALL
1090 start_element_event_handler2(void *userData, const XML_Char *name,
1091                              const XML_Char **attr) {
1092   StructData *storage = (StructData *)userData;
1093   UNUSED_P(attr);
1094   StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser),
1095                      XML_GetCurrentLineNumber(g_parser), STRUCT_START_TAG);
1096 }
1097 
1098 static void XMLCALL
1099 end_element_event_handler2(void *userData, const XML_Char *name) {
1100   StructData *storage = (StructData *)userData;
1101   StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser),
1102                      XML_GetCurrentLineNumber(g_parser), STRUCT_END_TAG);
1103 }
1104 
1105 /* Regression test #3 for SF bug #653180. */
1106 START_TEST(test_line_and_column_numbers_inside_handlers) {
1107   const char *text = "<a>\n"      /* Unix end-of-line */
1108                      "  <b>\r\n"  /* Windows end-of-line */
1109                      "    <c/>\r" /* Mac OS end-of-line */
1110                      "  </b>\n"
1111                      "  <d>\n"
1112                      "    <f/>\n"
1113                      "  </d>\n"
1114                      "</a>";
1115   const StructDataEntry expected[]
1116       = {{XCS("a"), 0, 1, STRUCT_START_TAG}, {XCS("b"), 2, 2, STRUCT_START_TAG},
1117          {XCS("c"), 4, 3, STRUCT_START_TAG}, {XCS("c"), 8, 3, STRUCT_END_TAG},
1118          {XCS("b"), 2, 4, STRUCT_END_TAG},   {XCS("d"), 2, 5, STRUCT_START_TAG},
1119          {XCS("f"), 4, 6, STRUCT_START_TAG}, {XCS("f"), 8, 6, STRUCT_END_TAG},
1120          {XCS("d"), 2, 7, STRUCT_END_TAG},   {XCS("a"), 0, 8, STRUCT_END_TAG}};
1121   const int expected_count = sizeof(expected) / sizeof(StructDataEntry);
1122   StructData storage;
1123 
1124   StructData_Init(&storage);
1125   XML_SetUserData(g_parser, &storage);
1126   XML_SetStartElementHandler(g_parser, start_element_event_handler2);
1127   XML_SetEndElementHandler(g_parser, end_element_event_handler2);
1128   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1129       == XML_STATUS_ERROR)
1130     xml_failure(g_parser);
1131 
1132   StructData_CheckItems(&storage, expected, expected_count);
1133   StructData_Dispose(&storage);
1134 }
1135 END_TEST
1136 
1137 /* Regression test #4 for SF bug #653180. */
1138 START_TEST(test_line_number_after_error) {
1139   const char *text = "<a>\n"
1140                      "  <b>\n"
1141                      "  </a>"; /* missing </b> */
1142   XML_Size lineno;
1143   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
1144       != XML_STATUS_ERROR)
1145     fail("Expected a parse error");
1146 
1147   lineno = XML_GetCurrentLineNumber(g_parser);
1148   if (lineno != 3) {
1149     char buffer[100];
1150     sprintf(buffer, "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno);
1151     fail(buffer);
1152   }
1153 }
1154 END_TEST
1155 
1156 /* Regression test #5 for SF bug #653180. */
1157 START_TEST(test_column_number_after_error) {
1158   const char *text = "<a>\n"
1159                      "  <b>\n"
1160                      "  </a>"; /* missing </b> */
1161   XML_Size colno;
1162   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
1163       != XML_STATUS_ERROR)
1164     fail("Expected a parse error");
1165 
1166   colno = XML_GetCurrentColumnNumber(g_parser);
1167   if (colno != 4) {
1168     char buffer[100];
1169     sprintf(buffer, "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno);
1170     fail(buffer);
1171   }
1172 }
1173 END_TEST
1174 
1175 /* Regression test for SF bug #478332. */
1176 START_TEST(test_really_long_lines) {
1177   /* This parses an input line longer than INIT_DATA_BUF_SIZE
1178      characters long (defined to be 1024 in xmlparse.c).  We take a
1179      really cheesy approach to building the input buffer, because
1180      this avoids writing bugs in buffer-filling code.
1181   */
1182   const char *text
1183       = "<e>"
1184         /* 64 chars */
1185         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1186         /* until we have at least 1024 characters on the line: */
1187         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1188         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1189         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1190         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1191         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1192         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1193         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1194         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1195         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1196         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1197         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1198         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1199         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1200         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1201         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1202         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1203         "</e>";
1204   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1205       == XML_STATUS_ERROR)
1206     xml_failure(g_parser);
1207 }
1208 END_TEST
1209 
1210 /* Test cdata processing across a buffer boundary */
1211 START_TEST(test_really_long_encoded_lines) {
1212   /* As above, except that we want to provoke an output buffer
1213    * overflow with a non-trivial encoding.  For this we need to pass
1214    * the whole cdata in one go, not byte-by-byte.
1215    */
1216   void *buffer;
1217   const char *text
1218       = "<?xml version='1.0' encoding='iso-8859-1'?>"
1219         "<e>"
1220         /* 64 chars */
1221         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1222         /* until we have at least 1024 characters on the line: */
1223         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1224         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1225         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1226         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1227         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1228         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1229         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1230         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1231         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1232         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1233         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1234         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1235         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1236         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1237         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1238         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1239         "</e>";
1240   int parse_len = (int)strlen(text);
1241 
1242   /* Need a cdata handler to provoke the code path we want to test */
1243   XML_SetCharacterDataHandler(g_parser, dummy_cdata_handler);
1244   buffer = XML_GetBuffer(g_parser, parse_len);
1245   if (buffer == NULL)
1246     fail("Could not allocate parse buffer");
1247   assert(buffer != NULL);
1248   memcpy(buffer, text, parse_len);
1249   if (XML_ParseBuffer(g_parser, parse_len, XML_TRUE) == XML_STATUS_ERROR)
1250     xml_failure(g_parser);
1251 }
1252 END_TEST
1253 
1254 /*
1255  * Element event tests.
1256  */
1257 
1258 static void XMLCALL
1259 start_element_event_handler(void *userData, const XML_Char *name,
1260                             const XML_Char **atts) {
1261   UNUSED_P(atts);
1262   CharData_AppendXMLChars((CharData *)userData, name, -1);
1263 }
1264 
1265 static void XMLCALL
1266 end_element_event_handler(void *userData, const XML_Char *name) {
1267   CharData *storage = (CharData *)userData;
1268   CharData_AppendXMLChars(storage, XCS("/"), 1);
1269   CharData_AppendXMLChars(storage, name, -1);
1270 }
1271 
1272 START_TEST(test_end_element_events) {
1273   const char *text = "<a><b><c/></b><d><f/></d></a>";
1274   const XML_Char *expected = XCS("/c/b/f/d/a");
1275   CharData storage;
1276 
1277   CharData_Init(&storage);
1278   XML_SetUserData(g_parser, &storage);
1279   XML_SetEndElementHandler(g_parser, end_element_event_handler);
1280   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1281       == XML_STATUS_ERROR)
1282     xml_failure(g_parser);
1283   CharData_CheckXMLChars(&storage, expected);
1284 }
1285 END_TEST
1286 
1287 /*
1288  * Attribute tests.
1289  */
1290 
1291 /* Helpers used by the following test; this checks any "attr" and "refs"
1292    attributes to make sure whitespace has been normalized.
1293 
1294    Return true if whitespace has been normalized in a string, using
1295    the rules for attribute value normalization.  The 'is_cdata' flag
1296    is needed since CDATA attributes don't need to have multiple
1297    whitespace characters collapsed to a single space, while other
1298    attribute data types do.  (Section 3.3.3 of the recommendation.)
1299 */
1300 static int
1301 is_whitespace_normalized(const XML_Char *s, int is_cdata) {
1302   int blanks = 0;
1303   int at_start = 1;
1304   while (*s) {
1305     if (*s == XCS(' '))
1306       ++blanks;
1307     else if (*s == XCS('\t') || *s == XCS('\n') || *s == XCS('\r'))
1308       return 0;
1309     else {
1310       if (at_start) {
1311         at_start = 0;
1312         if (blanks && ! is_cdata)
1313           /* illegal leading blanks */
1314           return 0;
1315       } else if (blanks > 1 && ! is_cdata)
1316         return 0;
1317       blanks = 0;
1318     }
1319     ++s;
1320   }
1321   if (blanks && ! is_cdata)
1322     return 0;
1323   return 1;
1324 }
1325 
1326 /* Check the attribute whitespace checker: */
1327 static void
1328 testhelper_is_whitespace_normalized(void) {
1329   assert(is_whitespace_normalized(XCS("abc"), 0));
1330   assert(is_whitespace_normalized(XCS("abc"), 1));
1331   assert(is_whitespace_normalized(XCS("abc def ghi"), 0));
1332   assert(is_whitespace_normalized(XCS("abc def ghi"), 1));
1333   assert(! is_whitespace_normalized(XCS(" abc def ghi"), 0));
1334   assert(is_whitespace_normalized(XCS(" abc def ghi"), 1));
1335   assert(! is_whitespace_normalized(XCS("abc  def ghi"), 0));
1336   assert(is_whitespace_normalized(XCS("abc  def ghi"), 1));
1337   assert(! is_whitespace_normalized(XCS("abc def ghi "), 0));
1338   assert(is_whitespace_normalized(XCS("abc def ghi "), 1));
1339   assert(! is_whitespace_normalized(XCS(" "), 0));
1340   assert(is_whitespace_normalized(XCS(" "), 1));
1341   assert(! is_whitespace_normalized(XCS("\t"), 0));
1342   assert(! is_whitespace_normalized(XCS("\t"), 1));
1343   assert(! is_whitespace_normalized(XCS("\n"), 0));
1344   assert(! is_whitespace_normalized(XCS("\n"), 1));
1345   assert(! is_whitespace_normalized(XCS("\r"), 0));
1346   assert(! is_whitespace_normalized(XCS("\r"), 1));
1347   assert(! is_whitespace_normalized(XCS("abc\t def"), 1));
1348 }
1349 
1350 static void XMLCALL
1351 check_attr_contains_normalized_whitespace(void *userData, const XML_Char *name,
1352                                           const XML_Char **atts) {
1353   int i;
1354   UNUSED_P(userData);
1355   UNUSED_P(name);
1356   for (i = 0; atts[i] != NULL; i += 2) {
1357     const XML_Char *attrname = atts[i];
1358     const XML_Char *value = atts[i + 1];
1359     if (xcstrcmp(XCS("attr"), attrname) == 0
1360         || xcstrcmp(XCS("ents"), attrname) == 0
1361         || xcstrcmp(XCS("refs"), attrname) == 0) {
1362       if (! is_whitespace_normalized(value, 0)) {
1363         char buffer[256];
1364         sprintf(buffer,
1365                 "attribute value not normalized: %" XML_FMT_STR
1366                 "='%" XML_FMT_STR "'",
1367                 attrname, value);
1368         fail(buffer);
1369       }
1370     }
1371   }
1372 }
1373 
1374 START_TEST(test_attr_whitespace_normalization) {
1375   const char *text
1376       = "<!DOCTYPE doc [\n"
1377         "  <!ATTLIST doc\n"
1378         "            attr NMTOKENS #REQUIRED\n"
1379         "            ents ENTITIES #REQUIRED\n"
1380         "            refs IDREFS   #REQUIRED>\n"
1381         "]>\n"
1382         "<doc attr='    a  b c\t\td\te\t' refs=' id-1   \t  id-2\t\t'  \n"
1383         "     ents=' ent-1   \t\r\n"
1384         "            ent-2  ' >\n"
1385         "  <e id='id-1'/>\n"
1386         "  <e id='id-2'/>\n"
1387         "</doc>";
1388 
1389   XML_SetStartElementHandler(g_parser,
1390                              check_attr_contains_normalized_whitespace);
1391   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1392       == XML_STATUS_ERROR)
1393     xml_failure(g_parser);
1394 }
1395 END_TEST
1396 
1397 /*
1398  * XML declaration tests.
1399  */
1400 
1401 START_TEST(test_xmldecl_misplaced) {
1402   expect_failure("\n"
1403                  "<?xml version='1.0'?>\n"
1404                  "<a/>",
1405                  XML_ERROR_MISPLACED_XML_PI,
1406                  "failed to report misplaced XML declaration");
1407 }
1408 END_TEST
1409 
1410 START_TEST(test_xmldecl_invalid) {
1411   expect_failure("<?xml version='1.0' \xc3\xa7?>\n<doc/>", XML_ERROR_XML_DECL,
1412                  "Failed to report invalid XML declaration");
1413 }
1414 END_TEST
1415 
1416 START_TEST(test_xmldecl_missing_attr) {
1417   expect_failure("<?xml ='1.0'?>\n<doc/>\n", XML_ERROR_XML_DECL,
1418                  "Failed to report missing XML declaration attribute");
1419 }
1420 END_TEST
1421 
1422 START_TEST(test_xmldecl_missing_value) {
1423   expect_failure("<?xml version='1.0' encoding='us-ascii' standalone?>\n"
1424                  "<doc/>",
1425                  XML_ERROR_XML_DECL,
1426                  "Failed to report missing attribute value");
1427 }
1428 END_TEST
1429 
1430 /* Regression test for SF bug #584832. */
1431 static int XMLCALL
1432 UnknownEncodingHandler(void *data, const XML_Char *encoding,
1433                        XML_Encoding *info) {
1434   UNUSED_P(data);
1435   if (xcstrcmp(encoding, XCS("unsupported-encoding")) == 0) {
1436     int i;
1437     for (i = 0; i < 256; ++i)
1438       info->map[i] = i;
1439     info->data = NULL;
1440     info->convert = NULL;
1441     info->release = NULL;
1442     return XML_STATUS_OK;
1443   }
1444   return XML_STATUS_ERROR;
1445 }
1446 
1447 START_TEST(test_unknown_encoding_internal_entity) {
1448   const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
1449                      "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
1450                      "<test a='&foo;'/>";
1451 
1452   XML_SetUnknownEncodingHandler(g_parser, UnknownEncodingHandler, NULL);
1453   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1454       == XML_STATUS_ERROR)
1455     xml_failure(g_parser);
1456 }
1457 END_TEST
1458 
1459 /* Test unrecognised encoding handler */
1460 static void
1461 dummy_release(void *data) {
1462   UNUSED_P(data);
1463 }
1464 
1465 static int XMLCALL
1466 UnrecognisedEncodingHandler(void *data, const XML_Char *encoding,
1467                             XML_Encoding *info) {
1468   UNUSED_P(data);
1469   UNUSED_P(encoding);
1470   info->data = NULL;
1471   info->convert = NULL;
1472   info->release = dummy_release;
1473   return XML_STATUS_ERROR;
1474 }
1475 
1476 START_TEST(test_unrecognised_encoding_internal_entity) {
1477   const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
1478                      "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
1479                      "<test a='&foo;'/>";
1480 
1481   XML_SetUnknownEncodingHandler(g_parser, UnrecognisedEncodingHandler, NULL);
1482   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1483       != XML_STATUS_ERROR)
1484     fail("Unrecognised encoding not rejected");
1485 }
1486 END_TEST
1487 
1488 /* Regression test for SF bug #620106. */
1489 static int XMLCALL
1490 external_entity_loader(XML_Parser parser, const XML_Char *context,
1491                        const XML_Char *base, const XML_Char *systemId,
1492                        const XML_Char *publicId) {
1493   ExtTest *test_data = (ExtTest *)XML_GetUserData(parser);
1494   XML_Parser extparser;
1495 
1496   UNUSED_P(base);
1497   UNUSED_P(systemId);
1498   UNUSED_P(publicId);
1499   extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
1500   if (extparser == NULL)
1501     fail("Could not create external entity parser.");
1502   if (test_data->encoding != NULL) {
1503     if (! XML_SetEncoding(extparser, test_data->encoding))
1504       fail("XML_SetEncoding() ignored for external entity");
1505   }
1506   if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
1507                               (int)strlen(test_data->parse_text), XML_TRUE)
1508       == XML_STATUS_ERROR) {
1509     xml_failure(extparser);
1510     return XML_STATUS_ERROR;
1511   }
1512   XML_ParserFree(extparser);
1513   return XML_STATUS_OK;
1514 }
1515 
1516 START_TEST(test_ext_entity_set_encoding) {
1517   const char *text = "<!DOCTYPE doc [\n"
1518                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1519                      "]>\n"
1520                      "<doc>&en;</doc>";
1521   ExtTest test_data
1522       = {/* This text says it's an unsupported encoding, but it's really
1523             UTF-8, which we tell Expat using XML_SetEncoding().
1524          */
1525          "<?xml encoding='iso-8859-3'?>\xC3\xA9", XCS("utf-8"), NULL};
1526 #ifdef XML_UNICODE
1527   const XML_Char *expected = XCS("\x00e9");
1528 #else
1529   const XML_Char *expected = XCS("\xc3\xa9");
1530 #endif
1531 
1532   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1533   run_ext_character_check(text, &test_data, expected);
1534 }
1535 END_TEST
1536 
1537 /* Test external entities with no handler */
1538 START_TEST(test_ext_entity_no_handler) {
1539   const char *text = "<!DOCTYPE doc [\n"
1540                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1541                      "]>\n"
1542                      "<doc>&en;</doc>";
1543 
1544   XML_SetDefaultHandler(g_parser, dummy_default_handler);
1545   run_character_check(text, XCS(""));
1546 }
1547 END_TEST
1548 
1549 /* Test UTF-8 BOM is accepted */
1550 START_TEST(test_ext_entity_set_bom) {
1551   const char *text = "<!DOCTYPE doc [\n"
1552                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1553                      "]>\n"
1554                      "<doc>&en;</doc>";
1555   ExtTest test_data = {"\xEF\xBB\xBF" /* BOM */
1556                        "<?xml encoding='iso-8859-3'?>"
1557                        "\xC3\xA9",
1558                        XCS("utf-8"), NULL};
1559 #ifdef XML_UNICODE
1560   const XML_Char *expected = XCS("\x00e9");
1561 #else
1562   const XML_Char *expected = XCS("\xc3\xa9");
1563 #endif
1564 
1565   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1566   run_ext_character_check(text, &test_data, expected);
1567 }
1568 END_TEST
1569 
1570 /* Test that bad encodings are faulted */
1571 typedef struct ext_faults {
1572   const char *parse_text;
1573   const char *fail_text;
1574   const XML_Char *encoding;
1575   enum XML_Error error;
1576 } ExtFaults;
1577 
1578 static int XMLCALL
1579 external_entity_faulter(XML_Parser parser, const XML_Char *context,
1580                         const XML_Char *base, const XML_Char *systemId,
1581                         const XML_Char *publicId) {
1582   XML_Parser ext_parser;
1583   ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
1584 
1585   UNUSED_P(base);
1586   UNUSED_P(systemId);
1587   UNUSED_P(publicId);
1588   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1589   if (ext_parser == NULL)
1590     fail("Could not create external entity parser");
1591   if (fault->encoding != NULL) {
1592     if (! XML_SetEncoding(ext_parser, fault->encoding))
1593       fail("XML_SetEncoding failed");
1594   }
1595   if (_XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
1596                               (int)strlen(fault->parse_text), XML_TRUE)
1597       != XML_STATUS_ERROR)
1598     fail(fault->fail_text);
1599   if (XML_GetErrorCode(ext_parser) != fault->error)
1600     xml_failure(ext_parser);
1601 
1602   XML_ParserFree(ext_parser);
1603   return XML_STATUS_ERROR;
1604 }
1605 
1606 START_TEST(test_ext_entity_bad_encoding) {
1607   const char *text = "<!DOCTYPE doc [\n"
1608                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1609                      "]>\n"
1610                      "<doc>&en;</doc>";
1611   ExtFaults fault
1612       = {"<?xml encoding='iso-8859-3'?>u", "Unsupported encoding not faulted",
1613          XCS("unknown"), XML_ERROR_UNKNOWN_ENCODING};
1614 
1615   XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
1616   XML_SetUserData(g_parser, &fault);
1617   expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
1618                  "Bad encoding should not have been accepted");
1619 }
1620 END_TEST
1621 
1622 /* Try handing an invalid encoding to an external entity parser */
1623 START_TEST(test_ext_entity_bad_encoding_2) {
1624   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1625                      "<!DOCTYPE doc SYSTEM 'foo'>\n"
1626                      "<doc>&entity;</doc>";
1627   ExtFaults fault
1628       = {"<!ELEMENT doc (#PCDATA)*>", "Unknown encoding not faulted",
1629          XCS("unknown-encoding"), XML_ERROR_UNKNOWN_ENCODING};
1630 
1631   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1632   XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
1633   XML_SetUserData(g_parser, &fault);
1634   expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
1635                  "Bad encoding not faulted in external entity handler");
1636 }
1637 END_TEST
1638 
1639 /* Test that no error is reported for unknown entities if we don't
1640    read an external subset.  This was fixed in Expat 1.95.5.
1641 */
1642 START_TEST(test_wfc_undeclared_entity_unread_external_subset) {
1643   const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
1644                      "<doc>&entity;</doc>";
1645 
1646   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1647       == XML_STATUS_ERROR)
1648     xml_failure(g_parser);
1649 }
1650 END_TEST
1651 
1652 /* Test that an error is reported for unknown entities if we don't
1653    have an external subset.
1654 */
1655 START_TEST(test_wfc_undeclared_entity_no_external_subset) {
1656   expect_failure("<doc>&entity;</doc>", XML_ERROR_UNDEFINED_ENTITY,
1657                  "Parser did not report undefined entity w/out a DTD.");
1658 }
1659 END_TEST
1660 
1661 /* Test that an error is reported for unknown entities if we don't
1662    read an external subset, but have been declared standalone.
1663 */
1664 START_TEST(test_wfc_undeclared_entity_standalone) {
1665   const char *text
1666       = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
1667         "<!DOCTYPE doc SYSTEM 'foo'>\n"
1668         "<doc>&entity;</doc>";
1669 
1670   expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
1671                  "Parser did not report undefined entity (standalone).");
1672 }
1673 END_TEST
1674 
1675 /* Test that an error is reported for unknown entities if we have read
1676    an external subset, and standalone is true.
1677 */
1678 START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) {
1679   const char *text
1680       = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
1681         "<!DOCTYPE doc SYSTEM 'foo'>\n"
1682         "<doc>&entity;</doc>";
1683   ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1684 
1685   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1686   XML_SetUserData(g_parser, &test_data);
1687   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1688   expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
1689                  "Parser did not report undefined entity (external DTD).");
1690 }
1691 END_TEST
1692 
1693 /* Test that external entity handling is not done if the parsing flag
1694  * is set to UNLESS_STANDALONE
1695  */
1696 START_TEST(test_entity_with_external_subset_unless_standalone) {
1697   const char *text
1698       = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
1699         "<!DOCTYPE doc SYSTEM 'foo'>\n"
1700         "<doc>&entity;</doc>";
1701   ExtTest test_data = {"<!ENTITY entity 'bar'>", NULL, NULL};
1702 
1703   XML_SetParamEntityParsing(g_parser,
1704                             XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
1705   XML_SetUserData(g_parser, &test_data);
1706   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1707   expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
1708                  "Parser did not report undefined entity");
1709 }
1710 END_TEST
1711 
1712 /* Test that no error is reported for unknown entities if we have read
1713    an external subset, and standalone is false.
1714 */
1715 START_TEST(test_wfc_undeclared_entity_with_external_subset) {
1716   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1717                      "<!DOCTYPE doc SYSTEM 'foo'>\n"
1718                      "<doc>&entity;</doc>";
1719   ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1720 
1721   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1722   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1723   run_ext_character_check(text, &test_data, XCS(""));
1724 }
1725 END_TEST
1726 
1727 /* Test that an error is reported if our NotStandalone handler fails */
1728 static int XMLCALL
1729 reject_not_standalone_handler(void *userData) {
1730   UNUSED_P(userData);
1731   return XML_STATUS_ERROR;
1732 }
1733 
1734 START_TEST(test_not_standalone_handler_reject) {
1735   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1736                      "<!DOCTYPE doc SYSTEM 'foo'>\n"
1737                      "<doc>&entity;</doc>";
1738   ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1739 
1740   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1741   XML_SetUserData(g_parser, &test_data);
1742   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1743   XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
1744   expect_failure(text, XML_ERROR_NOT_STANDALONE,
1745                  "NotStandalone handler failed to reject");
1746 
1747   /* Try again but without external entity handling */
1748   XML_ParserReset(g_parser, NULL);
1749   XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
1750   expect_failure(text, XML_ERROR_NOT_STANDALONE,
1751                  "NotStandalone handler failed to reject");
1752 }
1753 END_TEST
1754 
1755 /* Test that no error is reported if our NotStandalone handler succeeds */
1756 static int XMLCALL
1757 accept_not_standalone_handler(void *userData) {
1758   UNUSED_P(userData);
1759   return XML_STATUS_OK;
1760 }
1761 
1762 START_TEST(test_not_standalone_handler_accept) {
1763   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1764                      "<!DOCTYPE doc SYSTEM 'foo'>\n"
1765                      "<doc>&entity;</doc>";
1766   ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1767 
1768   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1769   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1770   XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
1771   run_ext_character_check(text, &test_data, XCS(""));
1772 
1773   /* Repeat without the external entity handler */
1774   XML_ParserReset(g_parser, NULL);
1775   XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
1776   run_character_check(text, XCS(""));
1777 }
1778 END_TEST
1779 
1780 START_TEST(test_wfc_no_recursive_entity_refs) {
1781   const char *text = "<!DOCTYPE doc [\n"
1782                      "  <!ENTITY entity '&#38;entity;'>\n"
1783                      "]>\n"
1784                      "<doc>&entity;</doc>";
1785 
1786   expect_failure(text, XML_ERROR_RECURSIVE_ENTITY_REF,
1787                  "Parser did not report recursive entity reference.");
1788 }
1789 END_TEST
1790 
1791 /* Test incomplete external entities are faulted */
1792 START_TEST(test_ext_entity_invalid_parse) {
1793   const char *text = "<!DOCTYPE doc [\n"
1794                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1795                      "]>\n"
1796                      "<doc>&en;</doc>";
1797   const ExtFaults faults[]
1798       = {{"<", "Incomplete element declaration not faulted", NULL,
1799           XML_ERROR_UNCLOSED_TOKEN},
1800          {"<\xe2\x82", /* First two bytes of a three-byte char */
1801           "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
1802          {"<tag>\xe2\x82", "Incomplete character in CDATA not faulted", NULL,
1803           XML_ERROR_PARTIAL_CHAR},
1804          {NULL, NULL, NULL, XML_ERROR_NONE}};
1805   const ExtFaults *fault = faults;
1806 
1807   for (; fault->parse_text != NULL; fault++) {
1808     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1809     XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
1810     XML_SetUserData(g_parser, (void *)fault);
1811     expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
1812                    "Parser did not report external entity error");
1813     XML_ParserReset(g_parser, NULL);
1814   }
1815 }
1816 END_TEST
1817 
1818 /* Regression test for SF bug #483514. */
1819 START_TEST(test_dtd_default_handling) {
1820   const char *text = "<!DOCTYPE doc [\n"
1821                      "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
1822                      "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
1823                      "<!ELEMENT doc EMPTY>\n"
1824                      "<!ATTLIST doc a CDATA #IMPLIED>\n"
1825                      "<?pi in dtd?>\n"
1826                      "<!--comment in dtd-->\n"
1827                      "]><doc/>";
1828 
1829   XML_SetDefaultHandler(g_parser, accumulate_characters);
1830   XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
1831   XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
1832   XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
1833   XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
1834   XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
1835   XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
1836   XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
1837   XML_SetCommentHandler(g_parser, dummy_comment_handler);
1838   XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
1839   XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
1840   run_character_check(text, XCS("\n\n\n\n\n\n\n<doc/>"));
1841 }
1842 END_TEST
1843 
1844 /* Test handling of attribute declarations */
1845 typedef struct AttTest {
1846   const char *definition;
1847   const XML_Char *element_name;
1848   const XML_Char *attr_name;
1849   const XML_Char *attr_type;
1850   const XML_Char *default_value;
1851   int is_required;
1852 } AttTest;
1853 
1854 static void XMLCALL
1855 verify_attlist_decl_handler(void *userData, const XML_Char *element_name,
1856                             const XML_Char *attr_name,
1857                             const XML_Char *attr_type,
1858                             const XML_Char *default_value, int is_required) {
1859   AttTest *at = (AttTest *)userData;
1860 
1861   if (xcstrcmp(element_name, at->element_name))
1862     fail("Unexpected element name in attribute declaration");
1863   if (xcstrcmp(attr_name, at->attr_name))
1864     fail("Unexpected attribute name in attribute declaration");
1865   if (xcstrcmp(attr_type, at->attr_type))
1866     fail("Unexpected attribute type in attribute declaration");
1867   if ((default_value == NULL && at->default_value != NULL)
1868       || (default_value != NULL && at->default_value == NULL)
1869       || (default_value != NULL && xcstrcmp(default_value, at->default_value)))
1870     fail("Unexpected default value in attribute declaration");
1871   if (is_required != at->is_required)
1872     fail("Requirement mismatch in attribute declaration");
1873 }
1874 
1875 START_TEST(test_dtd_attr_handling) {
1876   const char *prolog = "<!DOCTYPE doc [\n"
1877                        "<!ELEMENT doc EMPTY>\n";
1878   AttTest attr_data[]
1879       = {{"<!ATTLIST doc a ( one | two | three ) #REQUIRED>\n"
1880           "]>"
1881           "<doc a='two'/>",
1882           XCS("doc"), XCS("a"),
1883           XCS("(one|two|three)"), /* Extraneous spaces will be removed */
1884           NULL, XML_TRUE},
1885          {"<!NOTATION foo SYSTEM 'http://example.org/foo'>\n"
1886           "<!ATTLIST doc a NOTATION (foo) #IMPLIED>\n"
1887           "]>"
1888           "<doc/>",
1889           XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), NULL, XML_FALSE},
1890          {"<!ATTLIST doc a NOTATION (foo) 'bar'>\n"
1891           "]>"
1892           "<doc/>",
1893           XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), XCS("bar"), XML_FALSE},
1894          {"<!ATTLIST doc a CDATA '\xdb\xb2'>\n"
1895           "]>"
1896           "<doc/>",
1897           XCS("doc"), XCS("a"), XCS("CDATA"),
1898 #ifdef XML_UNICODE
1899           XCS("\x06f2"),
1900 #else
1901           XCS("\xdb\xb2"),
1902 #endif
1903           XML_FALSE},
1904          {NULL, NULL, NULL, NULL, NULL, XML_FALSE}};
1905   AttTest *test;
1906 
1907   for (test = attr_data; test->definition != NULL; test++) {
1908     XML_SetAttlistDeclHandler(g_parser, verify_attlist_decl_handler);
1909     XML_SetUserData(g_parser, test);
1910     if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)strlen(prolog),
1911                                 XML_FALSE)
1912         == XML_STATUS_ERROR)
1913       xml_failure(g_parser);
1914     if (_XML_Parse_SINGLE_BYTES(g_parser, test->definition,
1915                                 (int)strlen(test->definition), XML_TRUE)
1916         == XML_STATUS_ERROR)
1917       xml_failure(g_parser);
1918     XML_ParserReset(g_parser, NULL);
1919   }
1920 }
1921 END_TEST
1922 
1923 /* See related SF bug #673791.
1924    When namespace processing is enabled, setting the namespace URI for
1925    a prefix is not allowed; this test ensures that it *is* allowed
1926    when namespace processing is not enabled.
1927    (See Namespaces in XML, section 2.)
1928 */
1929 START_TEST(test_empty_ns_without_namespaces) {
1930   const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
1931                      "  <e xmlns:prefix=''/>\n"
1932                      "</doc>";
1933 
1934   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1935       == XML_STATUS_ERROR)
1936     xml_failure(g_parser);
1937 }
1938 END_TEST
1939 
1940 /* Regression test for SF bug #824420.
1941    Checks that an xmlns:prefix attribute set in an attribute's default
1942    value isn't misinterpreted.
1943 */
1944 START_TEST(test_ns_in_attribute_default_without_namespaces) {
1945   const char *text = "<!DOCTYPE e:element [\n"
1946                      "  <!ATTLIST e:element\n"
1947                      "    xmlns:e CDATA 'http://example.org/'>\n"
1948                      "      ]>\n"
1949                      "<e:element/>";
1950 
1951   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1952       == XML_STATUS_ERROR)
1953     xml_failure(g_parser);
1954 }
1955 END_TEST
1956 
1957 static const char *long_character_data_text
1958     = "<?xml version='1.0' encoding='iso-8859-1'?><s>"
1959       "012345678901234567890123456789012345678901234567890123456789"
1960       "012345678901234567890123456789012345678901234567890123456789"
1961       "012345678901234567890123456789012345678901234567890123456789"
1962       "012345678901234567890123456789012345678901234567890123456789"
1963       "012345678901234567890123456789012345678901234567890123456789"
1964       "012345678901234567890123456789012345678901234567890123456789"
1965       "012345678901234567890123456789012345678901234567890123456789"
1966       "012345678901234567890123456789012345678901234567890123456789"
1967       "012345678901234567890123456789012345678901234567890123456789"
1968       "012345678901234567890123456789012345678901234567890123456789"
1969       "012345678901234567890123456789012345678901234567890123456789"
1970       "012345678901234567890123456789012345678901234567890123456789"
1971       "012345678901234567890123456789012345678901234567890123456789"
1972       "012345678901234567890123456789012345678901234567890123456789"
1973       "012345678901234567890123456789012345678901234567890123456789"
1974       "012345678901234567890123456789012345678901234567890123456789"
1975       "012345678901234567890123456789012345678901234567890123456789"
1976       "012345678901234567890123456789012345678901234567890123456789"
1977       "012345678901234567890123456789012345678901234567890123456789"
1978       "012345678901234567890123456789012345678901234567890123456789"
1979       "</s>";
1980 
1981 static XML_Bool resumable = XML_FALSE;
1982 
1983 static void
1984 clearing_aborting_character_handler(void *userData, const XML_Char *s,
1985                                     int len) {
1986   UNUSED_P(userData);
1987   UNUSED_P(s);
1988   UNUSED_P(len);
1989   XML_StopParser(g_parser, resumable);
1990   XML_SetCharacterDataHandler(g_parser, NULL);
1991 }
1992 
1993 /* Regression test for SF bug #1515266: missing check of stopped
1994    parser in doContext() 'for' loop. */
1995 START_TEST(test_stop_parser_between_char_data_calls) {
1996   /* The sample data must be big enough that there are two calls to
1997      the character data handler from within the inner "for" loop of
1998      the XML_TOK_DATA_CHARS case in doContent(), and the character
1999      handler must stop the parser and clear the character data
2000      handler.
2001   */
2002   const char *text = long_character_data_text;
2003 
2004   XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2005   resumable = XML_FALSE;
2006   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2007       != XML_STATUS_ERROR)
2008     xml_failure(g_parser);
2009   if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
2010     xml_failure(g_parser);
2011 }
2012 END_TEST
2013 
2014 /* Regression test for SF bug #1515266: missing check of stopped
2015    parser in doContext() 'for' loop. */
2016 START_TEST(test_suspend_parser_between_char_data_calls) {
2017   /* The sample data must be big enough that there are two calls to
2018      the character data handler from within the inner "for" loop of
2019      the XML_TOK_DATA_CHARS case in doContent(), and the character
2020      handler must stop the parser and clear the character data
2021      handler.
2022   */
2023   const char *text = long_character_data_text;
2024 
2025   XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2026   resumable = XML_TRUE;
2027   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2028       != XML_STATUS_SUSPENDED)
2029     xml_failure(g_parser);
2030   if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
2031     xml_failure(g_parser);
2032   /* Try parsing directly */
2033   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
2034       != XML_STATUS_ERROR)
2035     fail("Attempt to continue parse while suspended not faulted");
2036   if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
2037     fail("Suspended parse not faulted with correct error");
2038 }
2039 END_TEST
2040 
2041 static XML_Bool abortable = XML_FALSE;
2042 
2043 static void
2044 parser_stop_character_handler(void *userData, const XML_Char *s, int len) {
2045   UNUSED_P(userData);
2046   UNUSED_P(s);
2047   UNUSED_P(len);
2048   XML_StopParser(g_parser, resumable);
2049   XML_SetCharacterDataHandler(g_parser, NULL);
2050   if (! resumable) {
2051     /* Check that aborting an aborted parser is faulted */
2052     if (XML_StopParser(g_parser, XML_FALSE) != XML_STATUS_ERROR)
2053       fail("Aborting aborted parser not faulted");
2054     if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
2055       xml_failure(g_parser);
2056   } else if (abortable) {
2057     /* Check that aborting a suspended parser works */
2058     if (XML_StopParser(g_parser, XML_FALSE) == XML_STATUS_ERROR)
2059       xml_failure(g_parser);
2060   } else {
2061     /* Check that suspending a suspended parser works */
2062     if (XML_StopParser(g_parser, XML_TRUE) != XML_STATUS_ERROR)
2063       fail("Suspending suspended parser not faulted");
2064     if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
2065       xml_failure(g_parser);
2066   }
2067 }
2068 
2069 /* Test repeated calls to XML_StopParser are handled correctly */
2070 START_TEST(test_repeated_stop_parser_between_char_data_calls) {
2071   const char *text = long_character_data_text;
2072 
2073   XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
2074   resumable = XML_FALSE;
2075   abortable = XML_FALSE;
2076   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2077       != XML_STATUS_ERROR)
2078     fail("Failed to double-stop parser");
2079 
2080   XML_ParserReset(g_parser, NULL);
2081   XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
2082   resumable = XML_TRUE;
2083   abortable = XML_FALSE;
2084   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2085       != XML_STATUS_SUSPENDED)
2086     fail("Failed to double-suspend parser");
2087 
2088   XML_ParserReset(g_parser, NULL);
2089   XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
2090   resumable = XML_TRUE;
2091   abortable = XML_TRUE;
2092   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2093       != XML_STATUS_ERROR)
2094     fail("Failed to suspend-abort parser");
2095 }
2096 END_TEST
2097 
2098 START_TEST(test_good_cdata_ascii) {
2099   const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
2100   const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
2101 
2102   CharData storage;
2103   CharData_Init(&storage);
2104   XML_SetUserData(g_parser, &storage);
2105   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2106   /* Add start and end handlers for coverage */
2107   XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
2108   XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
2109 
2110   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2111       == XML_STATUS_ERROR)
2112     xml_failure(g_parser);
2113   CharData_CheckXMLChars(&storage, expected);
2114 
2115   /* Try again, this time with a default handler */
2116   XML_ParserReset(g_parser, NULL);
2117   CharData_Init(&storage);
2118   XML_SetUserData(g_parser, &storage);
2119   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2120   XML_SetDefaultHandler(g_parser, dummy_default_handler);
2121 
2122   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2123       == XML_STATUS_ERROR)
2124     xml_failure(g_parser);
2125   CharData_CheckXMLChars(&storage, expected);
2126 }
2127 END_TEST
2128 
2129 START_TEST(test_good_cdata_utf16) {
2130   /* Test data is:
2131    *   <?xml version='1.0' encoding='utf-16'?>
2132    *   <a><![CDATA[hello]]></a>
2133    */
2134   const char text[]
2135       = "\0<\0?\0x\0m\0l\0"
2136         " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2137         " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2138         "1\0"
2139         "6\0'"
2140         "\0?\0>\0\n"
2141         "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>";
2142   const XML_Char *expected = XCS("hello");
2143 
2144   CharData storage;
2145   CharData_Init(&storage);
2146   XML_SetUserData(g_parser, &storage);
2147   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2148 
2149   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
2150       == XML_STATUS_ERROR)
2151     xml_failure(g_parser);
2152   CharData_CheckXMLChars(&storage, expected);
2153 }
2154 END_TEST
2155 
2156 START_TEST(test_good_cdata_utf16_le) {
2157   /* Test data is:
2158    *   <?xml version='1.0' encoding='utf-16'?>
2159    *   <a><![CDATA[hello]]></a>
2160    */
2161   const char text[]
2162       = "<\0?\0x\0m\0l\0"
2163         " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2164         " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2165         "1\0"
2166         "6\0'"
2167         "\0?\0>\0\n"
2168         "\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";
2169   const XML_Char *expected = XCS("hello");
2170 
2171   CharData storage;
2172   CharData_Init(&storage);
2173   XML_SetUserData(g_parser, &storage);
2174   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2175 
2176   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
2177       == XML_STATUS_ERROR)
2178     xml_failure(g_parser);
2179   CharData_CheckXMLChars(&storage, expected);
2180 }
2181 END_TEST
2182 
2183 /* Test UTF16 conversion of a long cdata string */
2184 
2185 /* 16 characters: handy macro to reduce visual clutter */
2186 #define A_TO_P_IN_UTF16 "\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P"
2187 
2188 START_TEST(test_long_cdata_utf16) {
2189   /* Test data is:
2190    * <?xlm version='1.0' encoding='utf-16'?>
2191    * <a><![CDATA[
2192    * ABCDEFGHIJKLMNOP
2193    * ]]></a>
2194    */
2195   const char text[]
2196       = "\0<\0?\0x\0m\0l\0 "
2197         "\0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0 "
2198         "\0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0\x31\0\x36\0'\0?\0>"
2199         "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
2200       /* 64 characters per line */
2201       /* clang-format off */
2202         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2203         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2204         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2205         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2206         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2207         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2208         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2209         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2210         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2211         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2212         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2213         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2214         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2215         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2216         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2217         A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
2218         A_TO_P_IN_UTF16
2219         /* clang-format on */
2220         "\0]\0]\0>\0<\0/\0a\0>";
2221   const XML_Char *expected =
2222       /* clang-format off */
2223         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2224         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2225         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2226         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2227         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2228         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2229         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2230         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2231         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2232         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2233         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2234         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2235         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2236         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2237         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2238         XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
2239         XCS("ABCDEFGHIJKLMNOP");
2240   /* clang-format on */
2241   CharData storage;
2242   void *buffer;
2243 
2244   CharData_Init(&storage);
2245   XML_SetUserData(g_parser, &storage);
2246   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2247   buffer = XML_GetBuffer(g_parser, sizeof(text) - 1);
2248   if (buffer == NULL)
2249     fail("Could not allocate parse buffer");
2250   assert(buffer != NULL);
2251   memcpy(buffer, text, sizeof(text) - 1);
2252   if (XML_ParseBuffer(g_parser, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
2253     xml_failure(g_parser);
2254   CharData_CheckXMLChars(&storage, expected);
2255 }
2256 END_TEST
2257 
2258 /* Test handling of multiple unit UTF-16 characters */
2259 START_TEST(test_multichar_cdata_utf16) {
2260   /* Test data is:
2261    *   <?xml version='1.0' encoding='utf-16'?>
2262    *   <a><![CDATA[{MINIM}{CROTCHET}]]></a>
2263    *
2264    * where {MINIM} is U+1d15e (a minim or half-note)
2265    *   UTF-16: 0xd834 0xdd5e
2266    *   UTF-8:  0xf0 0x9d 0x85 0x9e
2267    * and {CROTCHET} is U+1d15f (a crotchet or quarter-note)
2268    *   UTF-16: 0xd834 0xdd5f
2269    *   UTF-8:  0xf0 0x9d 0x85 0x9f
2270    */
2271   const char text[] = "\0<\0?\0x\0m\0l\0"
2272                       " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2273                       " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2274                       "1\0"
2275                       "6\0'"
2276                       "\0?\0>\0\n"
2277                       "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
2278                       "\xd8\x34\xdd\x5e\xd8\x34\xdd\x5f"
2279                       "\0]\0]\0>\0<\0/\0a\0>";
2280 #ifdef XML_UNICODE
2281   const XML_Char *expected = XCS("\xd834\xdd5e\xd834\xdd5f");
2282 #else
2283   const XML_Char *expected = XCS("\xf0\x9d\x85\x9e\xf0\x9d\x85\x9f");
2284 #endif
2285   CharData storage;
2286 
2287   CharData_Init(&storage);
2288   XML_SetUserData(g_parser, &storage);
2289   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2290 
2291   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
2292       == XML_STATUS_ERROR)
2293     xml_failure(g_parser);
2294   CharData_CheckXMLChars(&storage, expected);
2295 }
2296 END_TEST
2297 
2298 /* Test that an element name with a UTF-16 surrogate pair is rejected */
2299 START_TEST(test_utf16_bad_surrogate_pair) {
2300   /* Test data is:
2301    *   <?xml version='1.0' encoding='utf-16'?>
2302    *   <a><![CDATA[{BADLINB}]]></a>
2303    *
2304    * where {BADLINB} is U+10000 (the first Linear B character)
2305    * with the UTF-16 surrogate pair in the wrong order, i.e.
2306    *   0xdc00 0xd800
2307    */
2308   const char text[] = "\0<\0?\0x\0m\0l\0"
2309                       " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2310                       " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2311                       "1\0"
2312                       "6\0'"
2313                       "\0?\0>\0\n"
2314                       "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
2315                       "\xdc\x00\xd8\x00"
2316                       "\0]\0]\0>\0<\0/\0a\0>";
2317 
2318   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
2319       != XML_STATUS_ERROR)
2320     fail("Reversed UTF-16 surrogate pair not faulted");
2321   if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
2322     xml_failure(g_parser);
2323 }
2324 END_TEST
2325 
2326 START_TEST(test_bad_cdata) {
2327   struct CaseData {
2328     const char *text;
2329     enum XML_Error expectedError;
2330   };
2331 
2332   struct CaseData cases[]
2333       = {{"<a><", XML_ERROR_UNCLOSED_TOKEN},
2334          {"<a><!", XML_ERROR_UNCLOSED_TOKEN},
2335          {"<a><![", XML_ERROR_UNCLOSED_TOKEN},
2336          {"<a><![C", XML_ERROR_UNCLOSED_TOKEN},
2337          {"<a><![CD", XML_ERROR_UNCLOSED_TOKEN},
2338          {"<a><![CDA", XML_ERROR_UNCLOSED_TOKEN},
2339          {"<a><![CDAT", XML_ERROR_UNCLOSED_TOKEN},
2340          {"<a><![CDATA", XML_ERROR_UNCLOSED_TOKEN},
2341 
2342          {"<a><![CDATA[", XML_ERROR_UNCLOSED_CDATA_SECTION},
2343          {"<a><![CDATA[]", XML_ERROR_UNCLOSED_CDATA_SECTION},
2344          {"<a><![CDATA[]]", XML_ERROR_UNCLOSED_CDATA_SECTION},
2345 
2346          {"<a><!<a/>", XML_ERROR_INVALID_TOKEN},
2347          {"<a><![<a/>", XML_ERROR_UNCLOSED_TOKEN},  /* ?! */
2348          {"<a><![C<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
2349          {"<a><![CD<a/>", XML_ERROR_INVALID_TOKEN},
2350          {"<a><![CDA<a/>", XML_ERROR_INVALID_TOKEN},
2351          {"<a><![CDAT<a/>", XML_ERROR_INVALID_TOKEN},
2352          {"<a><![CDATA<a/>", XML_ERROR_INVALID_TOKEN},
2353 
2354          {"<a><![CDATA[<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
2355          {"<a><![CDATA[]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
2356          {"<a><![CDATA[]]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION}};
2357 
2358   size_t i = 0;
2359   for (; i < sizeof(cases) / sizeof(struct CaseData); i++) {
2360     const enum XML_Status actualStatus = _XML_Parse_SINGLE_BYTES(
2361         g_parser, cases[i].text, (int)strlen(cases[i].text), XML_TRUE);
2362     const enum XML_Error actualError = XML_GetErrorCode(g_parser);
2363 
2364     assert(actualStatus == XML_STATUS_ERROR);
2365 
2366     if (actualError != cases[i].expectedError) {
2367       char message[100];
2368       sprintf(message,
2369               "Expected error %d but got error %d for case %u: \"%s\"\n",
2370               cases[i].expectedError, actualError, (unsigned int)i + 1,
2371               cases[i].text);
2372       fail(message);
2373     }
2374 
2375     XML_ParserReset(g_parser, NULL);
2376   }
2377 }
2378 END_TEST
2379 
2380 /* Test failures in UTF-16 CDATA */
2381 START_TEST(test_bad_cdata_utf16) {
2382   struct CaseData {
2383     size_t text_bytes;
2384     const char *text;
2385     enum XML_Error expected_error;
2386   };
2387 
2388   const char prolog[] = "\0<\0?\0x\0m\0l\0"
2389                         " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2390                         " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2391                         "1\0"
2392                         "6\0'"
2393                         "\0?\0>\0\n"
2394                         "\0<\0a\0>";
2395   struct CaseData cases[] = {
2396       {1, "\0", XML_ERROR_UNCLOSED_TOKEN},
2397       {2, "\0<", XML_ERROR_UNCLOSED_TOKEN},
2398       {3, "\0<\0", XML_ERROR_UNCLOSED_TOKEN},
2399       {4, "\0<\0!", XML_ERROR_UNCLOSED_TOKEN},
2400       {5, "\0<\0!\0", XML_ERROR_UNCLOSED_TOKEN},
2401       {6, "\0<\0!\0[", XML_ERROR_UNCLOSED_TOKEN},
2402       {7, "\0<\0!\0[\0", XML_ERROR_UNCLOSED_TOKEN},
2403       {8, "\0<\0!\0[\0C", XML_ERROR_UNCLOSED_TOKEN},
2404       {9, "\0<\0!\0[\0C\0", XML_ERROR_UNCLOSED_TOKEN},
2405       {10, "\0<\0!\0[\0C\0D", XML_ERROR_UNCLOSED_TOKEN},
2406       {11, "\0<\0!\0[\0C\0D\0", XML_ERROR_UNCLOSED_TOKEN},
2407       {12, "\0<\0!\0[\0C\0D\0A", XML_ERROR_UNCLOSED_TOKEN},
2408       {13, "\0<\0!\0[\0C\0D\0A\0", XML_ERROR_UNCLOSED_TOKEN},
2409       {14, "\0<\0!\0[\0C\0D\0A\0T", XML_ERROR_UNCLOSED_TOKEN},
2410       {15, "\0<\0!\0[\0C\0D\0A\0T\0", XML_ERROR_UNCLOSED_TOKEN},
2411       {16, "\0<\0!\0[\0C\0D\0A\0T\0A", XML_ERROR_UNCLOSED_TOKEN},
2412       {17, "\0<\0!\0[\0C\0D\0A\0T\0A\0", XML_ERROR_UNCLOSED_TOKEN},
2413       {18, "\0<\0!\0[\0C\0D\0A\0T\0A\0[", XML_ERROR_UNCLOSED_CDATA_SECTION},
2414       {19, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0", XML_ERROR_UNCLOSED_CDATA_SECTION},
2415       {20, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z", XML_ERROR_UNCLOSED_CDATA_SECTION},
2416       /* Now add a four-byte UTF-16 character */
2417       {21, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8",
2418        XML_ERROR_UNCLOSED_CDATA_SECTION},
2419       {22, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34", XML_ERROR_PARTIAL_CHAR},
2420       {23, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd",
2421        XML_ERROR_PARTIAL_CHAR},
2422       {24, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd\x5e",
2423        XML_ERROR_UNCLOSED_CDATA_SECTION}};
2424   size_t i;
2425 
2426   for (i = 0; i < sizeof(cases) / sizeof(struct CaseData); i++) {
2427     enum XML_Status actual_status;
2428     enum XML_Error actual_error;
2429 
2430     if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)sizeof(prolog) - 1,
2431                                 XML_FALSE)
2432         == XML_STATUS_ERROR)
2433       xml_failure(g_parser);
2434     actual_status = _XML_Parse_SINGLE_BYTES(g_parser, cases[i].text,
2435                                             (int)cases[i].text_bytes, XML_TRUE);
2436     assert(actual_status == XML_STATUS_ERROR);
2437     actual_error = XML_GetErrorCode(g_parser);
2438     if (actual_error != cases[i].expected_error) {
2439       char message[1024];
2440 
2441       sprintf(message,
2442               "Expected error %d (%" XML_FMT_STR "), got %d (%" XML_FMT_STR
2443               ") for case %lu\n",
2444               cases[i].expected_error, XML_ErrorString(cases[i].expected_error),
2445               actual_error, XML_ErrorString(actual_error),
2446               (long unsigned)(i + 1));
2447       fail(message);
2448     }
2449     XML_ParserReset(g_parser, NULL);
2450   }
2451 }
2452 END_TEST
2453 
2454 static const char *long_cdata_text
2455     = "<s><![CDATA["
2456       "012345678901234567890123456789012345678901234567890123456789"
2457       "012345678901234567890123456789012345678901234567890123456789"
2458       "012345678901234567890123456789012345678901234567890123456789"
2459       "012345678901234567890123456789012345678901234567890123456789"
2460       "012345678901234567890123456789012345678901234567890123456789"
2461       "012345678901234567890123456789012345678901234567890123456789"
2462       "012345678901234567890123456789012345678901234567890123456789"
2463       "012345678901234567890123456789012345678901234567890123456789"
2464       "012345678901234567890123456789012345678901234567890123456789"
2465       "012345678901234567890123456789012345678901234567890123456789"
2466       "012345678901234567890123456789012345678901234567890123456789"
2467       "012345678901234567890123456789012345678901234567890123456789"
2468       "012345678901234567890123456789012345678901234567890123456789"
2469       "012345678901234567890123456789012345678901234567890123456789"
2470       "012345678901234567890123456789012345678901234567890123456789"
2471       "012345678901234567890123456789012345678901234567890123456789"
2472       "012345678901234567890123456789012345678901234567890123456789"
2473       "012345678901234567890123456789012345678901234567890123456789"
2474       "012345678901234567890123456789012345678901234567890123456789"
2475       "012345678901234567890123456789012345678901234567890123456789"
2476       "]]></s>";
2477 
2478 /* Test stopping the parser in cdata handler */
2479 START_TEST(test_stop_parser_between_cdata_calls) {
2480   const char *text = long_cdata_text;
2481 
2482   XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2483   resumable = XML_FALSE;
2484   expect_failure(text, XML_ERROR_ABORTED, "Parse not aborted in CDATA handler");
2485 }
2486 END_TEST
2487 
2488 /* Test suspending the parser in cdata handler */
2489 START_TEST(test_suspend_parser_between_cdata_calls) {
2490   const char *text = long_cdata_text;
2491   enum XML_Status result;
2492 
2493   XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2494   resumable = XML_TRUE;
2495   result = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
2496   if (result != XML_STATUS_SUSPENDED) {
2497     if (result == XML_STATUS_ERROR)
2498       xml_failure(g_parser);
2499     fail("Parse not suspended in CDATA handler");
2500   }
2501   if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
2502     xml_failure(g_parser);
2503 }
2504 END_TEST
2505 
2506 /* Test memory allocation functions */
2507 START_TEST(test_memory_allocation) {
2508   char *buffer = (char *)XML_MemMalloc(g_parser, 256);
2509   char *p;
2510 
2511   if (buffer == NULL) {
2512     fail("Allocation failed");
2513   } else {
2514     /* Try writing to memory; some OSes try to cheat! */
2515     buffer[0] = 'T';
2516     buffer[1] = 'E';
2517     buffer[2] = 'S';
2518     buffer[3] = 'T';
2519     buffer[4] = '\0';
2520     if (strcmp(buffer, "TEST") != 0) {
2521       fail("Memory not writable");
2522     } else {
2523       p = (char *)XML_MemRealloc(g_parser, buffer, 512);
2524       if (p == NULL) {
2525         fail("Reallocation failed");
2526       } else {
2527         /* Write again, just to be sure */
2528         buffer = p;
2529         buffer[0] = 'V';
2530         if (strcmp(buffer, "VEST") != 0) {
2531           fail("Reallocated memory not writable");
2532         }
2533       }
2534     }
2535     XML_MemFree(g_parser, buffer);
2536   }
2537 }
2538 END_TEST
2539 
2540 static void XMLCALL
2541 record_default_handler(void *userData, const XML_Char *s, int len) {
2542   UNUSED_P(s);
2543   UNUSED_P(len);
2544   CharData_AppendXMLChars((CharData *)userData, XCS("D"), 1);
2545 }
2546 
2547 static void XMLCALL
2548 record_cdata_handler(void *userData, const XML_Char *s, int len) {
2549   UNUSED_P(s);
2550   UNUSED_P(len);
2551   CharData_AppendXMLChars((CharData *)userData, XCS("C"), 1);
2552   XML_DefaultCurrent(g_parser);
2553 }
2554 
2555 static void XMLCALL
2556 record_cdata_nodefault_handler(void *userData, const XML_Char *s, int len) {
2557   UNUSED_P(s);
2558   UNUSED_P(len);
2559   CharData_AppendXMLChars((CharData *)userData, XCS("c"), 1);
2560 }
2561 
2562 static void XMLCALL
2563 record_skip_handler(void *userData, const XML_Char *entityName,
2564                     int is_parameter_entity) {
2565   UNUSED_P(entityName);
2566   CharData_AppendXMLChars((CharData *)userData,
2567                           is_parameter_entity ? XCS("E") : XCS("e"), 1);
2568 }
2569 
2570 /* Test XML_DefaultCurrent() passes handling on correctly */
2571 START_TEST(test_default_current) {
2572   const char *text = "<doc>hell]</doc>";
2573   const char *entity_text = "<!DOCTYPE doc [\n"
2574                             "<!ENTITY entity '&#37;'>\n"
2575                             "]>\n"
2576                             "<doc>&entity;</doc>";
2577   CharData storage;
2578 
2579   XML_SetDefaultHandler(g_parser, record_default_handler);
2580   XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2581   CharData_Init(&storage);
2582   XML_SetUserData(g_parser, &storage);
2583   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2584       == XML_STATUS_ERROR)
2585     xml_failure(g_parser);
2586   CharData_CheckXMLChars(&storage, XCS("DCDCDCDCDCDD"));
2587 
2588   /* Again, without the defaulting */
2589   XML_ParserReset(g_parser, NULL);
2590   XML_SetDefaultHandler(g_parser, record_default_handler);
2591   XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
2592   CharData_Init(&storage);
2593   XML_SetUserData(g_parser, &storage);
2594   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2595       == XML_STATUS_ERROR)
2596     xml_failure(g_parser);
2597   CharData_CheckXMLChars(&storage, XCS("DcccccD"));
2598 
2599   /* Now with an internal entity to complicate matters */
2600   XML_ParserReset(g_parser, NULL);
2601   XML_SetDefaultHandler(g_parser, record_default_handler);
2602   XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2603   CharData_Init(&storage);
2604   XML_SetUserData(g_parser, &storage);
2605   if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2606                               XML_TRUE)
2607       == XML_STATUS_ERROR)
2608     xml_failure(g_parser);
2609   /* The default handler suppresses the entity */
2610   CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDDD"));
2611 
2612   /* Again, with a skip handler */
2613   XML_ParserReset(g_parser, NULL);
2614   XML_SetDefaultHandler(g_parser, record_default_handler);
2615   XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2616   XML_SetSkippedEntityHandler(g_parser, record_skip_handler);
2617   CharData_Init(&storage);
2618   XML_SetUserData(g_parser, &storage);
2619   if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2620                               XML_TRUE)
2621       == XML_STATUS_ERROR)
2622     xml_failure(g_parser);
2623   /* The default handler suppresses the entity */
2624   CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDeD"));
2625 
2626   /* This time, allow the entity through */
2627   XML_ParserReset(g_parser, NULL);
2628   XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
2629   XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2630   CharData_Init(&storage);
2631   XML_SetUserData(g_parser, &storage);
2632   if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2633                               XML_TRUE)
2634       == XML_STATUS_ERROR)
2635     xml_failure(g_parser);
2636   CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDCDD"));
2637 
2638   /* Finally, without passing the cdata to the default handler */
2639   XML_ParserReset(g_parser, NULL);
2640   XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
2641   XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
2642   CharData_Init(&storage);
2643   XML_SetUserData(g_parser, &storage);
2644   if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2645                               XML_TRUE)
2646       == XML_STATUS_ERROR)
2647     xml_failure(g_parser);
2648   CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDcD"));
2649 }
2650 END_TEST
2651 
2652 /* Test DTD element parsing code paths */
2653 START_TEST(test_dtd_elements) {
2654   const char *text = "<!DOCTYPE doc [\n"
2655                      "<!ELEMENT doc (chapter)>\n"
2656                      "<!ELEMENT chapter (#PCDATA)>\n"
2657                      "]>\n"
2658                      "<doc><chapter>Wombats are go</chapter></doc>";
2659 
2660   XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
2661   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2662       == XML_STATUS_ERROR)
2663     xml_failure(g_parser);
2664 }
2665 END_TEST
2666 
2667 /* Test foreign DTD handling */
2668 START_TEST(test_set_foreign_dtd) {
2669   const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n";
2670   const char *text2 = "<doc>&entity;</doc>";
2671   ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
2672 
2673   /* Check hash salt is passed through too */
2674   XML_SetHashSalt(g_parser, 0x12345678);
2675   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2676   XML_SetUserData(g_parser, &test_data);
2677   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
2678   /* Add a default handler to exercise more code paths */
2679   XML_SetDefaultHandler(g_parser, dummy_default_handler);
2680   if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
2681     fail("Could not set foreign DTD");
2682   if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
2683       == XML_STATUS_ERROR)
2684     xml_failure(g_parser);
2685 
2686   /* Ensure that trying to set the DTD after parsing has started
2687    * is faulted, even if it's the same setting.
2688    */
2689   if (XML_UseForeignDTD(g_parser, XML_TRUE)
2690       != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
2691     fail("Failed to reject late foreign DTD setting");
2692   /* Ditto for the hash salt */
2693   if (XML_SetHashSalt(g_parser, 0x23456789))
2694     fail("Failed to reject late hash salt change");
2695 
2696   /* Now finish the parse */
2697   if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
2698       == XML_STATUS_ERROR)
2699     xml_failure(g_parser);
2700 }
2701 END_TEST
2702 
2703 /* Test foreign DTD handling with a failing NotStandalone handler */
2704 START_TEST(test_foreign_dtd_not_standalone) {
2705   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
2706                      "<doc>&entity;</doc>";
2707   ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
2708 
2709   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2710   XML_SetUserData(g_parser, &test_data);
2711   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
2712   XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
2713   if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
2714     fail("Could not set foreign DTD");
2715   expect_failure(text, XML_ERROR_NOT_STANDALONE,
2716                  "NotStandalonehandler failed to reject");
2717 }
2718 END_TEST
2719 
2720 /* Test invalid character in a foreign DTD is faulted */
2721 START_TEST(test_invalid_foreign_dtd) {
2722   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
2723                      "<doc>&entity;</doc>";
2724   ExtFaults test_data
2725       = {"$", "Dollar not faulted", NULL, XML_ERROR_INVALID_TOKEN};
2726 
2727   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2728   XML_SetUserData(g_parser, &test_data);
2729   XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
2730   XML_UseForeignDTD(g_parser, XML_TRUE);
2731   expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
2732                  "Bad DTD should not have been accepted");
2733 }
2734 END_TEST
2735 
2736 /* Test foreign DTD use with a doctype */
2737 START_TEST(test_foreign_dtd_with_doctype) {
2738   const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
2739                       "<!DOCTYPE doc [<!ENTITY entity 'hello world'>]>\n";
2740   const char *text2 = "<doc>&entity;</doc>";
2741   ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
2742 
2743   /* Check hash salt is passed through too */
2744   XML_SetHashSalt(g_parser, 0x12345678);
2745   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2746   XML_SetUserData(g_parser, &test_data);
2747   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
2748   /* Add a default handler to exercise more code paths */
2749   XML_SetDefaultHandler(g_parser, dummy_default_handler);
2750   if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
2751     fail("Could not set foreign DTD");
2752   if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
2753       == XML_STATUS_ERROR)
2754     xml_failure(g_parser);
2755 
2756   /* Ensure that trying to set the DTD after parsing has started
2757    * is faulted, even if it's the same setting.
2758    */
2759   if (XML_UseForeignDTD(g_parser, XML_TRUE)
2760       != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
2761     fail("Failed to reject late foreign DTD setting");
2762   /* Ditto for the hash salt */
2763   if (XML_SetHashSalt(g_parser, 0x23456789))
2764     fail("Failed to reject late hash salt change");
2765 
2766   /* Now finish the parse */
2767   if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
2768       == XML_STATUS_ERROR)
2769     xml_failure(g_parser);
2770 }
2771 END_TEST
2772 
2773 /* Test XML_UseForeignDTD with no external subset present */
2774 static int XMLCALL
2775 external_entity_null_loader(XML_Parser parser, const XML_Char *context,
2776                             const XML_Char *base, const XML_Char *systemId,
2777                             const XML_Char *publicId) {
2778   UNUSED_P(parser);
2779   UNUSED_P(context);
2780   UNUSED_P(base);
2781   UNUSED_P(systemId);
2782   UNUSED_P(publicId);
2783   return XML_STATUS_OK;
2784 }
2785 
2786 START_TEST(test_foreign_dtd_without_external_subset) {
2787   const char *text = "<!DOCTYPE doc [<!ENTITY foo 'bar'>]>\n"
2788                      "<doc>&foo;</doc>";
2789 
2790   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2791   XML_SetUserData(g_parser, NULL);
2792   XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
2793   XML_UseForeignDTD(g_parser, XML_TRUE);
2794   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2795       == XML_STATUS_ERROR)
2796     xml_failure(g_parser);
2797 }
2798 END_TEST
2799 
2800 START_TEST(test_empty_foreign_dtd) {
2801   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
2802                      "<doc>&entity;</doc>";
2803 
2804   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2805   XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
2806   XML_UseForeignDTD(g_parser, XML_TRUE);
2807   expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
2808                  "Undefined entity not faulted");
2809 }
2810 END_TEST
2811 
2812 /* Test XML Base is set and unset appropriately */
2813 START_TEST(test_set_base) {
2814   const XML_Char *old_base;
2815   const XML_Char *new_base = XCS("/local/file/name.xml");
2816 
2817   old_base = XML_GetBase(g_parser);
2818   if (XML_SetBase(g_parser, new_base) != XML_STATUS_OK)
2819     fail("Unable to set base");
2820   if (xcstrcmp(XML_GetBase(g_parser), new_base) != 0)
2821     fail("Base setting not correct");
2822   if (XML_SetBase(g_parser, NULL) != XML_STATUS_OK)
2823     fail("Unable to NULL base");
2824   if (XML_GetBase(g_parser) != NULL)
2825     fail("Base setting not nulled");
2826   XML_SetBase(g_parser, old_base);
2827 }
2828 END_TEST
2829 
2830 /* Test attribute counts, indexing, etc */
2831 typedef struct attrInfo {
2832   const XML_Char *name;
2833   const XML_Char *value;
2834 } AttrInfo;
2835 
2836 typedef struct elementInfo {
2837   const XML_Char *name;
2838   int attr_count;
2839   const XML_Char *id_name;
2840   AttrInfo *attributes;
2841 } ElementInfo;
2842 
2843 static void XMLCALL
2844 counting_start_element_handler(void *userData, const XML_Char *name,
2845                                const XML_Char **atts) {
2846   ElementInfo *info = (ElementInfo *)userData;
2847   AttrInfo *attr;
2848   int count, id, i;
2849 
2850   while (info->name != NULL) {
2851     if (! xcstrcmp(name, info->name))
2852       break;
2853     info++;
2854   }
2855   if (info->name == NULL)
2856     fail("Element not recognised");
2857   /* The attribute count is twice what you might expect.  It is a
2858    * count of items in atts, an array which contains alternating
2859    * attribute names and attribute values.  For the naive user this
2860    * is possibly a little unexpected, but it is what the
2861    * documentation in expat.h tells us to expect.
2862    */
2863   count = XML_GetSpecifiedAttributeCount(g_parser);
2864   if (info->attr_count * 2 != count) {
2865     fail("Not got expected attribute count");
2866     return;
2867   }
2868   id = XML_GetIdAttributeIndex(g_parser);
2869   if (id == -1 && info->id_name != NULL) {
2870     fail("ID not present");
2871     return;
2872   }
2873   if (id != -1 && xcstrcmp(atts[id], info->id_name)) {
2874     fail("ID does not have the correct name");
2875     return;
2876   }
2877   for (i = 0; i < info->attr_count; i++) {
2878     attr = info->attributes;
2879     while (attr->name != NULL) {
2880       if (! xcstrcmp(atts[0], attr->name))
2881         break;
2882       attr++;
2883     }
2884     if (attr->name == NULL) {
2885       fail("Attribute not recognised");
2886       return;
2887     }
2888     if (xcstrcmp(atts[1], attr->value)) {
2889       fail("Attribute has wrong value");
2890       return;
2891     }
2892     /* Remember, two entries in atts per attribute (see above) */
2893     atts += 2;
2894   }
2895 }
2896 
2897 START_TEST(test_attributes) {
2898   const char *text = "<!DOCTYPE doc [\n"
2899                      "<!ELEMENT doc (tag)>\n"
2900                      "<!ATTLIST doc id ID #REQUIRED>\n"
2901                      "]>"
2902                      "<doc a='1' id='one' b='2'>"
2903                      "<tag c='3'/>"
2904                      "</doc>";
2905   AttrInfo doc_info[] = {{XCS("a"), XCS("1")},
2906                          {XCS("b"), XCS("2")},
2907                          {XCS("id"), XCS("one")},
2908                          {NULL, NULL}};
2909   AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}};
2910   ElementInfo info[] = {{XCS("doc"), 3, XCS("id"), NULL},
2911                         {XCS("tag"), 1, NULL, NULL},
2912                         {NULL, 0, NULL, NULL}};
2913   info[0].attributes = doc_info;
2914   info[1].attributes = tag_info;
2915 
2916   XML_SetStartElementHandler(g_parser, counting_start_element_handler);
2917   XML_SetUserData(g_parser, info);
2918   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2919       == XML_STATUS_ERROR)
2920     xml_failure(g_parser);
2921 }
2922 END_TEST
2923 
2924 /* Test reset works correctly in the middle of processing an internal
2925  * entity.  Exercises some obscure code in XML_ParserReset().
2926  */
2927 START_TEST(test_reset_in_entity) {
2928   const char *text = "<!DOCTYPE doc [\n"
2929                      "<!ENTITY wombat 'wom'>\n"
2930                      "<!ENTITY entity 'hi &wom; there'>\n"
2931                      "]>\n"
2932                      "<doc>&entity;</doc>";
2933   XML_ParsingStatus status;
2934 
2935   resumable = XML_TRUE;
2936   XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2937   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
2938       == XML_STATUS_ERROR)
2939     xml_failure(g_parser);
2940   XML_GetParsingStatus(g_parser, &status);
2941   if (status.parsing != XML_SUSPENDED)
2942     fail("Parsing status not SUSPENDED");
2943   XML_ParserReset(g_parser, NULL);
2944   XML_GetParsingStatus(g_parser, &status);
2945   if (status.parsing != XML_INITIALIZED)
2946     fail("Parsing status doesn't reset to INITIALIZED");
2947 }
2948 END_TEST
2949 
2950 /* Test that resume correctly passes through parse errors */
2951 START_TEST(test_resume_invalid_parse) {
2952   const char *text = "<doc>Hello</doc"; /* Missing closing wedge */
2953 
2954   resumable = XML_TRUE;
2955   XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2956   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
2957       == XML_STATUS_ERROR)
2958     xml_failure(g_parser);
2959   if (XML_ResumeParser(g_parser) == XML_STATUS_OK)
2960     fail("Resumed invalid parse not faulted");
2961   if (XML_GetErrorCode(g_parser) != XML_ERROR_UNCLOSED_TOKEN)
2962     fail("Invalid parse not correctly faulted");
2963 }
2964 END_TEST
2965 
2966 /* Test that re-suspended parses are correctly passed through */
2967 START_TEST(test_resume_resuspended) {
2968   const char *text = "<doc>Hello<meep/>world</doc>";
2969 
2970   resumable = XML_TRUE;
2971   XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2972   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
2973       == XML_STATUS_ERROR)
2974     xml_failure(g_parser);
2975   resumable = XML_TRUE;
2976   XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2977   if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
2978     fail("Resumption not suspended");
2979   /* This one should succeed and finish up */
2980   if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
2981     xml_failure(g_parser);
2982 }
2983 END_TEST
2984 
2985 /* Test that CDATA shows up correctly through a default handler */
2986 START_TEST(test_cdata_default) {
2987   const char *text = "<doc><![CDATA[Hello\nworld]]></doc>";
2988   const XML_Char *expected = XCS("<doc><![CDATA[Hello\nworld]]></doc>");
2989   CharData storage;
2990 
2991   CharData_Init(&storage);
2992   XML_SetUserData(g_parser, &storage);
2993   XML_SetDefaultHandler(g_parser, accumulate_characters);
2994 
2995   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2996       == XML_STATUS_ERROR)
2997     xml_failure(g_parser);
2998   CharData_CheckXMLChars(&storage, expected);
2999 }
3000 END_TEST
3001 
3002 /* Test resetting a subordinate parser does exactly nothing */
3003 static int XMLCALL
3004 external_entity_resetter(XML_Parser parser, const XML_Char *context,
3005                          const XML_Char *base, const XML_Char *systemId,
3006                          const XML_Char *publicId) {
3007   const char *text = "<!ELEMENT doc (#PCDATA)*>";
3008   XML_Parser ext_parser;
3009   XML_ParsingStatus status;
3010 
3011   UNUSED_P(base);
3012   UNUSED_P(systemId);
3013   UNUSED_P(publicId);
3014   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3015   if (ext_parser == NULL)
3016     fail("Could not create external entity parser");
3017   XML_GetParsingStatus(ext_parser, &status);
3018   if (status.parsing != XML_INITIALIZED) {
3019     fail("Parsing status is not INITIALIZED");
3020     return XML_STATUS_ERROR;
3021   }
3022   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3023       == XML_STATUS_ERROR) {
3024     xml_failure(parser);
3025     return XML_STATUS_ERROR;
3026   }
3027   XML_GetParsingStatus(ext_parser, &status);
3028   if (status.parsing != XML_FINISHED) {
3029     fail("Parsing status is not FINISHED");
3030     return XML_STATUS_ERROR;
3031   }
3032   /* Check we can't parse here */
3033   if (XML_Parse(ext_parser, text, (int)strlen(text), XML_TRUE)
3034       != XML_STATUS_ERROR)
3035     fail("Parsing when finished not faulted");
3036   if (XML_GetErrorCode(ext_parser) != XML_ERROR_FINISHED)
3037     fail("Parsing when finished faulted with wrong code");
3038   XML_ParserReset(ext_parser, NULL);
3039   XML_GetParsingStatus(ext_parser, &status);
3040   if (status.parsing != XML_FINISHED) {
3041     fail("Parsing status not still FINISHED");
3042     return XML_STATUS_ERROR;
3043   }
3044   XML_ParserFree(ext_parser);
3045   return XML_STATUS_OK;
3046 }
3047 
3048 START_TEST(test_subordinate_reset) {
3049   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3050                      "<!DOCTYPE doc SYSTEM 'foo'>\n"
3051                      "<doc>&entity;</doc>";
3052 
3053   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3054   XML_SetExternalEntityRefHandler(g_parser, external_entity_resetter);
3055   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3056       == XML_STATUS_ERROR)
3057     xml_failure(g_parser);
3058 }
3059 END_TEST
3060 
3061 /* Test suspending a subordinate parser */
3062 
3063 static void XMLCALL
3064 entity_suspending_decl_handler(void *userData, const XML_Char *name,
3065                                XML_Content *model) {
3066   XML_Parser ext_parser = (XML_Parser)userData;
3067 
3068   UNUSED_P(name);
3069   if (XML_StopParser(ext_parser, XML_TRUE) != XML_STATUS_ERROR)
3070     fail("Attempting to suspend a subordinate parser not faulted");
3071   if (XML_GetErrorCode(ext_parser) != XML_ERROR_SUSPEND_PE)
3072     fail("Suspending subordinate parser get wrong code");
3073   XML_SetElementDeclHandler(ext_parser, NULL);
3074   XML_FreeContentModel(g_parser, model);
3075 }
3076 
3077 static int XMLCALL
3078 external_entity_suspender(XML_Parser parser, const XML_Char *context,
3079                           const XML_Char *base, const XML_Char *systemId,
3080                           const XML_Char *publicId) {
3081   const char *text = "<!ELEMENT doc (#PCDATA)*>";
3082   XML_Parser ext_parser;
3083 
3084   UNUSED_P(base);
3085   UNUSED_P(systemId);
3086   UNUSED_P(publicId);
3087   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3088   if (ext_parser == NULL)
3089     fail("Could not create external entity parser");
3090   XML_SetElementDeclHandler(ext_parser, entity_suspending_decl_handler);
3091   XML_SetUserData(ext_parser, ext_parser);
3092   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3093       == XML_STATUS_ERROR) {
3094     xml_failure(ext_parser);
3095     return XML_STATUS_ERROR;
3096   }
3097   XML_ParserFree(ext_parser);
3098   return XML_STATUS_OK;
3099 }
3100 
3101 START_TEST(test_subordinate_suspend) {
3102   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3103                      "<!DOCTYPE doc SYSTEM 'foo'>\n"
3104                      "<doc>&entity;</doc>";
3105 
3106   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3107   XML_SetExternalEntityRefHandler(g_parser, external_entity_suspender);
3108   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3109       == XML_STATUS_ERROR)
3110     xml_failure(g_parser);
3111 }
3112 END_TEST
3113 
3114 /* Test suspending a subordinate parser from an XML declaration */
3115 /* Increases code coverage of the tests */
3116 static void XMLCALL
3117 entity_suspending_xdecl_handler(void *userData, const XML_Char *version,
3118                                 const XML_Char *encoding, int standalone) {
3119   XML_Parser ext_parser = (XML_Parser)userData;
3120 
3121   UNUSED_P(version);
3122   UNUSED_P(encoding);
3123   UNUSED_P(standalone);
3124   XML_StopParser(ext_parser, resumable);
3125   XML_SetXmlDeclHandler(ext_parser, NULL);
3126 }
3127 
3128 static int XMLCALL
3129 external_entity_suspend_xmldecl(XML_Parser parser, const XML_Char *context,
3130                                 const XML_Char *base, const XML_Char *systemId,
3131                                 const XML_Char *publicId) {
3132   const char *text = "<?xml version='1.0' encoding='us-ascii'?>";
3133   XML_Parser ext_parser;
3134   XML_ParsingStatus status;
3135   enum XML_Status rc;
3136 
3137   UNUSED_P(base);
3138   UNUSED_P(systemId);
3139   UNUSED_P(publicId);
3140   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3141   if (ext_parser == NULL)
3142     fail("Could not create external entity parser");
3143   XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
3144   XML_SetUserData(ext_parser, ext_parser);
3145   rc = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
3146   XML_GetParsingStatus(ext_parser, &status);
3147   if (resumable) {
3148     if (rc == XML_STATUS_ERROR)
3149       xml_failure(ext_parser);
3150     if (status.parsing != XML_SUSPENDED)
3151       fail("Ext Parsing status not SUSPENDED");
3152   } else {
3153     if (rc != XML_STATUS_ERROR)
3154       fail("Ext parsing not aborted");
3155     if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
3156       xml_failure(ext_parser);
3157     if (status.parsing != XML_FINISHED)
3158       fail("Ext Parsing status not FINISHED");
3159   }
3160 
3161   XML_ParserFree(ext_parser);
3162   return XML_STATUS_OK;
3163 }
3164 
3165 START_TEST(test_subordinate_xdecl_suspend) {
3166   const char *text
3167       = "<!DOCTYPE doc [\n"
3168         "  <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
3169         "]>\n"
3170         "<doc>&entity;</doc>";
3171 
3172   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3173   XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
3174   resumable = XML_TRUE;
3175   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3176       == XML_STATUS_ERROR)
3177     xml_failure(g_parser);
3178 }
3179 END_TEST
3180 
3181 START_TEST(test_subordinate_xdecl_abort) {
3182   const char *text
3183       = "<!DOCTYPE doc [\n"
3184         "  <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
3185         "]>\n"
3186         "<doc>&entity;</doc>";
3187 
3188   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3189   XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
3190   resumable = XML_FALSE;
3191   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3192       == XML_STATUS_ERROR)
3193     xml_failure(g_parser);
3194 }
3195 END_TEST
3196 
3197 /* Test external entity fault handling with suspension */
3198 static int XMLCALL
3199 external_entity_suspending_faulter(XML_Parser parser, const XML_Char *context,
3200                                    const XML_Char *base,
3201                                    const XML_Char *systemId,
3202                                    const XML_Char *publicId) {
3203   XML_Parser ext_parser;
3204   ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
3205   void *buffer;
3206   int parse_len = (int)strlen(fault->parse_text);
3207 
3208   UNUSED_P(base);
3209   UNUSED_P(systemId);
3210   UNUSED_P(publicId);
3211   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3212   if (ext_parser == NULL)
3213     fail("Could not create external entity parser");
3214   XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
3215   XML_SetUserData(ext_parser, ext_parser);
3216   resumable = XML_TRUE;
3217   buffer = XML_GetBuffer(ext_parser, parse_len);
3218   if (buffer == NULL)
3219     fail("Could not allocate parse buffer");
3220   assert(buffer != NULL);
3221   memcpy(buffer, fault->parse_text, parse_len);
3222   if (XML_ParseBuffer(ext_parser, parse_len, XML_FALSE) != XML_STATUS_SUSPENDED)
3223     fail("XML declaration did not suspend");
3224   if (XML_ResumeParser(ext_parser) != XML_STATUS_OK)
3225     xml_failure(ext_parser);
3226   if (XML_ParseBuffer(ext_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
3227     fail(fault->fail_text);
3228   if (XML_GetErrorCode(ext_parser) != fault->error)
3229     xml_failure(ext_parser);
3230 
3231   XML_ParserFree(ext_parser);
3232   return XML_STATUS_ERROR;
3233 }
3234 
3235 START_TEST(test_ext_entity_invalid_suspended_parse) {
3236   const char *text = "<!DOCTYPE doc [\n"
3237                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3238                      "]>\n"
3239                      "<doc>&en;</doc>";
3240   ExtFaults faults[]
3241       = {{"<?xml version='1.0' encoding='us-ascii'?><",
3242           "Incomplete element declaration not faulted", NULL,
3243           XML_ERROR_UNCLOSED_TOKEN},
3244          {/* First two bytes of a three-byte char */
3245           "<?xml version='1.0' encoding='utf-8'?>\xe2\x82",
3246           "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
3247          {NULL, NULL, NULL, XML_ERROR_NONE}};
3248   ExtFaults *fault;
3249 
3250   for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
3251     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3252     XML_SetExternalEntityRefHandler(g_parser,
3253                                     external_entity_suspending_faulter);
3254     XML_SetUserData(g_parser, fault);
3255     expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
3256                    "Parser did not report external entity error");
3257     XML_ParserReset(g_parser, NULL);
3258   }
3259 }
3260 END_TEST
3261 
3262 /* Test setting an explicit encoding */
3263 START_TEST(test_explicit_encoding) {
3264   const char *text1 = "<doc>Hello ";
3265   const char *text2 = " World</doc>";
3266 
3267   /* Just check that we can set the encoding to NULL before starting */
3268   if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
3269     fail("Failed to initialise encoding to NULL");
3270   /* Say we are UTF-8 */
3271   if (XML_SetEncoding(g_parser, XCS("utf-8")) != XML_STATUS_OK)
3272     fail("Failed to set explicit encoding");
3273   if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
3274       == XML_STATUS_ERROR)
3275     xml_failure(g_parser);
3276   /* Try to switch encodings mid-parse */
3277   if (XML_SetEncoding(g_parser, XCS("us-ascii")) != XML_STATUS_ERROR)
3278     fail("Allowed encoding change");
3279   if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
3280       == XML_STATUS_ERROR)
3281     xml_failure(g_parser);
3282   /* Try now the parse is over */
3283   if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
3284     fail("Failed to unset encoding");
3285 }
3286 END_TEST
3287 
3288 /* Test handling of trailing CR (rather than newline) */
3289 static void XMLCALL
3290 cr_cdata_handler(void *userData, const XML_Char *s, int len) {
3291   int *pfound = (int *)userData;
3292 
3293   /* Internal processing turns the CR into a newline for the
3294    * character data handler, but not for the default handler
3295    */
3296   if (len == 1 && (*s == XCS('\n') || *s == XCS('\r')))
3297     *pfound = 1;
3298 }
3299 
3300 START_TEST(test_trailing_cr) {
3301   const char *text = "<doc>\r";
3302   int found_cr;
3303 
3304   /* Try with a character handler, for code coverage */
3305   XML_SetCharacterDataHandler(g_parser, cr_cdata_handler);
3306   XML_SetUserData(g_parser, &found_cr);
3307   found_cr = 0;
3308   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3309       == XML_STATUS_OK)
3310     fail("Failed to fault unclosed doc");
3311   if (found_cr == 0)
3312     fail("Did not catch the carriage return");
3313   XML_ParserReset(g_parser, NULL);
3314 
3315   /* Now with a default handler instead */
3316   XML_SetDefaultHandler(g_parser, cr_cdata_handler);
3317   XML_SetUserData(g_parser, &found_cr);
3318   found_cr = 0;
3319   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3320       == XML_STATUS_OK)
3321     fail("Failed to fault unclosed doc");
3322   if (found_cr == 0)
3323     fail("Did not catch default carriage return");
3324 }
3325 END_TEST
3326 
3327 /* Test trailing CR in an external entity parse */
3328 static int XMLCALL
3329 external_entity_cr_catcher(XML_Parser parser, const XML_Char *context,
3330                            const XML_Char *base, const XML_Char *systemId,
3331                            const XML_Char *publicId) {
3332   const char *text = "\r";
3333   XML_Parser ext_parser;
3334 
3335   UNUSED_P(base);
3336   UNUSED_P(systemId);
3337   UNUSED_P(publicId);
3338   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3339   if (ext_parser == NULL)
3340     fail("Could not create external entity parser");
3341   XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
3342   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3343       == XML_STATUS_ERROR)
3344     xml_failure(ext_parser);
3345   XML_ParserFree(ext_parser);
3346   return XML_STATUS_OK;
3347 }
3348 
3349 static int XMLCALL
3350 external_entity_bad_cr_catcher(XML_Parser parser, const XML_Char *context,
3351                                const XML_Char *base, const XML_Char *systemId,
3352                                const XML_Char *publicId) {
3353   const char *text = "<tag>\r";
3354   XML_Parser ext_parser;
3355 
3356   UNUSED_P(base);
3357   UNUSED_P(systemId);
3358   UNUSED_P(publicId);
3359   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3360   if (ext_parser == NULL)
3361     fail("Could not create external entity parser");
3362   XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
3363   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3364       == XML_STATUS_OK)
3365     fail("Async entity error not caught");
3366   if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
3367     xml_failure(ext_parser);
3368   XML_ParserFree(ext_parser);
3369   return XML_STATUS_OK;
3370 }
3371 
3372 START_TEST(test_ext_entity_trailing_cr) {
3373   const char *text = "<!DOCTYPE doc [\n"
3374                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3375                      "]>\n"
3376                      "<doc>&en;</doc>";
3377   int found_cr;
3378 
3379   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3380   XML_SetExternalEntityRefHandler(g_parser, external_entity_cr_catcher);
3381   XML_SetUserData(g_parser, &found_cr);
3382   found_cr = 0;
3383   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3384       != XML_STATUS_OK)
3385     xml_failure(g_parser);
3386   if (found_cr == 0)
3387     fail("No carriage return found");
3388   XML_ParserReset(g_parser, NULL);
3389 
3390   /* Try again with a different trailing CR */
3391   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3392   XML_SetExternalEntityRefHandler(g_parser, external_entity_bad_cr_catcher);
3393   XML_SetUserData(g_parser, &found_cr);
3394   found_cr = 0;
3395   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3396       != XML_STATUS_OK)
3397     xml_failure(g_parser);
3398   if (found_cr == 0)
3399     fail("No carriage return found");
3400 }
3401 END_TEST
3402 
3403 /* Test handling of trailing square bracket */
3404 static void XMLCALL
3405 rsqb_handler(void *userData, const XML_Char *s, int len) {
3406   int *pfound = (int *)userData;
3407 
3408   if (len == 1 && *s == XCS(']'))
3409     *pfound = 1;
3410 }
3411 
3412 START_TEST(test_trailing_rsqb) {
3413   const char *text8 = "<doc>]";
3414   const char text16[] = "\xFF\xFE<\000d\000o\000c\000>\000]\000";
3415   int found_rsqb;
3416   int text8_len = (int)strlen(text8);
3417 
3418   XML_SetCharacterDataHandler(g_parser, rsqb_handler);
3419   XML_SetUserData(g_parser, &found_rsqb);
3420   found_rsqb = 0;
3421   if (_XML_Parse_SINGLE_BYTES(g_parser, text8, text8_len, XML_TRUE)
3422       == XML_STATUS_OK)
3423     fail("Failed to fault unclosed doc");
3424   if (found_rsqb == 0)
3425     fail("Did not catch the right square bracket");
3426 
3427   /* Try again with a different encoding */
3428   XML_ParserReset(g_parser, NULL);
3429   XML_SetCharacterDataHandler(g_parser, rsqb_handler);
3430   XML_SetUserData(g_parser, &found_rsqb);
3431   found_rsqb = 0;
3432   if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
3433                               XML_TRUE)
3434       == XML_STATUS_OK)
3435     fail("Failed to fault unclosed doc");
3436   if (found_rsqb == 0)
3437     fail("Did not catch the right square bracket");
3438 
3439   /* And finally with a default handler */
3440   XML_ParserReset(g_parser, NULL);
3441   XML_SetDefaultHandler(g_parser, rsqb_handler);
3442   XML_SetUserData(g_parser, &found_rsqb);
3443   found_rsqb = 0;
3444   if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
3445                               XML_TRUE)
3446       == XML_STATUS_OK)
3447     fail("Failed to fault unclosed doc");
3448   if (found_rsqb == 0)
3449     fail("Did not catch the right square bracket");
3450 }
3451 END_TEST
3452 
3453 /* Test trailing right square bracket in an external entity parse */
3454 static int XMLCALL
3455 external_entity_rsqb_catcher(XML_Parser parser, const XML_Char *context,
3456                              const XML_Char *base, const XML_Char *systemId,
3457                              const XML_Char *publicId) {
3458   const char *text = "<tag>]";
3459   XML_Parser ext_parser;
3460 
3461   UNUSED_P(base);
3462   UNUSED_P(systemId);
3463   UNUSED_P(publicId);
3464   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3465   if (ext_parser == NULL)
3466     fail("Could not create external entity parser");
3467   XML_SetCharacterDataHandler(ext_parser, rsqb_handler);
3468   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3469       != XML_STATUS_ERROR)
3470     fail("Async entity error not caught");
3471   if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
3472     xml_failure(ext_parser);
3473   XML_ParserFree(ext_parser);
3474   return XML_STATUS_OK;
3475 }
3476 
3477 START_TEST(test_ext_entity_trailing_rsqb) {
3478   const char *text = "<!DOCTYPE doc [\n"
3479                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3480                      "]>\n"
3481                      "<doc>&en;</doc>";
3482   int found_rsqb;
3483 
3484   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3485   XML_SetExternalEntityRefHandler(g_parser, external_entity_rsqb_catcher);
3486   XML_SetUserData(g_parser, &found_rsqb);
3487   found_rsqb = 0;
3488   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3489       != XML_STATUS_OK)
3490     xml_failure(g_parser);
3491   if (found_rsqb == 0)
3492     fail("No right square bracket found");
3493 }
3494 END_TEST
3495 
3496 /* Test CDATA handling in an external entity */
3497 static int XMLCALL
3498 external_entity_good_cdata_ascii(XML_Parser parser, const XML_Char *context,
3499                                  const XML_Char *base, const XML_Char *systemId,
3500                                  const XML_Char *publicId) {
3501   const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
3502   const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
3503   CharData storage;
3504   XML_Parser ext_parser;
3505 
3506   UNUSED_P(base);
3507   UNUSED_P(systemId);
3508   UNUSED_P(publicId);
3509   CharData_Init(&storage);
3510   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3511   if (ext_parser == NULL)
3512     fail("Could not create external entity parser");
3513   XML_SetUserData(ext_parser, &storage);
3514   XML_SetCharacterDataHandler(ext_parser, accumulate_characters);
3515 
3516   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3517       == XML_STATUS_ERROR)
3518     xml_failure(ext_parser);
3519   CharData_CheckXMLChars(&storage, expected);
3520 
3521   XML_ParserFree(ext_parser);
3522   return XML_STATUS_OK;
3523 }
3524 
3525 START_TEST(test_ext_entity_good_cdata) {
3526   const char *text = "<!DOCTYPE doc [\n"
3527                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3528                      "]>\n"
3529                      "<doc>&en;</doc>";
3530 
3531   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3532   XML_SetExternalEntityRefHandler(g_parser, external_entity_good_cdata_ascii);
3533   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3534       != XML_STATUS_OK)
3535     xml_failure(g_parser);
3536 }
3537 END_TEST
3538 
3539 /* Test user parameter settings */
3540 /* Variable holding the expected handler userData */
3541 static void *handler_data = NULL;
3542 /* Count of the number of times the comment handler has been invoked */
3543 static int comment_count = 0;
3544 /* Count of the number of skipped entities */
3545 static int skip_count = 0;
3546 /* Count of the number of times the XML declaration handler is invoked */
3547 static int xdecl_count = 0;
3548 
3549 static void XMLCALL
3550 xml_decl_handler(void *userData, const XML_Char *version,
3551                  const XML_Char *encoding, int standalone) {
3552   UNUSED_P(version);
3553   UNUSED_P(encoding);
3554   if (userData != handler_data)
3555     fail("User data (xml decl) not correctly set");
3556   if (standalone != -1)
3557     fail("Standalone not flagged as not present in XML decl");
3558   xdecl_count++;
3559 }
3560 
3561 static void XMLCALL
3562 param_check_skip_handler(void *userData, const XML_Char *entityName,
3563                          int is_parameter_entity) {
3564   UNUSED_P(entityName);
3565   UNUSED_P(is_parameter_entity);
3566   if (userData != handler_data)
3567     fail("User data (skip) not correctly set");
3568   skip_count++;
3569 }
3570 
3571 static void XMLCALL
3572 data_check_comment_handler(void *userData, const XML_Char *data) {
3573   UNUSED_P(data);
3574   /* Check that the userData passed through is what we expect */
3575   if (userData != handler_data)
3576     fail("User data (parser) not correctly set");
3577   /* Check that the user data in the parser is appropriate */
3578   if (XML_GetUserData(userData) != (void *)1)
3579     fail("User data in parser not correctly set");
3580   comment_count++;
3581 }
3582 
3583 static int XMLCALL
3584 external_entity_param_checker(XML_Parser parser, const XML_Char *context,
3585                               const XML_Char *base, const XML_Char *systemId,
3586                               const XML_Char *publicId) {
3587   const char *text = "<!-- Subordinate parser -->\n"
3588                      "<!ELEMENT doc (#PCDATA)*>";
3589   XML_Parser ext_parser;
3590 
3591   UNUSED_P(base);
3592   UNUSED_P(systemId);
3593   UNUSED_P(publicId);
3594   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3595   if (ext_parser == NULL)
3596     fail("Could not create external entity parser");
3597   handler_data = ext_parser;
3598   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3599       == XML_STATUS_ERROR) {
3600     xml_failure(parser);
3601     return XML_STATUS_ERROR;
3602   }
3603   handler_data = parser;
3604   XML_ParserFree(ext_parser);
3605   return XML_STATUS_OK;
3606 }
3607 
3608 START_TEST(test_user_parameters) {
3609   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3610                      "<!-- Primary parse -->\n"
3611                      "<!DOCTYPE doc SYSTEM 'foo'>\n"
3612                      "<doc>&entity;";
3613   const char *epilog = "<!-- Back to primary parser -->\n"
3614                        "</doc>";
3615 
3616   comment_count = 0;
3617   skip_count = 0;
3618   xdecl_count = 0;
3619   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3620   XML_SetXmlDeclHandler(g_parser, xml_decl_handler);
3621   XML_SetExternalEntityRefHandler(g_parser, external_entity_param_checker);
3622   XML_SetCommentHandler(g_parser, data_check_comment_handler);
3623   XML_SetSkippedEntityHandler(g_parser, param_check_skip_handler);
3624   XML_UseParserAsHandlerArg(g_parser);
3625   XML_SetUserData(g_parser, (void *)1);
3626   handler_data = g_parser;
3627   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
3628       == XML_STATUS_ERROR)
3629     xml_failure(g_parser);
3630   if (comment_count != 2)
3631     fail("Comment handler not invoked enough times");
3632   /* Ensure we can't change policy mid-parse */
3633   if (XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_NEVER))
3634     fail("Changed param entity parsing policy while parsing");
3635   if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
3636       == XML_STATUS_ERROR)
3637     xml_failure(g_parser);
3638   if (comment_count != 3)
3639     fail("Comment handler not invoked enough times");
3640   if (skip_count != 1)
3641     fail("Skip handler not invoked enough times");
3642   if (xdecl_count != 1)
3643     fail("XML declaration handler not invoked");
3644 }
3645 END_TEST
3646 
3647 /* Test that an explicit external entity handler argument replaces
3648  * the parser as the first argument.
3649  *
3650  * We do not call the first parameter to the external entity handler
3651  * 'parser' for once, since the first time the handler is called it
3652  * will actually be a text string.  We need to be able to access the
3653  * global 'parser' variable to create our external entity parser from,
3654  * since there are code paths we need to ensure get executed.
3655  */
3656 static int XMLCALL
3657 external_entity_ref_param_checker(XML_Parser parameter, const XML_Char *context,
3658                                   const XML_Char *base,
3659                                   const XML_Char *systemId,
3660                                   const XML_Char *publicId) {
3661   const char *text = "<!ELEMENT doc (#PCDATA)*>";
3662   XML_Parser ext_parser;
3663 
3664   UNUSED_P(base);
3665   UNUSED_P(systemId);
3666   UNUSED_P(publicId);
3667   if ((void *)parameter != handler_data)
3668     fail("External entity ref handler parameter not correct");
3669 
3670   /* Here we use the global 'parser' variable */
3671   ext_parser = XML_ExternalEntityParserCreate(g_parser, context, NULL);
3672   if (ext_parser == NULL)
3673     fail("Could not create external entity parser");
3674   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3675       == XML_STATUS_ERROR)
3676     xml_failure(ext_parser);
3677 
3678   XML_ParserFree(ext_parser);
3679   return XML_STATUS_OK;
3680 }
3681 
3682 START_TEST(test_ext_entity_ref_parameter) {
3683   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3684                      "<!DOCTYPE doc SYSTEM 'foo'>\n"
3685                      "<doc>&entity;</doc>";
3686 
3687   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3688   XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
3689   /* Set a handler arg that is not NULL and not parser (which is
3690    * what NULL would cause to be passed.
3691    */
3692   XML_SetExternalEntityRefHandlerArg(g_parser, (void *)text);
3693   handler_data = (void *)text;
3694   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3695       == XML_STATUS_ERROR)
3696     xml_failure(g_parser);
3697 
3698   /* Now try again with unset args */
3699   XML_ParserReset(g_parser, NULL);
3700   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3701   XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
3702   XML_SetExternalEntityRefHandlerArg(g_parser, NULL);
3703   handler_data = (void *)g_parser;
3704   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3705       == XML_STATUS_ERROR)
3706     xml_failure(g_parser);
3707 }
3708 END_TEST
3709 
3710 /* Test the parsing of an empty string */
3711 START_TEST(test_empty_parse) {
3712   const char *text = "<doc></doc>";
3713   const char *partial = "<doc>";
3714 
3715   if (XML_Parse(g_parser, NULL, 0, XML_FALSE) == XML_STATUS_ERROR)
3716     fail("Parsing empty string faulted");
3717   if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
3718     fail("Parsing final empty string not faulted");
3719   if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_ELEMENTS)
3720     fail("Parsing final empty string faulted for wrong reason");
3721 
3722   /* Now try with valid text before the empty end */
3723   XML_ParserReset(g_parser, NULL);
3724   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
3725       == XML_STATUS_ERROR)
3726     xml_failure(g_parser);
3727   if (XML_Parse(g_parser, NULL, 0, XML_TRUE) == XML_STATUS_ERROR)
3728     fail("Parsing final empty string faulted");
3729 
3730   /* Now try with invalid text before the empty end */
3731   XML_ParserReset(g_parser, NULL);
3732   if (_XML_Parse_SINGLE_BYTES(g_parser, partial, (int)strlen(partial),
3733                               XML_FALSE)
3734       == XML_STATUS_ERROR)
3735     xml_failure(g_parser);
3736   if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
3737     fail("Parsing final incomplete empty string not faulted");
3738 }
3739 END_TEST
3740 
3741 /* Test odd corners of the XML_GetBuffer interface */
3742 static enum XML_Status
3743 get_feature(enum XML_FeatureEnum feature_id, long *presult) {
3744   const XML_Feature *feature = XML_GetFeatureList();
3745 
3746   if (feature == NULL)
3747     return XML_STATUS_ERROR;
3748   for (; feature->feature != XML_FEATURE_END; feature++) {
3749     if (feature->feature == feature_id) {
3750       *presult = feature->value;
3751       return XML_STATUS_OK;
3752     }
3753   }
3754   return XML_STATUS_ERROR;
3755 }
3756 
3757 /* Having an element name longer than 1024 characters exercises some
3758  * of the pool allocation code in the parser that otherwise does not
3759  * get executed.  The count at the end of the line is the number of
3760  * characters (bytes) in the element name by that point.x
3761  */
3762 static const char *get_buffer_test_text
3763     = "<documentwitharidiculouslylongelementnametotease"  /* 0x030 */
3764       "aparticularcorneroftheallocationinXML_GetBuffers"  /* 0x060 */
3765       "othatwecanimprovethecoverageyetagain012345678901"  /* 0x090 */
3766       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x0c0 */
3767       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x0f0 */
3768       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x120 */
3769       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x150 */
3770       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x180 */
3771       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x1b0 */
3772       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x1e0 */
3773       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x210 */
3774       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x240 */
3775       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x270 */
3776       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x2a0 */
3777       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x2d0 */
3778       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x300 */
3779       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x330 */
3780       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x360 */
3781       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x390 */
3782       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x3c0 */
3783       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x3f0 */
3784       "123456789abcdef0123456789abcdef0123456789>\n<ef0"; /* 0x420 */
3785 
3786 /* Test odd corners of the XML_GetBuffer interface */
3787 START_TEST(test_get_buffer_1) {
3788   const char *text = get_buffer_test_text;
3789   void *buffer;
3790   long context_bytes;
3791 
3792   /* Attempt to allocate a negative length buffer */
3793   if (XML_GetBuffer(g_parser, -12) != NULL)
3794     fail("Negative length buffer not failed");
3795 
3796   /* Now get a small buffer and extend it past valid length */
3797   buffer = XML_GetBuffer(g_parser, 1536);
3798   if (buffer == NULL)
3799     fail("1.5K buffer failed");
3800   assert(buffer != NULL);
3801   memcpy(buffer, text, strlen(text));
3802   if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
3803       == XML_STATUS_ERROR)
3804     xml_failure(g_parser);
3805   if (XML_GetBuffer(g_parser, INT_MAX) != NULL)
3806     fail("INT_MAX buffer not failed");
3807 
3808   /* Now try extending it a more reasonable but still too large
3809    * amount.  The allocator in XML_GetBuffer() doubles the buffer
3810    * size until it exceeds the requested amount or INT_MAX.  If it
3811    * exceeds INT_MAX, it rejects the request, so we want a request
3812    * between INT_MAX and INT_MAX/2.  A gap of 1K seems comfortable,
3813    * with an extra byte just to ensure that the request is off any
3814    * boundary.  The request will be inflated internally by
3815    * XML_CONTEXT_BYTES (if defined), so we subtract that from our
3816    * request.
3817    */
3818   if (get_feature(XML_FEATURE_CONTEXT_BYTES, &context_bytes) != XML_STATUS_OK)
3819     context_bytes = 0;
3820   if (XML_GetBuffer(g_parser, INT_MAX - (context_bytes + 1025)) != NULL)
3821     fail("INT_MAX- buffer not failed");
3822 
3823   /* Now try extending it a carefully crafted amount */
3824   if (XML_GetBuffer(g_parser, 1000) == NULL)
3825     fail("1000 buffer failed");
3826 }
3827 END_TEST
3828 
3829 /* Test more corners of the XML_GetBuffer interface */
3830 START_TEST(test_get_buffer_2) {
3831   const char *text = get_buffer_test_text;
3832   void *buffer;
3833 
3834   /* Now get a decent buffer */
3835   buffer = XML_GetBuffer(g_parser, 1536);
3836   if (buffer == NULL)
3837     fail("1.5K buffer failed");
3838   assert(buffer != NULL);
3839   memcpy(buffer, text, strlen(text));
3840   if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
3841       == XML_STATUS_ERROR)
3842     xml_failure(g_parser);
3843 
3844   /* Extend it, to catch a different code path */
3845   if (XML_GetBuffer(g_parser, 1024) == NULL)
3846     fail("1024 buffer failed");
3847 }
3848 END_TEST
3849 
3850 /* Test position information macros */
3851 START_TEST(test_byte_info_at_end) {
3852   const char *text = "<doc></doc>";
3853 
3854   if (XML_GetCurrentByteIndex(g_parser) != -1
3855       || XML_GetCurrentByteCount(g_parser) != 0)
3856     fail("Byte index/count incorrect at start of parse");
3857   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3858       == XML_STATUS_ERROR)
3859     xml_failure(g_parser);
3860   /* At end, the count will be zero and the index the end of string */
3861   if (XML_GetCurrentByteCount(g_parser) != 0)
3862     fail("Terminal byte count incorrect");
3863   if (XML_GetCurrentByteIndex(g_parser) != (XML_Index)strlen(text))
3864     fail("Terminal byte index incorrect");
3865 }
3866 END_TEST
3867 
3868 /* Test position information from errors */
3869 #define PRE_ERROR_STR "<doc></"
3870 #define POST_ERROR_STR "wombat></doc>"
3871 START_TEST(test_byte_info_at_error) {
3872   const char *text = PRE_ERROR_STR POST_ERROR_STR;
3873 
3874   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3875       == XML_STATUS_OK)
3876     fail("Syntax error not faulted");
3877   if (XML_GetCurrentByteCount(g_parser) != 0)
3878     fail("Error byte count incorrect");
3879   if (XML_GetCurrentByteIndex(g_parser) != strlen(PRE_ERROR_STR))
3880     fail("Error byte index incorrect");
3881 }
3882 END_TEST
3883 #undef PRE_ERROR_STR
3884 #undef POST_ERROR_STR
3885 
3886 /* Test position information in handler */
3887 typedef struct ByteTestData {
3888   int start_element_len;
3889   int cdata_len;
3890   int total_string_len;
3891 } ByteTestData;
3892 
3893 static void
3894 byte_character_handler(void *userData, const XML_Char *s, int len) {
3895 #ifdef XML_CONTEXT_BYTES
3896   int offset, size;
3897   const char *buffer;
3898   ByteTestData *data = (ByteTestData *)userData;
3899 
3900   UNUSED_P(s);
3901   buffer = XML_GetInputContext(g_parser, &offset, &size);
3902   if (buffer == NULL)
3903     fail("Failed to get context buffer");
3904   if (offset != data->start_element_len)
3905     fail("Context offset in unexpected position");
3906   if (len != data->cdata_len)
3907     fail("CDATA length reported incorrectly");
3908   if (size != data->total_string_len)
3909     fail("Context size is not full buffer");
3910   if (XML_GetCurrentByteIndex(g_parser) != offset)
3911     fail("Character byte index incorrect");
3912   if (XML_GetCurrentByteCount(g_parser) != len)
3913     fail("Character byte count incorrect");
3914 #else
3915   UNUSED_P(s);
3916   UNUSED_P(userData);
3917   UNUSED_P(len);
3918 #endif
3919 }
3920 
3921 #define START_ELEMENT "<e>"
3922 #define CDATA_TEXT "Hello"
3923 #define END_ELEMENT "</e>"
3924 START_TEST(test_byte_info_at_cdata) {
3925   const char *text = START_ELEMENT CDATA_TEXT END_ELEMENT;
3926   int offset, size;
3927   ByteTestData data;
3928 
3929   /* Check initial context is empty */
3930   if (XML_GetInputContext(g_parser, &offset, &size) != NULL)
3931     fail("Unexpected context at start of parse");
3932 
3933   data.start_element_len = (int)strlen(START_ELEMENT);
3934   data.cdata_len = (int)strlen(CDATA_TEXT);
3935   data.total_string_len = (int)strlen(text);
3936   XML_SetCharacterDataHandler(g_parser, byte_character_handler);
3937   XML_SetUserData(g_parser, &data);
3938   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_OK)
3939     xml_failure(g_parser);
3940 }
3941 END_TEST
3942 #undef START_ELEMENT
3943 #undef CDATA_TEXT
3944 #undef END_ELEMENT
3945 
3946 /* Test predefined entities are correctly recognised */
3947 START_TEST(test_predefined_entities) {
3948   const char *text = "<doc>&lt;&gt;&amp;&quot;&apos;</doc>";
3949   const XML_Char *expected = XCS("<doc>&lt;&gt;&amp;&quot;&apos;</doc>");
3950   const XML_Char *result = XCS("<>&\"'");
3951   CharData storage;
3952 
3953   XML_SetDefaultHandler(g_parser, accumulate_characters);
3954   /* run_character_check uses XML_SetCharacterDataHandler(), which
3955    * unfortunately heads off a code path that we need to exercise.
3956    */
3957   CharData_Init(&storage);
3958   XML_SetUserData(g_parser, &storage);
3959   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3960       == XML_STATUS_ERROR)
3961     xml_failure(g_parser);
3962   /* The default handler doesn't translate the entities */
3963   CharData_CheckXMLChars(&storage, expected);
3964 
3965   /* Now try again and check the translation */
3966   XML_ParserReset(g_parser, NULL);
3967   run_character_check(text, result);
3968 }
3969 END_TEST
3970 
3971 /* Regression test that an invalid tag in an external parameter
3972  * reference in an external DTD is correctly faulted.
3973  *
3974  * Only a few specific tags are legal in DTDs ignoring comments and
3975  * processing instructions, all of which begin with an exclamation
3976  * mark.  "<el/>" is not one of them, so the parser should raise an
3977  * error on encountering it.
3978  */
3979 static int XMLCALL
3980 external_entity_param(XML_Parser parser, const XML_Char *context,
3981                       const XML_Char *base, const XML_Char *systemId,
3982                       const XML_Char *publicId) {
3983   const char *text1 = "<!ELEMENT doc EMPTY>\n"
3984                       "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
3985                       "<!ENTITY % e2 '%e1;'>\n"
3986                       "%e1;\n";
3987   const char *text2 = "<!ELEMENT el EMPTY>\n"
3988                       "<el/>\n";
3989   XML_Parser ext_parser;
3990 
3991   UNUSED_P(base);
3992   UNUSED_P(publicId);
3993   if (systemId == NULL)
3994     return XML_STATUS_OK;
3995 
3996   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3997   if (ext_parser == NULL)
3998     fail("Could not create external entity parser");
3999 
4000   if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
4001     if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
4002         != XML_STATUS_ERROR)
4003       fail("Inner DTD with invalid tag not rejected");
4004     if (XML_GetErrorCode(ext_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING)
4005       xml_failure(ext_parser);
4006   } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
4007     if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
4008         != XML_STATUS_ERROR)
4009       fail("Invalid tag in external param not rejected");
4010     if (XML_GetErrorCode(ext_parser) != XML_ERROR_SYNTAX)
4011       xml_failure(ext_parser);
4012   } else {
4013     fail("Unknown system ID");
4014   }
4015 
4016   XML_ParserFree(ext_parser);
4017   return XML_STATUS_ERROR;
4018 }
4019 
4020 START_TEST(test_invalid_tag_in_dtd) {
4021   const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
4022                      "<doc></doc>\n";
4023 
4024   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4025   XML_SetExternalEntityRefHandler(g_parser, external_entity_param);
4026   expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4027                  "Invalid tag IN DTD external param not rejected");
4028 }
4029 END_TEST
4030 
4031 /* Test entities not quite the predefined ones are not mis-recognised */
4032 START_TEST(test_not_predefined_entities) {
4033   const char *text[] = {"<doc>&pt;</doc>", "<doc>&amo;</doc>",
4034                         "<doc>&quid;</doc>", "<doc>&apod;</doc>", NULL};
4035   int i = 0;
4036 
4037   while (text[i] != NULL) {
4038     expect_failure(text[i], XML_ERROR_UNDEFINED_ENTITY,
4039                    "Undefined entity not rejected");
4040     XML_ParserReset(g_parser, NULL);
4041     i++;
4042   }
4043 }
4044 END_TEST
4045 
4046 /* Test conditional inclusion (IGNORE) */
4047 static int XMLCALL
4048 external_entity_load_ignore(XML_Parser parser, const XML_Char *context,
4049                             const XML_Char *base, const XML_Char *systemId,
4050                             const XML_Char *publicId) {
4051   const char *text = "<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>";
4052   XML_Parser ext_parser;
4053 
4054   UNUSED_P(base);
4055   UNUSED_P(systemId);
4056   UNUSED_P(publicId);
4057   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4058   if (ext_parser == NULL)
4059     fail("Could not create external entity parser");
4060   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
4061       == XML_STATUS_ERROR)
4062     xml_failure(parser);
4063 
4064   XML_ParserFree(ext_parser);
4065   return XML_STATUS_OK;
4066 }
4067 
4068 START_TEST(test_ignore_section) {
4069   const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4070                      "<doc><e>&entity;</e></doc>";
4071   const XML_Char *expected
4072       = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&entity;");
4073   CharData storage;
4074 
4075   CharData_Init(&storage);
4076   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4077   XML_SetUserData(g_parser, &storage);
4078   XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore);
4079   XML_SetDefaultHandler(g_parser, accumulate_characters);
4080   XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
4081   XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
4082   XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4083   XML_SetStartElementHandler(g_parser, dummy_start_element);
4084   XML_SetEndElementHandler(g_parser, dummy_end_element);
4085   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4086       == XML_STATUS_ERROR)
4087     xml_failure(g_parser);
4088   CharData_CheckXMLChars(&storage, expected);
4089 }
4090 END_TEST
4091 
4092 static int XMLCALL
4093 external_entity_load_ignore_utf16(XML_Parser parser, const XML_Char *context,
4094                                   const XML_Char *base,
4095                                   const XML_Char *systemId,
4096                                   const XML_Char *publicId) {
4097   const char text[] =
4098       /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
4099       "<\0!\0[\0I\0G\0N\0O\0R\0E\0[\0"
4100       "<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 \0"
4101       "(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>\0";
4102   XML_Parser ext_parser;
4103 
4104   UNUSED_P(base);
4105   UNUSED_P(systemId);
4106   UNUSED_P(publicId);
4107   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4108   if (ext_parser == NULL)
4109     fail("Could not create external entity parser");
4110   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4111       == XML_STATUS_ERROR)
4112     xml_failure(parser);
4113 
4114   XML_ParserFree(ext_parser);
4115   return XML_STATUS_OK;
4116 }
4117 
4118 START_TEST(test_ignore_section_utf16) {
4119   const char text[] =
4120       /* <!DOCTYPE d SYSTEM 's'> */
4121       "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
4122       "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n\0"
4123       /* <d><e>&en;</e></d> */
4124       "<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>\0";
4125   const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
4126   CharData storage;
4127 
4128   CharData_Init(&storage);
4129   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4130   XML_SetUserData(g_parser, &storage);
4131   XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore_utf16);
4132   XML_SetDefaultHandler(g_parser, accumulate_characters);
4133   XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
4134   XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
4135   XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4136   XML_SetStartElementHandler(g_parser, dummy_start_element);
4137   XML_SetEndElementHandler(g_parser, dummy_end_element);
4138   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4139       == XML_STATUS_ERROR)
4140     xml_failure(g_parser);
4141   CharData_CheckXMLChars(&storage, expected);
4142 }
4143 END_TEST
4144 
4145 static int XMLCALL
4146 external_entity_load_ignore_utf16_be(XML_Parser parser, const XML_Char *context,
4147                                      const XML_Char *base,
4148                                      const XML_Char *systemId,
4149                                      const XML_Char *publicId) {
4150   const char text[] =
4151       /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
4152       "\0<\0!\0[\0I\0G\0N\0O\0R\0E\0["
4153       "\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 "
4154       "\0(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>";
4155   XML_Parser ext_parser;
4156 
4157   UNUSED_P(base);
4158   UNUSED_P(systemId);
4159   UNUSED_P(publicId);
4160   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4161   if (ext_parser == NULL)
4162     fail("Could not create external entity parser");
4163   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4164       == XML_STATUS_ERROR)
4165     xml_failure(parser);
4166 
4167   XML_ParserFree(ext_parser);
4168   return XML_STATUS_OK;
4169 }
4170 
4171 START_TEST(test_ignore_section_utf16_be) {
4172   const char text[] =
4173       /* <!DOCTYPE d SYSTEM 's'> */
4174       "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
4175       "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n"
4176       /* <d><e>&en;</e></d> */
4177       "\0<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>";
4178   const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
4179   CharData storage;
4180 
4181   CharData_Init(&storage);
4182   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4183   XML_SetUserData(g_parser, &storage);
4184   XML_SetExternalEntityRefHandler(g_parser,
4185                                   external_entity_load_ignore_utf16_be);
4186   XML_SetDefaultHandler(g_parser, accumulate_characters);
4187   XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
4188   XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
4189   XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4190   XML_SetStartElementHandler(g_parser, dummy_start_element);
4191   XML_SetEndElementHandler(g_parser, dummy_end_element);
4192   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4193       == XML_STATUS_ERROR)
4194     xml_failure(g_parser);
4195   CharData_CheckXMLChars(&storage, expected);
4196 }
4197 END_TEST
4198 
4199 /* Test mis-formatted conditional exclusion */
4200 START_TEST(test_bad_ignore_section) {
4201   const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4202                      "<doc><e>&entity;</e></doc>";
4203   ExtFaults faults[]
4204       = {{"<![IGNORE[<!ELEM", "Broken-off declaration not faulted", NULL,
4205           XML_ERROR_SYNTAX},
4206          {"<![IGNORE[\x01]]>", "Invalid XML character not faulted", NULL,
4207           XML_ERROR_INVALID_TOKEN},
4208          {/* FIrst two bytes of a three-byte char */
4209           "<![IGNORE[\xe2\x82", "Partial XML character not faulted", NULL,
4210           XML_ERROR_PARTIAL_CHAR},
4211          {NULL, NULL, NULL, XML_ERROR_NONE}};
4212   ExtFaults *fault;
4213 
4214   for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
4215     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4216     XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
4217     XML_SetUserData(g_parser, fault);
4218     expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4219                    "Incomplete IGNORE section not failed");
4220     XML_ParserReset(g_parser, NULL);
4221   }
4222 }
4223 END_TEST
4224 
4225 /* Test recursive parsing */
4226 static int XMLCALL
4227 external_entity_valuer(XML_Parser parser, const XML_Char *context,
4228                        const XML_Char *base, const XML_Char *systemId,
4229                        const XML_Char *publicId) {
4230   const char *text1 = "<!ELEMENT doc EMPTY>\n"
4231                       "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
4232                       "<!ENTITY % e2 '%e1;'>\n"
4233                       "%e1;\n";
4234   XML_Parser ext_parser;
4235 
4236   UNUSED_P(base);
4237   UNUSED_P(publicId);
4238   if (systemId == NULL)
4239     return XML_STATUS_OK;
4240   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4241   if (ext_parser == NULL)
4242     fail("Could not create external entity parser");
4243   if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
4244     if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
4245         == XML_STATUS_ERROR)
4246       xml_failure(ext_parser);
4247   } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
4248     ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
4249     enum XML_Status status;
4250     enum XML_Error error;
4251 
4252     status = _XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
4253                                      (int)strlen(fault->parse_text), XML_TRUE);
4254     if (fault->error == XML_ERROR_NONE) {
4255       if (status == XML_STATUS_ERROR)
4256         xml_failure(ext_parser);
4257     } else {
4258       if (status != XML_STATUS_ERROR)
4259         fail(fault->fail_text);
4260       error = XML_GetErrorCode(ext_parser);
4261       if (error != fault->error
4262           && (fault->error != XML_ERROR_XML_DECL
4263               || error != XML_ERROR_TEXT_DECL))
4264         xml_failure(ext_parser);
4265     }
4266   }
4267 
4268   XML_ParserFree(ext_parser);
4269   return XML_STATUS_OK;
4270 }
4271 
4272 START_TEST(test_external_entity_values) {
4273   const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
4274                      "<doc></doc>\n";
4275   ExtFaults data_004_2[] = {
4276       {"<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL, XML_ERROR_NONE},
4277       {"<!ATTLIST $doc a1 CDATA 'value'>", "Invalid token not faulted", NULL,
4278        XML_ERROR_INVALID_TOKEN},
4279       {"'wombat", "Unterminated string not faulted", NULL,
4280        XML_ERROR_UNCLOSED_TOKEN},
4281       {"\xe2\x82", "Partial UTF-8 character not faulted", NULL,
4282        XML_ERROR_PARTIAL_CHAR},
4283       {"<?xml version='1.0' encoding='utf-8'?>\n", NULL, NULL, XML_ERROR_NONE},
4284       {"<?xml?>", "Malformed XML declaration not faulted", NULL,
4285        XML_ERROR_XML_DECL},
4286       {/* UTF-8 BOM */
4287        "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL,
4288        XML_ERROR_NONE},
4289       {"<?xml version='1.0' encoding='utf-8'?>\n$",
4290        "Invalid token after text declaration not faulted", NULL,
4291        XML_ERROR_INVALID_TOKEN},
4292       {"<?xml version='1.0' encoding='utf-8'?>\n'wombat",
4293        "Unterminated string after text decl not faulted", NULL,
4294        XML_ERROR_UNCLOSED_TOKEN},
4295       {"<?xml version='1.0' encoding='utf-8'?>\n\xe2\x82",
4296        "Partial UTF-8 character after text decl not faulted", NULL,
4297        XML_ERROR_PARTIAL_CHAR},
4298       {"%e1;", "Recursive parameter entity not faulted", NULL,
4299        XML_ERROR_RECURSIVE_ENTITY_REF},
4300       {NULL, NULL, NULL, XML_ERROR_NONE}};
4301   int i;
4302 
4303   for (i = 0; data_004_2[i].parse_text != NULL; i++) {
4304     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4305     XML_SetExternalEntityRefHandler(g_parser, external_entity_valuer);
4306     XML_SetUserData(g_parser, &data_004_2[i]);
4307     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4308         == XML_STATUS_ERROR)
4309       xml_failure(g_parser);
4310     XML_ParserReset(g_parser, NULL);
4311   }
4312 }
4313 END_TEST
4314 
4315 /* Test the recursive parse interacts with a not standalone handler */
4316 static int XMLCALL
4317 external_entity_not_standalone(XML_Parser parser, const XML_Char *context,
4318                                const XML_Char *base, const XML_Char *systemId,
4319                                const XML_Char *publicId) {
4320   const char *text1 = "<!ELEMENT doc EMPTY>\n"
4321                       "<!ENTITY % e1 SYSTEM 'bar'>\n"
4322                       "%e1;\n";
4323   const char *text2 = "<!ATTLIST doc a1 CDATA 'value'>";
4324   XML_Parser ext_parser;
4325 
4326   UNUSED_P(base);
4327   UNUSED_P(publicId);
4328   if (systemId == NULL)
4329     return XML_STATUS_OK;
4330   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4331   if (ext_parser == NULL)
4332     fail("Could not create external entity parser");
4333   if (! xcstrcmp(systemId, XCS("foo"))) {
4334     XML_SetNotStandaloneHandler(ext_parser, reject_not_standalone_handler);
4335     if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
4336         != XML_STATUS_ERROR)
4337       fail("Expected not standalone rejection");
4338     if (XML_GetErrorCode(ext_parser) != XML_ERROR_NOT_STANDALONE)
4339       xml_failure(ext_parser);
4340     XML_SetNotStandaloneHandler(ext_parser, NULL);
4341     XML_ParserFree(ext_parser);
4342     return XML_STATUS_ERROR;
4343   } else if (! xcstrcmp(systemId, XCS("bar"))) {
4344     if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
4345         == XML_STATUS_ERROR)
4346       xml_failure(ext_parser);
4347   }
4348 
4349   XML_ParserFree(ext_parser);
4350   return XML_STATUS_OK;
4351 }
4352 
4353 START_TEST(test_ext_entity_not_standalone) {
4354   const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4355                      "<doc></doc>";
4356 
4357   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4358   XML_SetExternalEntityRefHandler(g_parser, external_entity_not_standalone);
4359   expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4360                  "Standalone rejection not caught");
4361 }
4362 END_TEST
4363 
4364 static int XMLCALL
4365 external_entity_value_aborter(XML_Parser parser, const XML_Char *context,
4366                               const XML_Char *base, const XML_Char *systemId,
4367                               const XML_Char *publicId) {
4368   const char *text1 = "<!ELEMENT doc EMPTY>\n"
4369                       "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
4370                       "<!ENTITY % e2 '%e1;'>\n"
4371                       "%e1;\n";
4372   const char *text2 = "<?xml version='1.0' encoding='utf-8'?>";
4373   XML_Parser ext_parser;
4374 
4375   UNUSED_P(base);
4376   UNUSED_P(publicId);
4377   if (systemId == NULL)
4378     return XML_STATUS_OK;
4379   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4380   if (ext_parser == NULL)
4381     fail("Could not create external entity parser");
4382   if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
4383     if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
4384         == XML_STATUS_ERROR)
4385       xml_failure(ext_parser);
4386   }
4387   if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
4388     XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
4389     XML_SetUserData(ext_parser, ext_parser);
4390     if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
4391         != XML_STATUS_ERROR)
4392       fail("Aborted parse not faulted");
4393     if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
4394       xml_failure(ext_parser);
4395   }
4396 
4397   XML_ParserFree(ext_parser);
4398   return XML_STATUS_OK;
4399 }
4400 
4401 START_TEST(test_ext_entity_value_abort) {
4402   const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
4403                      "<doc></doc>\n";
4404 
4405   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4406   XML_SetExternalEntityRefHandler(g_parser, external_entity_value_aborter);
4407   resumable = XML_FALSE;
4408   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4409       == XML_STATUS_ERROR)
4410     xml_failure(g_parser);
4411 }
4412 END_TEST
4413 
4414 START_TEST(test_bad_public_doctype) {
4415   const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
4416                      "<!DOCTYPE doc PUBLIC '{BadName}' 'test'>\n"
4417                      "<doc></doc>";
4418 
4419   /* Setting a handler provokes a particular code path */
4420   XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
4421                             dummy_end_doctype_handler);
4422   expect_failure(text, XML_ERROR_PUBLICID, "Bad Public ID not failed");
4423 }
4424 END_TEST
4425 
4426 /* Test based on ibm/valid/P32/ibm32v04.xml */
4427 START_TEST(test_attribute_enum_value) {
4428   const char *text = "<?xml version='1.0' standalone='no'?>\n"
4429                      "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
4430                      "<animal>This is a \n    <a/>  \n\nyellow tiger</animal>";
4431   ExtTest dtd_data
4432       = {"<!ELEMENT animal (#PCDATA|a)*>\n"
4433          "<!ELEMENT a EMPTY>\n"
4434          "<!ATTLIST animal xml:space (default|preserve) 'preserve'>",
4435          NULL, NULL};
4436   const XML_Char *expected = XCS("This is a \n      \n\nyellow tiger");
4437 
4438   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
4439   XML_SetUserData(g_parser, &dtd_data);
4440   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4441   /* An attribute list handler provokes a different code path */
4442   XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
4443   run_ext_character_check(text, &dtd_data, expected);
4444 }
4445 END_TEST
4446 
4447 /* Slightly bizarrely, the library seems to silently ignore entity
4448  * definitions for predefined entities, even when they are wrong.  The
4449  * language of the XML 1.0 spec is somewhat unhelpful as to what ought
4450  * to happen, so this is currently treated as acceptable.
4451  */
4452 START_TEST(test_predefined_entity_redefinition) {
4453   const char *text = "<!DOCTYPE doc [\n"
4454                      "<!ENTITY apos 'foo'>\n"
4455                      "]>\n"
4456                      "<doc>&apos;</doc>";
4457   run_character_check(text, XCS("'"));
4458 }
4459 END_TEST
4460 
4461 /* Test that the parser stops processing the DTD after an unresolved
4462  * parameter entity is encountered.
4463  */
4464 START_TEST(test_dtd_stop_processing) {
4465   const char *text = "<!DOCTYPE doc [\n"
4466                      "%foo;\n"
4467                      "<!ENTITY bar 'bas'>\n"
4468                      "]><doc/>";
4469 
4470   XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
4471   dummy_handler_flags = 0;
4472   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4473       == XML_STATUS_ERROR)
4474     xml_failure(g_parser);
4475   if (dummy_handler_flags != 0)
4476     fail("DTD processing still going after undefined PE");
4477 }
4478 END_TEST
4479 
4480 /* Test public notations with no system ID */
4481 START_TEST(test_public_notation_no_sysid) {
4482   const char *text = "<!DOCTYPE doc [\n"
4483                      "<!NOTATION note PUBLIC 'foo'>\n"
4484                      "<!ELEMENT doc EMPTY>\n"
4485                      "]>\n<doc/>";
4486 
4487   dummy_handler_flags = 0;
4488   XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
4489   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4490       == XML_STATUS_ERROR)
4491     xml_failure(g_parser);
4492   if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
4493     fail("Notation declaration handler not called");
4494 }
4495 END_TEST
4496 
4497 static void XMLCALL
4498 record_element_start_handler(void *userData, const XML_Char *name,
4499                              const XML_Char **atts) {
4500   UNUSED_P(atts);
4501   CharData_AppendXMLChars((CharData *)userData, name, (int)xcstrlen(name));
4502 }
4503 
4504 START_TEST(test_nested_groups) {
4505   const char *text
4506       = "<!DOCTYPE doc [\n"
4507         "<!ELEMENT doc "
4508         /* Sixteen elements per line */
4509         "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
4510         "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
4511         "))))))))))))))))))))))))))))))))>\n"
4512         "<!ELEMENT e EMPTY>"
4513         "]>\n"
4514         "<doc><e/></doc>";
4515   CharData storage;
4516 
4517   CharData_Init(&storage);
4518   XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4519   XML_SetStartElementHandler(g_parser, record_element_start_handler);
4520   XML_SetUserData(g_parser, &storage);
4521   dummy_handler_flags = 0;
4522   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4523       == XML_STATUS_ERROR)
4524     xml_failure(g_parser);
4525   CharData_CheckXMLChars(&storage, XCS("doce"));
4526   if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
4527     fail("Element handler not fired");
4528 }
4529 END_TEST
4530 
4531 START_TEST(test_group_choice) {
4532   const char *text = "<!DOCTYPE doc [\n"
4533                      "<!ELEMENT doc (a|b|c)+>\n"
4534                      "<!ELEMENT a EMPTY>\n"
4535                      "<!ELEMENT b (#PCDATA)>\n"
4536                      "<!ELEMENT c ANY>\n"
4537                      "]>\n"
4538                      "<doc>\n"
4539                      "<a/>\n"
4540                      "<b attr='foo'>This is a foo</b>\n"
4541                      "<c></c>\n"
4542                      "</doc>\n";
4543 
4544   XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4545   dummy_handler_flags = 0;
4546   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4547       == XML_STATUS_ERROR)
4548     xml_failure(g_parser);
4549   if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
4550     fail("Element handler flag not raised");
4551 }
4552 END_TEST
4553 
4554 static int XMLCALL
4555 external_entity_public(XML_Parser parser, const XML_Char *context,
4556                        const XML_Char *base, const XML_Char *systemId,
4557                        const XML_Char *publicId) {
4558   const char *text1 = (const char *)XML_GetUserData(parser);
4559   const char *text2 = "<!ATTLIST doc a CDATA 'value'>";
4560   const char *text = NULL;
4561   XML_Parser ext_parser;
4562   int parse_res;
4563 
4564   UNUSED_P(base);
4565   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4566   if (ext_parser == NULL)
4567     return XML_STATUS_ERROR;
4568   if (systemId != NULL && ! xcstrcmp(systemId, XCS("http://example.org/"))) {
4569     text = text1;
4570   } else if (publicId != NULL && ! xcstrcmp(publicId, XCS("foo"))) {
4571     text = text2;
4572   } else
4573     fail("Unexpected parameters to external entity parser");
4574   assert(text != NULL);
4575   parse_res
4576       = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
4577   XML_ParserFree(ext_parser);
4578   return parse_res;
4579 }
4580 
4581 START_TEST(test_standalone_parameter_entity) {
4582   const char *text = "<?xml version='1.0' standalone='yes'?>\n"
4583                      "<!DOCTYPE doc SYSTEM 'http://example.org/' [\n"
4584                      "<!ENTITY % entity '<!ELEMENT doc (#PCDATA)>'>\n"
4585                      "%entity;\n"
4586                      "]>\n"
4587                      "<doc></doc>";
4588   char dtd_data[] = "<!ENTITY % e1 'foo'>\n";
4589 
4590   XML_SetUserData(g_parser, dtd_data);
4591   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4592   XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
4593   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4594       == XML_STATUS_ERROR)
4595     xml_failure(g_parser);
4596 }
4597 END_TEST
4598 
4599 /* Test skipping of parameter entity in an external DTD */
4600 /* Derived from ibm/invalid/P69/ibm69i01.xml */
4601 START_TEST(test_skipped_parameter_entity) {
4602   const char *text = "<?xml version='1.0'?>\n"
4603                      "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
4604                      "<!ELEMENT root (#PCDATA|a)* >\n"
4605                      "]>\n"
4606                      "<root></root>";
4607   ExtTest dtd_data = {"%pe2;", NULL, NULL};
4608 
4609   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
4610   XML_SetUserData(g_parser, &dtd_data);
4611   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4612   XML_SetSkippedEntityHandler(g_parser, dummy_skip_handler);
4613   dummy_handler_flags = 0;
4614   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4615       == XML_STATUS_ERROR)
4616     xml_failure(g_parser);
4617   if (dummy_handler_flags != DUMMY_SKIP_HANDLER_FLAG)
4618     fail("Skip handler not executed");
4619 }
4620 END_TEST
4621 
4622 /* Test recursive parameter entity definition rejected in external DTD */
4623 START_TEST(test_recursive_external_parameter_entity) {
4624   const char *text = "<?xml version='1.0'?>\n"
4625                      "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
4626                      "<!ELEMENT root (#PCDATA|a)* >\n"
4627                      "]>\n"
4628                      "<root></root>";
4629   ExtFaults dtd_data = {"<!ENTITY % pe2 '&#37;pe2;'>\n%pe2;",
4630                         "Recursive external parameter entity not faulted", NULL,
4631                         XML_ERROR_RECURSIVE_ENTITY_REF};
4632 
4633   XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
4634   XML_SetUserData(g_parser, &dtd_data);
4635   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4636   expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4637                  "Recursive external parameter not spotted");
4638 }
4639 END_TEST
4640 
4641 /* Test undefined parameter entity in external entity handler */
4642 static int XMLCALL
4643 external_entity_devaluer(XML_Parser parser, const XML_Char *context,
4644                          const XML_Char *base, const XML_Char *systemId,
4645                          const XML_Char *publicId) {
4646   const char *text = "<!ELEMENT doc EMPTY>\n"
4647                      "<!ENTITY % e1 SYSTEM 'bar'>\n"
4648                      "%e1;\n";
4649   XML_Parser ext_parser;
4650   intptr_t clear_handler = (intptr_t)XML_GetUserData(parser);
4651 
4652   UNUSED_P(base);
4653   UNUSED_P(publicId);
4654   if (systemId == NULL || ! xcstrcmp(systemId, XCS("bar")))
4655     return XML_STATUS_OK;
4656   if (xcstrcmp(systemId, XCS("foo")))
4657     fail("Unexpected system ID");
4658   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4659   if (ext_parser == NULL)
4660     fail("Could note create external entity parser");
4661   if (clear_handler)
4662     XML_SetExternalEntityRefHandler(ext_parser, NULL);
4663   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
4664       == XML_STATUS_ERROR)
4665     xml_failure(ext_parser);
4666 
4667   XML_ParserFree(ext_parser);
4668   return XML_STATUS_OK;
4669 }
4670 
4671 START_TEST(test_undefined_ext_entity_in_external_dtd) {
4672   const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4673                      "<doc></doc>\n";
4674 
4675   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4676   XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
4677   XML_SetUserData(g_parser, (void *)(intptr_t)XML_FALSE);
4678   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4679       == XML_STATUS_ERROR)
4680     xml_failure(g_parser);
4681 
4682   /* Now repeat without the external entity ref handler invoking
4683    * another copy of itself.
4684    */
4685   XML_ParserReset(g_parser, NULL);
4686   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4687   XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
4688   XML_SetUserData(g_parser, (void *)(intptr_t)XML_TRUE);
4689   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4690       == XML_STATUS_ERROR)
4691     xml_failure(g_parser);
4692 }
4693 END_TEST
4694 
4695 static void XMLCALL
4696 aborting_xdecl_handler(void *userData, const XML_Char *version,
4697                        const XML_Char *encoding, int standalone) {
4698   UNUSED_P(userData);
4699   UNUSED_P(version);
4700   UNUSED_P(encoding);
4701   UNUSED_P(standalone);
4702   XML_StopParser(g_parser, resumable);
4703   XML_SetXmlDeclHandler(g_parser, NULL);
4704 }
4705 
4706 /* Test suspending the parse on receiving an XML declaration works */
4707 START_TEST(test_suspend_xdecl) {
4708   const char *text = long_character_data_text;
4709 
4710   XML_SetXmlDeclHandler(g_parser, aborting_xdecl_handler);
4711   resumable = XML_TRUE;
4712   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4713       != XML_STATUS_SUSPENDED)
4714     xml_failure(g_parser);
4715   if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
4716     xml_failure(g_parser);
4717   /* Attempt to start a new parse while suspended */
4718   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4719       != XML_STATUS_ERROR)
4720     fail("Attempt to parse while suspended not faulted");
4721   if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
4722     fail("Suspended parse not faulted with correct error");
4723 }
4724 END_TEST
4725 
4726 /* Test aborting the parse in an epilog works */
4727 static void XMLCALL
4728 selective_aborting_default_handler(void *userData, const XML_Char *s, int len) {
4729   const XML_Char *match = (const XML_Char *)userData;
4730 
4731   if (match == NULL
4732       || (xcstrlen(match) == (unsigned)len && ! xcstrncmp(match, s, len))) {
4733     XML_StopParser(g_parser, resumable);
4734     XML_SetDefaultHandler(g_parser, NULL);
4735   }
4736 }
4737 
4738 START_TEST(test_abort_epilog) {
4739   const char *text = "<doc></doc>\n\r\n";
4740   XML_Char match[] = XCS("\r");
4741 
4742   XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
4743   XML_SetUserData(g_parser, match);
4744   resumable = XML_FALSE;
4745   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4746       != XML_STATUS_ERROR)
4747     fail("Abort not triggered");
4748   if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
4749     xml_failure(g_parser);
4750 }
4751 END_TEST
4752 
4753 /* Test a different code path for abort in the epilog */
4754 START_TEST(test_abort_epilog_2) {
4755   const char *text = "<doc></doc>\n";
4756   XML_Char match[] = XCS("\n");
4757 
4758   XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
4759   XML_SetUserData(g_parser, match);
4760   resumable = XML_FALSE;
4761   expect_failure(text, XML_ERROR_ABORTED, "Abort not triggered");
4762 }
4763 END_TEST
4764 
4765 /* Test suspension from the epilog */
4766 START_TEST(test_suspend_epilog) {
4767   const char *text = "<doc></doc>\n";
4768   XML_Char match[] = XCS("\n");
4769 
4770   XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
4771   XML_SetUserData(g_parser, match);
4772   resumable = XML_TRUE;
4773   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4774       != XML_STATUS_SUSPENDED)
4775     xml_failure(g_parser);
4776 }
4777 END_TEST
4778 
4779 static void XMLCALL
4780 suspending_end_handler(void *userData, const XML_Char *s) {
4781   UNUSED_P(s);
4782   XML_StopParser((XML_Parser)userData, 1);
4783 }
4784 
4785 START_TEST(test_suspend_in_sole_empty_tag) {
4786   const char *text = "<doc/>";
4787   enum XML_Status rc;
4788 
4789   XML_SetEndElementHandler(g_parser, suspending_end_handler);
4790   XML_SetUserData(g_parser, g_parser);
4791   rc = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
4792   if (rc == XML_STATUS_ERROR)
4793     xml_failure(g_parser);
4794   else if (rc != XML_STATUS_SUSPENDED)
4795     fail("Suspend not triggered");
4796   rc = XML_ResumeParser(g_parser);
4797   if (rc == XML_STATUS_ERROR)
4798     xml_failure(g_parser);
4799   else if (rc != XML_STATUS_OK)
4800     fail("Resume failed");
4801 }
4802 END_TEST
4803 
4804 START_TEST(test_unfinished_epilog) {
4805   const char *text = "<doc></doc><";
4806 
4807   expect_failure(text, XML_ERROR_UNCLOSED_TOKEN,
4808                  "Incomplete epilog entry not faulted");
4809 }
4810 END_TEST
4811 
4812 START_TEST(test_partial_char_in_epilog) {
4813   const char *text = "<doc></doc>\xe2\x82";
4814 
4815   /* First check that no fault is raised if the parse is not finished */
4816   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
4817       == XML_STATUS_ERROR)
4818     xml_failure(g_parser);
4819   /* Now check that it is faulted once we finish */
4820   if (XML_ParseBuffer(g_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
4821     fail("Partial character in epilog not faulted");
4822   if (XML_GetErrorCode(g_parser) != XML_ERROR_PARTIAL_CHAR)
4823     xml_failure(g_parser);
4824 }
4825 END_TEST
4826 
4827 START_TEST(test_hash_collision) {
4828   /* For full coverage of the lookup routine, we need to ensure a
4829    * hash collision even though we can only tell that we have one
4830    * through breakpoint debugging or coverage statistics.  The
4831    * following will cause a hash collision on machines with a 64-bit
4832    * long type; others will have to experiment.  The full coverage
4833    * tests invoked from qa.sh usually provide a hash collision, but
4834    * not always.  This is an attempt to provide insurance.
4835    */
4836 #define COLLIDING_HASH_SALT (unsigned long)_SIP_ULL(0xffffffffU, 0xff99fc90U)
4837   const char *text
4838       = "<doc>\n"
4839         "<a1/><a2/><a3/><a4/><a5/><a6/><a7/><a8/>\n"
4840         "<b1></b1><b2 attr='foo'>This is a foo</b2><b3></b3><b4></b4>\n"
4841         "<b5></b5><b6></b6><b7></b7><b8></b8>\n"
4842         "<c1/><c2/><c3/><c4/><c5/><c6/><c7/><c8/>\n"
4843         "<d1/><d2/><d3/><d4/><d5/><d6/><d7/>\n"
4844         "<d8>This triggers the table growth and collides with b2</d8>\n"
4845         "</doc>\n";
4846 
4847   XML_SetHashSalt(g_parser, COLLIDING_HASH_SALT);
4848   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4849       == XML_STATUS_ERROR)
4850     xml_failure(g_parser);
4851 }
4852 END_TEST
4853 #undef COLLIDING_HASH_SALT
4854 
4855 /* Test resuming a parse suspended in entity substitution */
4856 static void XMLCALL
4857 start_element_suspender(void *userData, const XML_Char *name,
4858                         const XML_Char **atts) {
4859   UNUSED_P(userData);
4860   UNUSED_P(atts);
4861   if (! xcstrcmp(name, XCS("suspend")))
4862     XML_StopParser(g_parser, XML_TRUE);
4863   if (! xcstrcmp(name, XCS("abort")))
4864     XML_StopParser(g_parser, XML_FALSE);
4865 }
4866 
4867 START_TEST(test_suspend_resume_internal_entity) {
4868   const char *text
4869       = "<!DOCTYPE doc [\n"
4870         "<!ENTITY foo '<suspend>Hi<suspend>Ho</suspend></suspend>'>\n"
4871         "]>\n"
4872         "<doc>&foo;</doc>\n";
4873   const XML_Char *expected1 = XCS("Hi");
4874   const XML_Char *expected2 = XCS("HiHo");
4875   CharData storage;
4876 
4877   CharData_Init(&storage);
4878   XML_SetStartElementHandler(g_parser, start_element_suspender);
4879   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
4880   XML_SetUserData(g_parser, &storage);
4881   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4882       != XML_STATUS_SUSPENDED)
4883     xml_failure(g_parser);
4884   CharData_CheckXMLChars(&storage, XCS(""));
4885   if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
4886     xml_failure(g_parser);
4887   CharData_CheckXMLChars(&storage, expected1);
4888   if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
4889     xml_failure(g_parser);
4890   CharData_CheckXMLChars(&storage, expected2);
4891 }
4892 END_TEST
4893 
4894 /* Test syntax error is caught at parse resumption */
4895 START_TEST(test_resume_entity_with_syntax_error) {
4896   const char *text = "<!DOCTYPE doc [\n"
4897                      "<!ENTITY foo '<suspend>Hi</wombat>'>\n"
4898                      "]>\n"
4899                      "<doc>&foo;</doc>\n";
4900 
4901   XML_SetStartElementHandler(g_parser, start_element_suspender);
4902   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4903       != XML_STATUS_SUSPENDED)
4904     xml_failure(g_parser);
4905   if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
4906     fail("Syntax error in entity not faulted");
4907   if (XML_GetErrorCode(g_parser) != XML_ERROR_TAG_MISMATCH)
4908     xml_failure(g_parser);
4909 }
4910 END_TEST
4911 
4912 /* Test suspending and resuming in a parameter entity substitution */
4913 static void XMLCALL
4914 element_decl_suspender(void *userData, const XML_Char *name,
4915                        XML_Content *model) {
4916   UNUSED_P(userData);
4917   UNUSED_P(name);
4918   XML_StopParser(g_parser, XML_TRUE);
4919   XML_FreeContentModel(g_parser, model);
4920 }
4921 
4922 START_TEST(test_suspend_resume_parameter_entity) {
4923   const char *text = "<!DOCTYPE doc [\n"
4924                      "<!ENTITY % foo '<!ELEMENT doc (#PCDATA)*>'>\n"
4925                      "%foo;\n"
4926                      "]>\n"
4927                      "<doc>Hello, world</doc>";
4928   const XML_Char *expected = XCS("Hello, world");
4929   CharData storage;
4930 
4931   CharData_Init(&storage);
4932   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4933   XML_SetElementDeclHandler(g_parser, element_decl_suspender);
4934   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
4935   XML_SetUserData(g_parser, &storage);
4936   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4937       != XML_STATUS_SUSPENDED)
4938     xml_failure(g_parser);
4939   CharData_CheckXMLChars(&storage, XCS(""));
4940   if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
4941     xml_failure(g_parser);
4942   CharData_CheckXMLChars(&storage, expected);
4943 }
4944 END_TEST
4945 
4946 /* Test attempting to use parser after an error is faulted */
4947 START_TEST(test_restart_on_error) {
4948   const char *text = "<$doc><doc></doc>";
4949 
4950   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4951       != XML_STATUS_ERROR)
4952     fail("Invalid tag name not faulted");
4953   if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
4954     xml_failure(g_parser);
4955   if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
4956     fail("Restarting invalid parse not faulted");
4957   if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
4958     xml_failure(g_parser);
4959 }
4960 END_TEST
4961 
4962 /* Test that angle brackets in an attribute default value are faulted */
4963 START_TEST(test_reject_lt_in_attribute_value) {
4964   const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '<bar>'>]>\n"
4965                      "<doc></doc>";
4966 
4967   expect_failure(text, XML_ERROR_INVALID_TOKEN,
4968                  "Bad attribute default not faulted");
4969 }
4970 END_TEST
4971 
4972 START_TEST(test_reject_unfinished_param_in_att_value) {
4973   const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '&foo'>]>\n"
4974                      "<doc></doc>";
4975 
4976   expect_failure(text, XML_ERROR_INVALID_TOKEN,
4977                  "Bad attribute default not faulted");
4978 }
4979 END_TEST
4980 
4981 START_TEST(test_trailing_cr_in_att_value) {
4982   const char *text = "<doc a='value\r'/>";
4983 
4984   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4985       == XML_STATUS_ERROR)
4986     xml_failure(g_parser);
4987 }
4988 END_TEST
4989 
4990 /* Try parsing a general entity within a parameter entity in a
4991  * standalone internal DTD.  Covers a corner case in the parser.
4992  */
4993 START_TEST(test_standalone_internal_entity) {
4994   const char *text = "<?xml version='1.0' standalone='yes' ?>\n"
4995                      "<!DOCTYPE doc [\n"
4996                      "  <!ELEMENT doc (#PCDATA)>\n"
4997                      "  <!ENTITY % pe '<!ATTLIST doc att2 CDATA \"&ge;\">'>\n"
4998                      "  <!ENTITY ge 'AttDefaultValue'>\n"
4999                      "  %pe;\n"
5000                      "]>\n"
5001                      "<doc att2='any'/>";
5002 
5003   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5004   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5005       == XML_STATUS_ERROR)
5006     xml_failure(g_parser);
5007 }
5008 END_TEST
5009 
5010 /* Test that a reference to an unknown external entity is skipped */
5011 START_TEST(test_skipped_external_entity) {
5012   const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
5013                      "<doc></doc>\n";
5014   ExtTest test_data = {"<!ELEMENT doc EMPTY>\n"
5015                        "<!ENTITY % e2 '%e1;'>\n",
5016                        NULL, NULL};
5017 
5018   XML_SetUserData(g_parser, &test_data);
5019   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5020   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
5021   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5022       == XML_STATUS_ERROR)
5023     xml_failure(g_parser);
5024 }
5025 END_TEST
5026 
5027 /* Test a different form of unknown external entity */
5028 typedef struct ext_hdlr_data {
5029   const char *parse_text;
5030   XML_ExternalEntityRefHandler handler;
5031 } ExtHdlrData;
5032 
5033 static int XMLCALL
5034 external_entity_oneshot_loader(XML_Parser parser, const XML_Char *context,
5035                                const XML_Char *base, const XML_Char *systemId,
5036                                const XML_Char *publicId) {
5037   ExtHdlrData *test_data = (ExtHdlrData *)XML_GetUserData(parser);
5038   XML_Parser ext_parser;
5039 
5040   UNUSED_P(base);
5041   UNUSED_P(systemId);
5042   UNUSED_P(publicId);
5043   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
5044   if (ext_parser == NULL)
5045     fail("Could not create external entity parser.");
5046   /* Use the requested entity parser for further externals */
5047   XML_SetExternalEntityRefHandler(ext_parser, test_data->handler);
5048   if (_XML_Parse_SINGLE_BYTES(ext_parser, test_data->parse_text,
5049                               (int)strlen(test_data->parse_text), XML_TRUE)
5050       == XML_STATUS_ERROR) {
5051     xml_failure(ext_parser);
5052   }
5053 
5054   XML_ParserFree(ext_parser);
5055   return XML_STATUS_OK;
5056 }
5057 
5058 START_TEST(test_skipped_null_loaded_ext_entity) {
5059   const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
5060                      "<doc />";
5061   ExtHdlrData test_data
5062       = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
5063          "<!ENTITY % pe2 '%pe1;'>\n"
5064          "%pe2;\n",
5065          external_entity_null_loader};
5066 
5067   XML_SetUserData(g_parser, &test_data);
5068   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5069   XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
5070   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5071       == XML_STATUS_ERROR)
5072     xml_failure(g_parser);
5073 }
5074 END_TEST
5075 
5076 START_TEST(test_skipped_unloaded_ext_entity) {
5077   const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
5078                      "<doc />";
5079   ExtHdlrData test_data
5080       = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
5081          "<!ENTITY % pe2 '%pe1;'>\n"
5082          "%pe2;\n",
5083          NULL};
5084 
5085   XML_SetUserData(g_parser, &test_data);
5086   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5087   XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
5088   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5089       == XML_STATUS_ERROR)
5090     xml_failure(g_parser);
5091 }
5092 END_TEST
5093 
5094 /* Test that a parameter entity value ending with a carriage return
5095  * has it translated internally into a newline.
5096  */
5097 START_TEST(test_param_entity_with_trailing_cr) {
5098 #define PARAM_ENTITY_NAME "pe"
5099 #define PARAM_ENTITY_CORE_VALUE "<!ATTLIST doc att CDATA \"default\">"
5100   const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
5101                      "<doc/>";
5102   ExtTest test_data
5103       = {"<!ENTITY % " PARAM_ENTITY_NAME " '" PARAM_ENTITY_CORE_VALUE "\r'>\n"
5104          "%" PARAM_ENTITY_NAME ";\n",
5105          NULL, NULL};
5106 
5107   XML_SetUserData(g_parser, &test_data);
5108   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5109   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
5110   XML_SetEntityDeclHandler(g_parser, param_entity_match_handler);
5111   entity_name_to_match = XCS(PARAM_ENTITY_NAME);
5112   entity_value_to_match = XCS(PARAM_ENTITY_CORE_VALUE) XCS("\n");
5113   entity_match_flag = ENTITY_MATCH_NOT_FOUND;
5114   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5115       == XML_STATUS_ERROR)
5116     xml_failure(g_parser);
5117   if (entity_match_flag == ENTITY_MATCH_FAIL)
5118     fail("Parameter entity CR->NEWLINE conversion failed");
5119   else if (entity_match_flag == ENTITY_MATCH_NOT_FOUND)
5120     fail("Parameter entity not parsed");
5121 }
5122 #undef PARAM_ENTITY_NAME
5123 #undef PARAM_ENTITY_CORE_VALUE
5124 END_TEST
5125 
5126 START_TEST(test_invalid_character_entity) {
5127   const char *text = "<!DOCTYPE doc [\n"
5128                      "  <!ENTITY entity '&#x110000;'>\n"
5129                      "]>\n"
5130                      "<doc>&entity;</doc>";
5131 
5132   expect_failure(text, XML_ERROR_BAD_CHAR_REF,
5133                  "Out of range character reference not faulted");
5134 }
5135 END_TEST
5136 
5137 START_TEST(test_invalid_character_entity_2) {
5138   const char *text = "<!DOCTYPE doc [\n"
5139                      "  <!ENTITY entity '&#xg0;'>\n"
5140                      "]>\n"
5141                      "<doc>&entity;</doc>";
5142 
5143   expect_failure(text, XML_ERROR_INVALID_TOKEN,
5144                  "Out of range character reference not faulted");
5145 }
5146 END_TEST
5147 
5148 START_TEST(test_invalid_character_entity_3) {
5149   const char text[] =
5150       /* <!DOCTYPE doc [\n */
5151       "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
5152       /* U+0E04 = KHO KHWAI
5153        * U+0E08 = CHO CHAN */
5154       /* <!ENTITY entity '&\u0e04\u0e08;'>\n */
5155       "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0e\0n\0t\0i\0t\0y\0 "
5156       "\0'\0&\x0e\x04\x0e\x08\0;\0'\0>\0\n"
5157       /* ]>\n */
5158       "\0]\0>\0\n"
5159       /* <doc>&entity;</doc> */
5160       "\0<\0d\0o\0c\0>\0&\0e\0n\0t\0i\0t\0y\0;\0<\0/\0d\0o\0c\0>";
5161 
5162   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5163       != XML_STATUS_ERROR)
5164     fail("Invalid start of entity name not faulted");
5165   if (XML_GetErrorCode(g_parser) != XML_ERROR_UNDEFINED_ENTITY)
5166     xml_failure(g_parser);
5167 }
5168 END_TEST
5169 
5170 START_TEST(test_invalid_character_entity_4) {
5171   const char *text = "<!DOCTYPE doc [\n"
5172                      "  <!ENTITY entity '&#1114112;'>\n" /* = &#x110000 */
5173                      "]>\n"
5174                      "<doc>&entity;</doc>";
5175 
5176   expect_failure(text, XML_ERROR_BAD_CHAR_REF,
5177                  "Out of range character reference not faulted");
5178 }
5179 END_TEST
5180 
5181 /* Test that processing instructions are picked up by a default handler */
5182 START_TEST(test_pi_handled_in_default) {
5183   const char *text = "<?test processing instruction?>\n<doc/>";
5184   const XML_Char *expected = XCS("<?test processing instruction?>\n<doc/>");
5185   CharData storage;
5186 
5187   CharData_Init(&storage);
5188   XML_SetDefaultHandler(g_parser, accumulate_characters);
5189   XML_SetUserData(g_parser, &storage);
5190   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5191       == XML_STATUS_ERROR)
5192     xml_failure(g_parser);
5193   CharData_CheckXMLChars(&storage, expected);
5194 }
5195 END_TEST
5196 
5197 /* Test that comments are picked up by a default handler */
5198 START_TEST(test_comment_handled_in_default) {
5199   const char *text = "<!-- This is a comment -->\n<doc/>";
5200   const XML_Char *expected = XCS("<!-- This is a comment -->\n<doc/>");
5201   CharData storage;
5202 
5203   CharData_Init(&storage);
5204   XML_SetDefaultHandler(g_parser, accumulate_characters);
5205   XML_SetUserData(g_parser, &storage);
5206   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5207       == XML_STATUS_ERROR)
5208     xml_failure(g_parser);
5209   CharData_CheckXMLChars(&storage, expected);
5210 }
5211 END_TEST
5212 
5213 /* Test PIs that look almost but not quite like XML declarations */
5214 static void XMLCALL
5215 accumulate_pi_characters(void *userData, const XML_Char *target,
5216                          const XML_Char *data) {
5217   CharData *storage = (CharData *)userData;
5218 
5219   CharData_AppendXMLChars(storage, target, -1);
5220   CharData_AppendXMLChars(storage, XCS(": "), 2);
5221   CharData_AppendXMLChars(storage, data, -1);
5222   CharData_AppendXMLChars(storage, XCS("\n"), 1);
5223 }
5224 
5225 START_TEST(test_pi_yml) {
5226   const char *text = "<?yml something like data?><doc/>";
5227   const XML_Char *expected = XCS("yml: something like data\n");
5228   CharData storage;
5229 
5230   CharData_Init(&storage);
5231   XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5232   XML_SetUserData(g_parser, &storage);
5233   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5234       == XML_STATUS_ERROR)
5235     xml_failure(g_parser);
5236   CharData_CheckXMLChars(&storage, expected);
5237 }
5238 END_TEST
5239 
5240 START_TEST(test_pi_xnl) {
5241   const char *text = "<?xnl nothing like data?><doc/>";
5242   const XML_Char *expected = XCS("xnl: nothing like data\n");
5243   CharData storage;
5244 
5245   CharData_Init(&storage);
5246   XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5247   XML_SetUserData(g_parser, &storage);
5248   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5249       == XML_STATUS_ERROR)
5250     xml_failure(g_parser);
5251   CharData_CheckXMLChars(&storage, expected);
5252 }
5253 END_TEST
5254 
5255 START_TEST(test_pi_xmm) {
5256   const char *text = "<?xmm everything like data?><doc/>";
5257   const XML_Char *expected = XCS("xmm: everything like data\n");
5258   CharData storage;
5259 
5260   CharData_Init(&storage);
5261   XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5262   XML_SetUserData(g_parser, &storage);
5263   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5264       == XML_STATUS_ERROR)
5265     xml_failure(g_parser);
5266   CharData_CheckXMLChars(&storage, expected);
5267 }
5268 END_TEST
5269 
5270 START_TEST(test_utf16_pi) {
5271   const char text[] =
5272       /* <?{KHO KHWAI}{CHO CHAN}?>
5273        * where {KHO KHWAI} = U+0E04
5274        * and   {CHO CHAN}  = U+0E08
5275        */
5276       "<\0?\0\x04\x0e\x08\x0e?\0>\0"
5277       /* <q/> */
5278       "<\0q\0/\0>\0";
5279 #ifdef XML_UNICODE
5280   const XML_Char *expected = XCS("\x0e04\x0e08: \n");
5281 #else
5282   const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
5283 #endif
5284   CharData storage;
5285 
5286   CharData_Init(&storage);
5287   XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5288   XML_SetUserData(g_parser, &storage);
5289   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5290       == XML_STATUS_ERROR)
5291     xml_failure(g_parser);
5292   CharData_CheckXMLChars(&storage, expected);
5293 }
5294 END_TEST
5295 
5296 START_TEST(test_utf16_be_pi) {
5297   const char text[] =
5298       /* <?{KHO KHWAI}{CHO CHAN}?>
5299        * where {KHO KHWAI} = U+0E04
5300        * and   {CHO CHAN}  = U+0E08
5301        */
5302       "\0<\0?\x0e\x04\x0e\x08\0?\0>"
5303       /* <q/> */
5304       "\0<\0q\0/\0>";
5305 #ifdef XML_UNICODE
5306   const XML_Char *expected = XCS("\x0e04\x0e08: \n");
5307 #else
5308   const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
5309 #endif
5310   CharData storage;
5311 
5312   CharData_Init(&storage);
5313   XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5314   XML_SetUserData(g_parser, &storage);
5315   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5316       == XML_STATUS_ERROR)
5317     xml_failure(g_parser);
5318   CharData_CheckXMLChars(&storage, expected);
5319 }
5320 END_TEST
5321 
5322 /* Test that comments can be picked up and translated */
5323 static void XMLCALL
5324 accumulate_comment(void *userData, const XML_Char *data) {
5325   CharData *storage = (CharData *)userData;
5326 
5327   CharData_AppendXMLChars(storage, data, -1);
5328 }
5329 
5330 START_TEST(test_utf16_be_comment) {
5331   const char text[] =
5332       /* <!-- Comment A --> */
5333       "\0<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0A\0 \0-\0-\0>\0\n"
5334       /* <doc/> */
5335       "\0<\0d\0o\0c\0/\0>";
5336   const XML_Char *expected = XCS(" Comment A ");
5337   CharData storage;
5338 
5339   CharData_Init(&storage);
5340   XML_SetCommentHandler(g_parser, accumulate_comment);
5341   XML_SetUserData(g_parser, &storage);
5342   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5343       == XML_STATUS_ERROR)
5344     xml_failure(g_parser);
5345   CharData_CheckXMLChars(&storage, expected);
5346 }
5347 END_TEST
5348 
5349 START_TEST(test_utf16_le_comment) {
5350   const char text[] =
5351       /* <!-- Comment B --> */
5352       "<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0B\0 \0-\0-\0>\0\n\0"
5353       /* <doc/> */
5354       "<\0d\0o\0c\0/\0>\0";
5355   const XML_Char *expected = XCS(" Comment B ");
5356   CharData storage;
5357 
5358   CharData_Init(&storage);
5359   XML_SetCommentHandler(g_parser, accumulate_comment);
5360   XML_SetUserData(g_parser, &storage);
5361   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5362       == XML_STATUS_ERROR)
5363     xml_failure(g_parser);
5364   CharData_CheckXMLChars(&storage, expected);
5365 }
5366 END_TEST
5367 
5368 /* Test that the unknown encoding handler with map entries that expect
5369  * conversion but no conversion function is faulted
5370  */
5371 static int XMLCALL
5372 failing_converter(void *data, const char *s) {
5373   UNUSED_P(data);
5374   UNUSED_P(s);
5375   /* Always claim to have failed */
5376   return -1;
5377 }
5378 
5379 static int XMLCALL
5380 prefix_converter(void *data, const char *s) {
5381   UNUSED_P(data);
5382   /* If the first byte is 0xff, raise an error */
5383   if (s[0] == (char)-1)
5384     return -1;
5385   /* Just add the low bits of the first byte to the second */
5386   return (s[1] + (s[0] & 0x7f)) & 0x01ff;
5387 }
5388 
5389 static int XMLCALL
5390 MiscEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) {
5391   int i;
5392   int high_map = -2; /* Assume a 2-byte sequence */
5393 
5394   if (! xcstrcmp(encoding, XCS("invalid-9"))
5395       || ! xcstrcmp(encoding, XCS("ascii-like"))
5396       || ! xcstrcmp(encoding, XCS("invalid-len"))
5397       || ! xcstrcmp(encoding, XCS("invalid-a"))
5398       || ! xcstrcmp(encoding, XCS("invalid-surrogate"))
5399       || ! xcstrcmp(encoding, XCS("invalid-high")))
5400     high_map = -1;
5401 
5402   for (i = 0; i < 128; ++i)
5403     info->map[i] = i;
5404   for (; i < 256; ++i)
5405     info->map[i] = high_map;
5406 
5407   /* If required, put an invalid value in the ASCII entries */
5408   if (! xcstrcmp(encoding, XCS("invalid-9")))
5409     info->map[9] = 5;
5410   /* If required, have a top-bit set character starts a 5-byte sequence */
5411   if (! xcstrcmp(encoding, XCS("invalid-len")))
5412     info->map[0x81] = -5;
5413   /* If required, make a top-bit set character a valid ASCII character */
5414   if (! xcstrcmp(encoding, XCS("invalid-a")))
5415     info->map[0x82] = 'a';
5416   /* If required, give a top-bit set character a forbidden value,
5417    * what would otherwise be the first of a surrogate pair.
5418    */
5419   if (! xcstrcmp(encoding, XCS("invalid-surrogate")))
5420     info->map[0x83] = 0xd801;
5421   /* If required, give a top-bit set character too high a value */
5422   if (! xcstrcmp(encoding, XCS("invalid-high")))
5423     info->map[0x84] = 0x010101;
5424 
5425   info->data = data;
5426   info->release = NULL;
5427   if (! xcstrcmp(encoding, XCS("failing-conv")))
5428     info->convert = failing_converter;
5429   else if (! xcstrcmp(encoding, XCS("prefix-conv")))
5430     info->convert = prefix_converter;
5431   else
5432     info->convert = NULL;
5433   return XML_STATUS_OK;
5434 }
5435 
5436 START_TEST(test_missing_encoding_conversion_fn) {
5437   const char *text = "<?xml version='1.0' encoding='no-conv'?>\n"
5438                      "<doc>\x81</doc>";
5439 
5440   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5441   /* MiscEncodingHandler sets up an encoding with every top-bit-set
5442    * character introducing a two-byte sequence.  For this, it
5443    * requires a convert function.  The above function call doesn't
5444    * pass one through, so when BadEncodingHandler actually gets
5445    * called it should supply an invalid encoding.
5446    */
5447   expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5448                  "Encoding with missing convert() not faulted");
5449 }
5450 END_TEST
5451 
5452 START_TEST(test_failing_encoding_conversion_fn) {
5453   const char *text = "<?xml version='1.0' encoding='failing-conv'?>\n"
5454                      "<doc>\x81</doc>";
5455 
5456   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5457   /* BadEncodingHandler sets up an encoding with every top-bit-set
5458    * character introducing a two-byte sequence.  For this, it
5459    * requires a convert function.  The above function call passes
5460    * one that insists all possible sequences are invalid anyway.
5461    */
5462   expect_failure(text, XML_ERROR_INVALID_TOKEN,
5463                  "Encoding with failing convert() not faulted");
5464 }
5465 END_TEST
5466 
5467 /* Test unknown encoding conversions */
5468 START_TEST(test_unknown_encoding_success) {
5469   const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5470                      /* Equivalent to <eoc>Hello, world</eoc> */
5471                      "<\x81\x64\x80oc>Hello, world</\x81\x64\x80oc>";
5472 
5473   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5474   run_character_check(text, XCS("Hello, world"));
5475 }
5476 END_TEST
5477 
5478 /* Test bad name character in unknown encoding */
5479 START_TEST(test_unknown_encoding_bad_name) {
5480   const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5481                      "<\xff\x64oc>Hello, world</\xff\x64oc>";
5482 
5483   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5484   expect_failure(text, XML_ERROR_INVALID_TOKEN,
5485                  "Bad name start in unknown encoding not faulted");
5486 }
5487 END_TEST
5488 
5489 /* Test bad mid-name character in unknown encoding */
5490 START_TEST(test_unknown_encoding_bad_name_2) {
5491   const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5492                      "<d\xffoc>Hello, world</d\xffoc>";
5493 
5494   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5495   expect_failure(text, XML_ERROR_INVALID_TOKEN,
5496                  "Bad name in unknown encoding not faulted");
5497 }
5498 END_TEST
5499 
5500 /* Test element name that is long enough to fill the conversion buffer
5501  * in an unknown encoding, finishing with an encoded character.
5502  */
5503 START_TEST(test_unknown_encoding_long_name_1) {
5504   const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5505                      "<abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>"
5506                      "Hi"
5507                      "</abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>";
5508   const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
5509   CharData storage;
5510 
5511   CharData_Init(&storage);
5512   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5513   XML_SetStartElementHandler(g_parser, record_element_start_handler);
5514   XML_SetUserData(g_parser, &storage);
5515   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5516       == XML_STATUS_ERROR)
5517     xml_failure(g_parser);
5518   CharData_CheckXMLChars(&storage, expected);
5519 }
5520 END_TEST
5521 
5522 /* Test element name that is long enough to fill the conversion buffer
5523  * in an unknown encoding, finishing with an simple character.
5524  */
5525 START_TEST(test_unknown_encoding_long_name_2) {
5526   const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5527                      "<abcdefghabcdefghabcdefghijklmnop>"
5528                      "Hi"
5529                      "</abcdefghabcdefghabcdefghijklmnop>";
5530   const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
5531   CharData storage;
5532 
5533   CharData_Init(&storage);
5534   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5535   XML_SetStartElementHandler(g_parser, record_element_start_handler);
5536   XML_SetUserData(g_parser, &storage);
5537   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5538       == XML_STATUS_ERROR)
5539     xml_failure(g_parser);
5540   CharData_CheckXMLChars(&storage, expected);
5541 }
5542 END_TEST
5543 
5544 START_TEST(test_invalid_unknown_encoding) {
5545   const char *text = "<?xml version='1.0' encoding='invalid-9'?>\n"
5546                      "<doc>Hello world</doc>";
5547 
5548   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5549   expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5550                  "Invalid unknown encoding not faulted");
5551 }
5552 END_TEST
5553 
5554 START_TEST(test_unknown_ascii_encoding_ok) {
5555   const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
5556                      "<doc>Hello, world</doc>";
5557 
5558   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5559   run_character_check(text, XCS("Hello, world"));
5560 }
5561 END_TEST
5562 
5563 START_TEST(test_unknown_ascii_encoding_fail) {
5564   const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
5565                      "<doc>Hello, \x80 world</doc>";
5566 
5567   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5568   expect_failure(text, XML_ERROR_INVALID_TOKEN,
5569                  "Invalid character not faulted");
5570 }
5571 END_TEST
5572 
5573 START_TEST(test_unknown_encoding_invalid_length) {
5574   const char *text = "<?xml version='1.0' encoding='invalid-len'?>\n"
5575                      "<doc>Hello, world</doc>";
5576 
5577   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5578   expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5579                  "Invalid unknown encoding not faulted");
5580 }
5581 END_TEST
5582 
5583 START_TEST(test_unknown_encoding_invalid_topbit) {
5584   const char *text = "<?xml version='1.0' encoding='invalid-a'?>\n"
5585                      "<doc>Hello, world</doc>";
5586 
5587   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5588   expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5589                  "Invalid unknown encoding not faulted");
5590 }
5591 END_TEST
5592 
5593 START_TEST(test_unknown_encoding_invalid_surrogate) {
5594   const char *text = "<?xml version='1.0' encoding='invalid-surrogate'?>\n"
5595                      "<doc>Hello, \x82 world</doc>";
5596 
5597   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5598   expect_failure(text, XML_ERROR_INVALID_TOKEN,
5599                  "Invalid unknown encoding not faulted");
5600 }
5601 END_TEST
5602 
5603 START_TEST(test_unknown_encoding_invalid_high) {
5604   const char *text = "<?xml version='1.0' encoding='invalid-high'?>\n"
5605                      "<doc>Hello, world</doc>";
5606 
5607   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5608   expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5609                  "Invalid unknown encoding not faulted");
5610 }
5611 END_TEST
5612 
5613 START_TEST(test_unknown_encoding_invalid_attr_value) {
5614   const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5615                      "<doc attr='\xff\x30'/>";
5616 
5617   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5618   expect_failure(text, XML_ERROR_INVALID_TOKEN,
5619                  "Invalid attribute valid not faulted");
5620 }
5621 END_TEST
5622 
5623 /* Test an external entity parser set to use latin-1 detects UTF-16
5624  * BOMs correctly.
5625  */
5626 enum ee_parse_flags { EE_PARSE_NONE = 0x00, EE_PARSE_FULL_BUFFER = 0x01 };
5627 
5628 typedef struct ExtTest2 {
5629   const char *parse_text;
5630   int parse_len;
5631   const XML_Char *encoding;
5632   CharData *storage;
5633   enum ee_parse_flags flags;
5634 } ExtTest2;
5635 
5636 static int XMLCALL
5637 external_entity_loader2(XML_Parser parser, const XML_Char *context,
5638                         const XML_Char *base, const XML_Char *systemId,
5639                         const XML_Char *publicId) {
5640   ExtTest2 *test_data = (ExtTest2 *)XML_GetUserData(parser);
5641   XML_Parser extparser;
5642 
5643   UNUSED_P(base);
5644   UNUSED_P(systemId);
5645   UNUSED_P(publicId);
5646   extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
5647   if (extparser == NULL)
5648     fail("Coulr not create external entity parser");
5649   if (test_data->encoding != NULL) {
5650     if (! XML_SetEncoding(extparser, test_data->encoding))
5651       fail("XML_SetEncoding() ignored for external entity");
5652   }
5653   if (test_data->flags & EE_PARSE_FULL_BUFFER) {
5654     if (XML_Parse(extparser, test_data->parse_text, test_data->parse_len,
5655                   XML_TRUE)
5656         == XML_STATUS_ERROR) {
5657       xml_failure(extparser);
5658     }
5659   } else if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
5660                                      test_data->parse_len, XML_TRUE)
5661              == XML_STATUS_ERROR) {
5662     xml_failure(extparser);
5663   }
5664 
5665   XML_ParserFree(extparser);
5666   return XML_STATUS_OK;
5667 }
5668 
5669 /* Test that UTF-16 BOM does not select UTF-16 given explicit encoding */
5670 static void XMLCALL
5671 ext2_accumulate_characters(void *userData, const XML_Char *s, int len) {
5672   ExtTest2 *test_data = (ExtTest2 *)userData;
5673   accumulate_characters(test_data->storage, s, len);
5674 }
5675 
5676 START_TEST(test_ext_entity_latin1_utf16le_bom) {
5677   const char *text = "<!DOCTYPE doc [\n"
5678                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5679                      "]>\n"
5680                      "<doc>&en;</doc>";
5681   ExtTest2 test_data
5682       = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5683          /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5684           *   0x4c = L and 0x20 is a space
5685           */
5686          "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL, EE_PARSE_NONE};
5687 #ifdef XML_UNICODE
5688   const XML_Char *expected = XCS("\x00ff\x00feL ");
5689 #else
5690   /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5691   const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
5692 #endif
5693   CharData storage;
5694 
5695   CharData_Init(&storage);
5696   test_data.storage = &storage;
5697   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5698   XML_SetUserData(g_parser, &test_data);
5699   XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5700   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5701       == XML_STATUS_ERROR)
5702     xml_failure(g_parser);
5703   CharData_CheckXMLChars(&storage, expected);
5704 }
5705 END_TEST
5706 
5707 START_TEST(test_ext_entity_latin1_utf16be_bom) {
5708   const char *text = "<!DOCTYPE doc [\n"
5709                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5710                      "]>\n"
5711                      "<doc>&en;</doc>";
5712   ExtTest2 test_data
5713       = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5714          /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5715           *   0x4c = L and 0x20 is a space
5716           */
5717          "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL, EE_PARSE_NONE};
5718 #ifdef XML_UNICODE
5719   const XML_Char *expected = XCS("\x00fe\x00ff L");
5720 #else
5721   /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5722   const XML_Char *expected = XCS("\xc3\xbe\xc3\xbf L");
5723 #endif
5724   CharData storage;
5725 
5726   CharData_Init(&storage);
5727   test_data.storage = &storage;
5728   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5729   XML_SetUserData(g_parser, &test_data);
5730   XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5731   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5732       == XML_STATUS_ERROR)
5733     xml_failure(g_parser);
5734   CharData_CheckXMLChars(&storage, expected);
5735 }
5736 END_TEST
5737 
5738 /* Parsing the full buffer rather than a byte at a time makes a
5739  * difference to the encoding scanning code, so repeat the above tests
5740  * without breaking them down by byte.
5741  */
5742 START_TEST(test_ext_entity_latin1_utf16le_bom2) {
5743   const char *text = "<!DOCTYPE doc [\n"
5744                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5745                      "]>\n"
5746                      "<doc>&en;</doc>";
5747   ExtTest2 test_data
5748       = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5749          /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5750           *   0x4c = L and 0x20 is a space
5751           */
5752          "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL, EE_PARSE_FULL_BUFFER};
5753 #ifdef XML_UNICODE
5754   const XML_Char *expected = XCS("\x00ff\x00feL ");
5755 #else
5756   /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5757   const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
5758 #endif
5759   CharData storage;
5760 
5761   CharData_Init(&storage);
5762   test_data.storage = &storage;
5763   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5764   XML_SetUserData(g_parser, &test_data);
5765   XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5766   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
5767       == XML_STATUS_ERROR)
5768     xml_failure(g_parser);
5769   CharData_CheckXMLChars(&storage, expected);
5770 }
5771 END_TEST
5772 
5773 START_TEST(test_ext_entity_latin1_utf16be_bom2) {
5774   const char *text = "<!DOCTYPE doc [\n"
5775                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5776                      "]>\n"
5777                      "<doc>&en;</doc>";
5778   ExtTest2 test_data
5779       = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5780          /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5781           *   0x4c = L and 0x20 is a space
5782           */
5783          "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL, EE_PARSE_FULL_BUFFER};
5784 #ifdef XML_UNICODE
5785   const XML_Char *expected = XCS("\x00fe\x00ff L");
5786 #else
5787   /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5788   const XML_Char *expected = "\xc3\xbe\xc3\xbf L";
5789 #endif
5790   CharData storage;
5791 
5792   CharData_Init(&storage);
5793   test_data.storage = &storage;
5794   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5795   XML_SetUserData(g_parser, &test_data);
5796   XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5797   if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
5798       == XML_STATUS_ERROR)
5799     xml_failure(g_parser);
5800   CharData_CheckXMLChars(&storage, expected);
5801 }
5802 END_TEST
5803 
5804 /* Test little-endian UTF-16 given an explicit big-endian encoding */
5805 START_TEST(test_ext_entity_utf16_be) {
5806   const char *text = "<!DOCTYPE doc [\n"
5807                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5808                      "]>\n"
5809                      "<doc>&en;</doc>";
5810   ExtTest2 test_data
5811       = {"<\0e\0/\0>\0", 8, XCS("utf-16be"), NULL, EE_PARSE_NONE};
5812 #ifdef XML_UNICODE
5813   const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
5814 #else
5815   const XML_Char *expected = XCS("\xe3\xb0\x80"   /* U+3C00 */
5816                                  "\xe6\x94\x80"   /* U+6500 */
5817                                  "\xe2\xbc\x80"   /* U+2F00 */
5818                                  "\xe3\xb8\x80"); /* U+3E00 */
5819 #endif
5820   CharData storage;
5821 
5822   CharData_Init(&storage);
5823   test_data.storage = &storage;
5824   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5825   XML_SetUserData(g_parser, &test_data);
5826   XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5827   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5828       == XML_STATUS_ERROR)
5829     xml_failure(g_parser);
5830   CharData_CheckXMLChars(&storage, expected);
5831 }
5832 END_TEST
5833 
5834 /* Test big-endian UTF-16 given an explicit little-endian encoding */
5835 START_TEST(test_ext_entity_utf16_le) {
5836   const char *text = "<!DOCTYPE doc [\n"
5837                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5838                      "]>\n"
5839                      "<doc>&en;</doc>";
5840   ExtTest2 test_data
5841       = {"\0<\0e\0/\0>", 8, XCS("utf-16le"), NULL, EE_PARSE_NONE};
5842 #ifdef XML_UNICODE
5843   const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
5844 #else
5845   const XML_Char *expected = XCS("\xe3\xb0\x80"   /* U+3C00 */
5846                                  "\xe6\x94\x80"   /* U+6500 */
5847                                  "\xe2\xbc\x80"   /* U+2F00 */
5848                                  "\xe3\xb8\x80"); /* U+3E00 */
5849 #endif
5850   CharData storage;
5851 
5852   CharData_Init(&storage);
5853   test_data.storage = &storage;
5854   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5855   XML_SetUserData(g_parser, &test_data);
5856   XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5857   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5858       == XML_STATUS_ERROR)
5859     xml_failure(g_parser);
5860   CharData_CheckXMLChars(&storage, expected);
5861 }
5862 END_TEST
5863 
5864 /* Test little-endian UTF-16 given no explicit encoding.
5865  * The existing default encoding (UTF-8) is assumed to hold without a
5866  * BOM to contradict it, so the entity value will in fact provoke an
5867  * error because 0x00 is not a valid XML character.  We parse the
5868  * whole buffer in one go rather than feeding it in byte by byte to
5869  * exercise different code paths in the initial scanning routines.
5870  */
5871 typedef struct ExtFaults2 {
5872   const char *parse_text;
5873   int parse_len;
5874   const char *fail_text;
5875   const XML_Char *encoding;
5876   enum XML_Error error;
5877 } ExtFaults2;
5878 
5879 static int XMLCALL
5880 external_entity_faulter2(XML_Parser parser, const XML_Char *context,
5881                          const XML_Char *base, const XML_Char *systemId,
5882                          const XML_Char *publicId) {
5883   ExtFaults2 *test_data = (ExtFaults2 *)XML_GetUserData(parser);
5884   XML_Parser extparser;
5885 
5886   UNUSED_P(base);
5887   UNUSED_P(systemId);
5888   UNUSED_P(publicId);
5889   extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
5890   if (extparser == NULL)
5891     fail("Could not create external entity parser");
5892   if (test_data->encoding != NULL) {
5893     if (! XML_SetEncoding(extparser, test_data->encoding))
5894       fail("XML_SetEncoding() ignored for external entity");
5895   }
5896   if (XML_Parse(extparser, test_data->parse_text, test_data->parse_len,
5897                 XML_TRUE)
5898       != XML_STATUS_ERROR)
5899     fail(test_data->fail_text);
5900   if (XML_GetErrorCode(extparser) != test_data->error)
5901     xml_failure(extparser);
5902 
5903   XML_ParserFree(extparser);
5904   return XML_STATUS_ERROR;
5905 }
5906 
5907 START_TEST(test_ext_entity_utf16_unknown) {
5908   const char *text = "<!DOCTYPE doc [\n"
5909                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5910                      "]>\n"
5911                      "<doc>&en;</doc>";
5912   ExtFaults2 test_data
5913       = {"a\0b\0c\0", 6, "Invalid character in entity not faulted", NULL,
5914          XML_ERROR_INVALID_TOKEN};
5915 
5916   XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter2);
5917   XML_SetUserData(g_parser, &test_data);
5918   expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
5919                  "Invalid character should not have been accepted");
5920 }
5921 END_TEST
5922 
5923 /* Test not-quite-UTF-8 BOM (0xEF 0xBB 0xBF) */
5924 START_TEST(test_ext_entity_utf8_non_bom) {
5925   const char *text = "<!DOCTYPE doc [\n"
5926                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5927                      "]>\n"
5928                      "<doc>&en;</doc>";
5929   ExtTest2 test_data
5930       = {"\xef\xbb\x80", /* Arabic letter DAD medial form, U+FEC0 */
5931          3, NULL, NULL, EE_PARSE_NONE};
5932 #ifdef XML_UNICODE
5933   const XML_Char *expected = XCS("\xfec0");
5934 #else
5935   const XML_Char *expected = XCS("\xef\xbb\x80");
5936 #endif
5937   CharData storage;
5938 
5939   CharData_Init(&storage);
5940   test_data.storage = &storage;
5941   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5942   XML_SetUserData(g_parser, &test_data);
5943   XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5944   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5945       == XML_STATUS_ERROR)
5946     xml_failure(g_parser);
5947   CharData_CheckXMLChars(&storage, expected);
5948 }
5949 END_TEST
5950 
5951 /* Test that UTF-8 in a CDATA section is correctly passed through */
5952 START_TEST(test_utf8_in_cdata_section) {
5953   const char *text = "<doc><![CDATA[one \xc3\xa9 two]]></doc>";
5954 #ifdef XML_UNICODE
5955   const XML_Char *expected = XCS("one \x00e9 two");
5956 #else
5957   const XML_Char *expected = XCS("one \xc3\xa9 two");
5958 #endif
5959 
5960   run_character_check(text, expected);
5961 }
5962 END_TEST
5963 
5964 /* Test that little-endian UTF-16 in a CDATA section is handled */
5965 START_TEST(test_utf8_in_cdata_section_2) {
5966   const char *text = "<doc><![CDATA[\xc3\xa9]\xc3\xa9two]]></doc>";
5967 #ifdef XML_UNICODE
5968   const XML_Char *expected = XCS("\x00e9]\x00e9two");
5969 #else
5970   const XML_Char *expected = XCS("\xc3\xa9]\xc3\xa9two");
5971 #endif
5972 
5973   run_character_check(text, expected);
5974 }
5975 END_TEST
5976 
5977 /* Test trailing spaces in elements are accepted */
5978 static void XMLCALL
5979 record_element_end_handler(void *userData, const XML_Char *name) {
5980   CharData *storage = (CharData *)userData;
5981 
5982   CharData_AppendXMLChars(storage, XCS("/"), 1);
5983   CharData_AppendXMLChars(storage, name, -1);
5984 }
5985 
5986 START_TEST(test_trailing_spaces_in_elements) {
5987   const char *text = "<doc   >Hi</doc >";
5988   const XML_Char *expected = XCS("doc/doc");
5989   CharData storage;
5990 
5991   CharData_Init(&storage);
5992   XML_SetElementHandler(g_parser, record_element_start_handler,
5993                         record_element_end_handler);
5994   XML_SetUserData(g_parser, &storage);
5995   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5996       == XML_STATUS_ERROR)
5997     xml_failure(g_parser);
5998   CharData_CheckXMLChars(&storage, expected);
5999 }
6000 END_TEST
6001 
6002 START_TEST(test_utf16_attribute) {
6003   const char text[] =
6004       /* <d {KHO KHWAI}{CHO CHAN}='a'/>
6005        * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
6006        * and   {CHO CHAN}  = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
6007        */
6008       "<\0d\0 \0\x04\x0e\x08\x0e=\0'\0a\0'\0/\0>\0";
6009   const XML_Char *expected = XCS("a");
6010   CharData storage;
6011 
6012   CharData_Init(&storage);
6013   XML_SetStartElementHandler(g_parser, accumulate_attribute);
6014   XML_SetUserData(g_parser, &storage);
6015   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6016       == XML_STATUS_ERROR)
6017     xml_failure(g_parser);
6018   CharData_CheckXMLChars(&storage, expected);
6019 }
6020 END_TEST
6021 
6022 START_TEST(test_utf16_second_attr) {
6023   /* <d a='1' {KHO KHWAI}{CHO CHAN}='2'/>
6024    * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
6025    * and   {CHO CHAN}  = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
6026    */
6027   const char text[] = "<\0d\0 \0a\0=\0'\0\x31\0'\0 \0"
6028                       "\x04\x0e\x08\x0e=\0'\0\x32\0'\0/\0>\0";
6029   const XML_Char *expected = XCS("1");
6030   CharData storage;
6031 
6032   CharData_Init(&storage);
6033   XML_SetStartElementHandler(g_parser, accumulate_attribute);
6034   XML_SetUserData(g_parser, &storage);
6035   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6036       == XML_STATUS_ERROR)
6037     xml_failure(g_parser);
6038   CharData_CheckXMLChars(&storage, expected);
6039 }
6040 END_TEST
6041 
6042 START_TEST(test_attr_after_solidus) {
6043   const char *text = "<doc attr1='a' / attr2='b'>";
6044 
6045   expect_failure(text, XML_ERROR_INVALID_TOKEN, "Misplaced / not faulted");
6046 }
6047 END_TEST
6048 
6049 static void XMLCALL
6050 accumulate_entity_decl(void *userData, const XML_Char *entityName,
6051                        int is_parameter_entity, const XML_Char *value,
6052                        int value_length, const XML_Char *base,
6053                        const XML_Char *systemId, const XML_Char *publicId,
6054                        const XML_Char *notationName) {
6055   CharData *storage = (CharData *)userData;
6056 
6057   UNUSED_P(is_parameter_entity);
6058   UNUSED_P(base);
6059   UNUSED_P(systemId);
6060   UNUSED_P(publicId);
6061   UNUSED_P(notationName);
6062   CharData_AppendXMLChars(storage, entityName, -1);
6063   CharData_AppendXMLChars(storage, XCS("="), 1);
6064   CharData_AppendXMLChars(storage, value, value_length);
6065   CharData_AppendXMLChars(storage, XCS("\n"), 1);
6066 }
6067 
6068 START_TEST(test_utf16_pe) {
6069   /* <!DOCTYPE doc [
6070    * <!ENTITY % {KHO KHWAI}{CHO CHAN} '<!ELEMENT doc (#PCDATA)>'>
6071    * %{KHO KHWAI}{CHO CHAN};
6072    * ]>
6073    * <doc></doc>
6074    *
6075    * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
6076    * and   {CHO CHAN}  = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
6077    */
6078   const char text[] = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
6079                       "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \x0e\x04\x0e\x08\0 "
6080                       "\0'\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 "
6081                       "\0d\0o\0c\0 \0(\0#\0P\0C\0D\0A\0T\0A\0)\0>\0'\0>\0\n"
6082                       "\0%\x0e\x04\x0e\x08\0;\0\n"
6083                       "\0]\0>\0\n"
6084                       "\0<\0d\0o\0c\0>\0<\0/\0d\0o\0c\0>";
6085 #ifdef XML_UNICODE
6086   const XML_Char *expected = XCS("\x0e04\x0e08=<!ELEMENT doc (#PCDATA)>\n");
6087 #else
6088   const XML_Char *expected
6089       = XCS("\xe0\xb8\x84\xe0\xb8\x88=<!ELEMENT doc (#PCDATA)>\n");
6090 #endif
6091   CharData storage;
6092 
6093   CharData_Init(&storage);
6094   XML_SetUserData(g_parser, &storage);
6095   XML_SetEntityDeclHandler(g_parser, accumulate_entity_decl);
6096   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6097       == XML_STATUS_ERROR)
6098     xml_failure(g_parser);
6099   CharData_CheckXMLChars(&storage, expected);
6100 }
6101 END_TEST
6102 
6103 /* Test that duff attribute description keywords are rejected */
6104 START_TEST(test_bad_attr_desc_keyword) {
6105   const char *text = "<!DOCTYPE doc [\n"
6106                      "  <!ATTLIST doc attr CDATA #!IMPLIED>\n"
6107                      "]>\n"
6108                      "<doc />";
6109 
6110   expect_failure(text, XML_ERROR_INVALID_TOKEN,
6111                  "Bad keyword !IMPLIED not faulted");
6112 }
6113 END_TEST
6114 
6115 /* Test that an invalid attribute description keyword consisting of
6116  * UTF-16 characters with their top bytes non-zero are correctly
6117  * faulted
6118  */
6119 START_TEST(test_bad_attr_desc_keyword_utf16) {
6120   /* <!DOCTYPE d [
6121    * <!ATTLIST d a CDATA #{KHO KHWAI}{CHO CHAN}>
6122    * ]><d/>
6123    *
6124    * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
6125    * and   {CHO CHAN}  = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
6126    */
6127   const char text[]
6128       = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
6129         "\0<\0!\0A\0T\0T\0L\0I\0S\0T\0 \0d\0 \0a\0 \0C\0D\0A\0T\0A\0 "
6130         "\0#\x0e\x04\x0e\x08\0>\0\n"
6131         "\0]\0>\0<\0d\0/\0>";
6132 
6133   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6134       != XML_STATUS_ERROR)
6135     fail("Invalid UTF16 attribute keyword not faulted");
6136   if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
6137     xml_failure(g_parser);
6138 }
6139 END_TEST
6140 
6141 /* Test that invalid syntax in a <!DOCTYPE> is rejected.  Do this
6142  * using prefix-encoding (see above) to trigger specific code paths
6143  */
6144 START_TEST(test_bad_doctype) {
6145   const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
6146                      "<!DOCTYPE doc [ \x80\x44 ]><doc/>";
6147 
6148   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
6149   expect_failure(text, XML_ERROR_SYNTAX,
6150                  "Invalid bytes in DOCTYPE not faulted");
6151 }
6152 END_TEST
6153 
6154 START_TEST(test_bad_doctype_utf16) {
6155   const char text[] =
6156       /* <!DOCTYPE doc [ \x06f2 ]><doc/>
6157        *
6158        * U+06F2 = EXTENDED ARABIC-INDIC DIGIT TWO, a valid number
6159        * (name character) but not a valid letter (name start character)
6160        */
6161       "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0 "
6162       "\x06\xf2"
6163       "\0 \0]\0>\0<\0d\0o\0c\0/\0>";
6164 
6165   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6166       != XML_STATUS_ERROR)
6167     fail("Invalid bytes in DOCTYPE not faulted");
6168   if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
6169     xml_failure(g_parser);
6170 }
6171 END_TEST
6172 
6173 START_TEST(test_bad_doctype_plus) {
6174   const char *text = "<!DOCTYPE 1+ [ <!ENTITY foo 'bar'> ]>\n"
6175                      "<1+>&foo;</1+>";
6176 
6177   expect_failure(text, XML_ERROR_INVALID_TOKEN,
6178                  "'+' in document name not faulted");
6179 }
6180 END_TEST
6181 
6182 START_TEST(test_bad_doctype_star) {
6183   const char *text = "<!DOCTYPE 1* [ <!ENTITY foo 'bar'> ]>\n"
6184                      "<1*>&foo;</1*>";
6185 
6186   expect_failure(text, XML_ERROR_INVALID_TOKEN,
6187                  "'*' in document name not faulted");
6188 }
6189 END_TEST
6190 
6191 START_TEST(test_bad_doctype_query) {
6192   const char *text = "<!DOCTYPE 1? [ <!ENTITY foo 'bar'> ]>\n"
6193                      "<1?>&foo;</1?>";
6194 
6195   expect_failure(text, XML_ERROR_INVALID_TOKEN,
6196                  "'?' in document name not faulted");
6197 }
6198 END_TEST
6199 
6200 START_TEST(test_unknown_encoding_bad_ignore) {
6201   const char *text = "<?xml version='1.0' encoding='prefix-conv'?>"
6202                      "<!DOCTYPE doc SYSTEM 'foo'>"
6203                      "<doc><e>&entity;</e></doc>";
6204   ExtFaults fault = {"<![IGNORE[<!ELEMENT \xffG (#PCDATA)*>]]>",
6205                      "Invalid character not faulted", XCS("prefix-conv"),
6206                      XML_ERROR_INVALID_TOKEN};
6207 
6208   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
6209   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6210   XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
6211   XML_SetUserData(g_parser, &fault);
6212   expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
6213                  "Bad IGNORE section with unknown encoding not failed");
6214 }
6215 END_TEST
6216 
6217 START_TEST(test_entity_in_utf16_be_attr) {
6218   const char text[] =
6219       /* <e a='&#228; &#x00E4;'></e> */
6220       "\0<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 "
6221       "\0&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>";
6222 #ifdef XML_UNICODE
6223   const XML_Char *expected = XCS("\x00e4 \x00e4");
6224 #else
6225   const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
6226 #endif
6227   CharData storage;
6228 
6229   CharData_Init(&storage);
6230   XML_SetUserData(g_parser, &storage);
6231   XML_SetStartElementHandler(g_parser, accumulate_attribute);
6232   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6233       == XML_STATUS_ERROR)
6234     xml_failure(g_parser);
6235   CharData_CheckXMLChars(&storage, expected);
6236 }
6237 END_TEST
6238 
6239 START_TEST(test_entity_in_utf16_le_attr) {
6240   const char text[] =
6241       /* <e a='&#228; &#x00E4;'></e> */
6242       "<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 \0"
6243       "&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>\0";
6244 #ifdef XML_UNICODE
6245   const XML_Char *expected = XCS("\x00e4 \x00e4");
6246 #else
6247   const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
6248 #endif
6249   CharData storage;
6250 
6251   CharData_Init(&storage);
6252   XML_SetUserData(g_parser, &storage);
6253   XML_SetStartElementHandler(g_parser, accumulate_attribute);
6254   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6255       == XML_STATUS_ERROR)
6256     xml_failure(g_parser);
6257   CharData_CheckXMLChars(&storage, expected);
6258 }
6259 END_TEST
6260 
6261 START_TEST(test_entity_public_utf16_be) {
6262   const char text[] =
6263       /* <!DOCTYPE d [ */
6264       "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
6265       /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
6266       "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 "
6267       "\0'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n"
6268       /* %e; */
6269       "\0%\0e\0;\0\n"
6270       /* ]> */
6271       "\0]\0>\0\n"
6272       /* <d>&j;</d> */
6273       "\0<\0d\0>\0&\0j\0;\0<\0/\0d\0>";
6274   ExtTest2 test_data = {/* <!ENTITY j 'baz'> */
6275                         "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>",
6276                         34, NULL, NULL, EE_PARSE_NONE};
6277   const XML_Char *expected = XCS("baz");
6278   CharData storage;
6279 
6280   CharData_Init(&storage);
6281   test_data.storage = &storage;
6282   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6283   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
6284   XML_SetUserData(g_parser, &test_data);
6285   XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
6286   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6287       == XML_STATUS_ERROR)
6288     xml_failure(g_parser);
6289   CharData_CheckXMLChars(&storage, expected);
6290 }
6291 END_TEST
6292 
6293 START_TEST(test_entity_public_utf16_le) {
6294   const char text[] =
6295       /* <!DOCTYPE d [ */
6296       "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n\0"
6297       /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
6298       "<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 \0"
6299       "'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n\0"
6300       /* %e; */
6301       "%\0e\0;\0\n\0"
6302       /* ]> */
6303       "]\0>\0\n\0"
6304       /* <d>&j;</d> */
6305       "<\0d\0>\0&\0j\0;\0<\0/\0d\0>\0";
6306   ExtTest2 test_data = {/* <!ENTITY j 'baz'> */
6307                         "<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>\0",
6308                         34, NULL, NULL, EE_PARSE_NONE};
6309   const XML_Char *expected = XCS("baz");
6310   CharData storage;
6311 
6312   CharData_Init(&storage);
6313   test_data.storage = &storage;
6314   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6315   XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
6316   XML_SetUserData(g_parser, &test_data);
6317   XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
6318   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6319       == XML_STATUS_ERROR)
6320     xml_failure(g_parser);
6321   CharData_CheckXMLChars(&storage, expected);
6322 }
6323 END_TEST
6324 
6325 /* Test that a doctype with neither an internal nor external subset is
6326  * faulted
6327  */
6328 START_TEST(test_short_doctype) {
6329   const char *text = "<!DOCTYPE doc></doc>";
6330   expect_failure(text, XML_ERROR_INVALID_TOKEN,
6331                  "DOCTYPE without subset not rejected");
6332 }
6333 END_TEST
6334 
6335 START_TEST(test_short_doctype_2) {
6336   const char *text = "<!DOCTYPE doc PUBLIC></doc>";
6337   expect_failure(text, XML_ERROR_SYNTAX,
6338                  "DOCTYPE without Public ID not rejected");
6339 }
6340 END_TEST
6341 
6342 START_TEST(test_short_doctype_3) {
6343   const char *text = "<!DOCTYPE doc SYSTEM></doc>";
6344   expect_failure(text, XML_ERROR_SYNTAX,
6345                  "DOCTYPE without System ID not rejected");
6346 }
6347 END_TEST
6348 
6349 START_TEST(test_long_doctype) {
6350   const char *text = "<!DOCTYPE doc PUBLIC 'foo' 'bar' 'baz'></doc>";
6351   expect_failure(text, XML_ERROR_SYNTAX, "DOCTYPE with extra ID not rejected");
6352 }
6353 END_TEST
6354 
6355 START_TEST(test_bad_entity) {
6356   const char *text = "<!DOCTYPE doc [\n"
6357                      "  <!ENTITY foo PUBLIC>\n"
6358                      "]>\n"
6359                      "<doc/>";
6360   expect_failure(text, XML_ERROR_SYNTAX,
6361                  "ENTITY without Public ID is not rejected");
6362 }
6363 END_TEST
6364 
6365 /* Test unquoted value is faulted */
6366 START_TEST(test_bad_entity_2) {
6367   const char *text = "<!DOCTYPE doc [\n"
6368                      "  <!ENTITY % foo bar>\n"
6369                      "]>\n"
6370                      "<doc/>";
6371   expect_failure(text, XML_ERROR_SYNTAX,
6372                  "ENTITY without Public ID is not rejected");
6373 }
6374 END_TEST
6375 
6376 START_TEST(test_bad_entity_3) {
6377   const char *text = "<!DOCTYPE doc [\n"
6378                      "  <!ENTITY % foo PUBLIC>\n"
6379                      "]>\n"
6380                      "<doc/>";
6381   expect_failure(text, XML_ERROR_SYNTAX,
6382                  "Parameter ENTITY without Public ID is not rejected");
6383 }
6384 END_TEST
6385 
6386 START_TEST(test_bad_entity_4) {
6387   const char *text = "<!DOCTYPE doc [\n"
6388                      "  <!ENTITY % foo SYSTEM>\n"
6389                      "]>\n"
6390                      "<doc/>";
6391   expect_failure(text, XML_ERROR_SYNTAX,
6392                  "Parameter ENTITY without Public ID is not rejected");
6393 }
6394 END_TEST
6395 
6396 START_TEST(test_bad_notation) {
6397   const char *text = "<!DOCTYPE doc [\n"
6398                      "  <!NOTATION n SYSTEM>\n"
6399                      "]>\n"
6400                      "<doc/>";
6401   expect_failure(text, XML_ERROR_SYNTAX,
6402                  "Notation without System ID is not rejected");
6403 }
6404 END_TEST
6405 
6406 /* Test for issue #11, wrongly suppressed default handler */
6407 typedef struct default_check {
6408   const XML_Char *expected;
6409   const int expectedLen;
6410   XML_Bool seen;
6411 } DefaultCheck;
6412 
6413 static void XMLCALL
6414 checking_default_handler(void *userData, const XML_Char *s, int len) {
6415   DefaultCheck *data = (DefaultCheck *)userData;
6416   int i;
6417 
6418   for (i = 0; data[i].expected != NULL; i++) {
6419     if (data[i].expectedLen == len
6420         && ! memcmp(data[i].expected, s, len * sizeof(XML_Char))) {
6421       data[i].seen = XML_TRUE;
6422       break;
6423     }
6424   }
6425 }
6426 
6427 START_TEST(test_default_doctype_handler) {
6428   const char *text = "<!DOCTYPE doc PUBLIC 'pubname' 'test.dtd' [\n"
6429                      "  <!ENTITY foo 'bar'>\n"
6430                      "]>\n"
6431                      "<doc>&foo;</doc>";
6432   DefaultCheck test_data[] = {{XCS("'pubname'"), 9, XML_FALSE},
6433                               {XCS("'test.dtd'"), 10, XML_FALSE},
6434                               {NULL, 0, XML_FALSE}};
6435   int i;
6436 
6437   XML_SetUserData(g_parser, &test_data);
6438   XML_SetDefaultHandler(g_parser, checking_default_handler);
6439   XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
6440   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6441       == XML_STATUS_ERROR)
6442     xml_failure(g_parser);
6443   for (i = 0; test_data[i].expected != NULL; i++)
6444     if (! test_data[i].seen)
6445       fail("Default handler not run for public !DOCTYPE");
6446 }
6447 END_TEST
6448 
6449 START_TEST(test_empty_element_abort) {
6450   const char *text = "<abort/>";
6451 
6452   XML_SetStartElementHandler(g_parser, start_element_suspender);
6453   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6454       != XML_STATUS_ERROR)
6455     fail("Expected to error on abort");
6456 }
6457 END_TEST
6458 
6459 /*
6460  * Namespaces tests.
6461  */
6462 
6463 static void
6464 namespace_setup(void) {
6465   g_parser = XML_ParserCreateNS(NULL, XCS(' '));
6466   if (g_parser == NULL)
6467     fail("Parser not created.");
6468 }
6469 
6470 static void
6471 namespace_teardown(void) {
6472   basic_teardown();
6473 }
6474 
6475 /* Check that an element name and attribute name match the expected values.
6476    The expected values are passed as an array reference of string pointers
6477    provided as the userData argument; the first is the expected
6478    element name, and the second is the expected attribute name.
6479 */
6480 static int triplet_start_flag = XML_FALSE;
6481 static int triplet_end_flag = XML_FALSE;
6482 
6483 static void XMLCALL
6484 triplet_start_checker(void *userData, const XML_Char *name,
6485                       const XML_Char **atts) {
6486   XML_Char **elemstr = (XML_Char **)userData;
6487   char buffer[1024];
6488   if (xcstrcmp(elemstr[0], name) != 0) {
6489     sprintf(buffer, "unexpected start string: '%" XML_FMT_STR "'", name);
6490     fail(buffer);
6491   }
6492   if (xcstrcmp(elemstr[1], atts[0]) != 0) {
6493     sprintf(buffer, "unexpected attribute string: '%" XML_FMT_STR "'", atts[0]);
6494     fail(buffer);
6495   }
6496   triplet_start_flag = XML_TRUE;
6497 }
6498 
6499 /* Check that the element name passed to the end-element handler matches
6500    the expected value.  The expected value is passed as the first element
6501    in an array of strings passed as the userData argument.
6502 */
6503 static void XMLCALL
6504 triplet_end_checker(void *userData, const XML_Char *name) {
6505   XML_Char **elemstr = (XML_Char **)userData;
6506   if (xcstrcmp(elemstr[0], name) != 0) {
6507     char buffer[1024];
6508     sprintf(buffer, "unexpected end string: '%" XML_FMT_STR "'", name);
6509     fail(buffer);
6510   }
6511   triplet_end_flag = XML_TRUE;
6512 }
6513 
6514 START_TEST(test_return_ns_triplet) {
6515   const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
6516                      "       xmlns:bar='http://example.org/'>";
6517   const char *epilog = "</foo:e>";
6518   const XML_Char *elemstr[]
6519       = {XCS("http://example.org/ e foo"), XCS("http://example.org/ a bar")};
6520   XML_SetReturnNSTriplet(g_parser, XML_TRUE);
6521   XML_SetUserData(g_parser, (void *)elemstr);
6522   XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
6523   XML_SetNamespaceDeclHandler(g_parser, dummy_start_namespace_decl_handler,
6524                               dummy_end_namespace_decl_handler);
6525   triplet_start_flag = XML_FALSE;
6526   triplet_end_flag = XML_FALSE;
6527   dummy_handler_flags = 0;
6528   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
6529       == XML_STATUS_ERROR)
6530     xml_failure(g_parser);
6531   if (! triplet_start_flag)
6532     fail("triplet_start_checker not invoked");
6533   /* Check that unsetting "return triplets" fails while still parsing */
6534   XML_SetReturnNSTriplet(g_parser, XML_FALSE);
6535   if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
6536       == XML_STATUS_ERROR)
6537     xml_failure(g_parser);
6538   if (! triplet_end_flag)
6539     fail("triplet_end_checker not invoked");
6540   if (dummy_handler_flags
6541       != (DUMMY_START_NS_DECL_HANDLER_FLAG | DUMMY_END_NS_DECL_HANDLER_FLAG))
6542     fail("Namespace handlers not called");
6543 }
6544 END_TEST
6545 
6546 static void XMLCALL
6547 overwrite_start_checker(void *userData, const XML_Char *name,
6548                         const XML_Char **atts) {
6549   CharData *storage = (CharData *)userData;
6550   CharData_AppendXMLChars(storage, XCS("start "), 6);
6551   CharData_AppendXMLChars(storage, name, -1);
6552   while (*atts != NULL) {
6553     CharData_AppendXMLChars(storage, XCS("\nattribute "), 11);
6554     CharData_AppendXMLChars(storage, *atts, -1);
6555     atts += 2;
6556   }
6557   CharData_AppendXMLChars(storage, XCS("\n"), 1);
6558 }
6559 
6560 static void XMLCALL
6561 overwrite_end_checker(void *userData, const XML_Char *name) {
6562   CharData *storage = (CharData *)userData;
6563   CharData_AppendXMLChars(storage, XCS("end "), 4);
6564   CharData_AppendXMLChars(storage, name, -1);
6565   CharData_AppendXMLChars(storage, XCS("\n"), 1);
6566 }
6567 
6568 static void
6569 run_ns_tagname_overwrite_test(const char *text, const XML_Char *result) {
6570   CharData storage;
6571   CharData_Init(&storage);
6572   XML_SetUserData(g_parser, &storage);
6573   XML_SetElementHandler(g_parser, overwrite_start_checker,
6574                         overwrite_end_checker);
6575   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6576       == XML_STATUS_ERROR)
6577     xml_failure(g_parser);
6578   CharData_CheckXMLChars(&storage, result);
6579 }
6580 
6581 /* Regression test for SF bug #566334. */
6582 START_TEST(test_ns_tagname_overwrite) {
6583   const char *text = "<n:e xmlns:n='http://example.org/'>\n"
6584                      "  <n:f n:attr='foo'/>\n"
6585                      "  <n:g n:attr2='bar'/>\n"
6586                      "</n:e>";
6587   const XML_Char *result = XCS("start http://example.org/ e\n")
6588       XCS("start http://example.org/ f\n")
6589           XCS("attribute http://example.org/ attr\n")
6590               XCS("end http://example.org/ f\n")
6591                   XCS("start http://example.org/ g\n")
6592                       XCS("attribute http://example.org/ attr2\n")
6593                           XCS("end http://example.org/ g\n")
6594                               XCS("end http://example.org/ e\n");
6595   run_ns_tagname_overwrite_test(text, result);
6596 }
6597 END_TEST
6598 
6599 /* Regression test for SF bug #566334. */
6600 START_TEST(test_ns_tagname_overwrite_triplet) {
6601   const char *text = "<n:e xmlns:n='http://example.org/'>\n"
6602                      "  <n:f n:attr='foo'/>\n"
6603                      "  <n:g n:attr2='bar'/>\n"
6604                      "</n:e>";
6605   const XML_Char *result = XCS("start http://example.org/ e n\n")
6606       XCS("start http://example.org/ f n\n")
6607           XCS("attribute http://example.org/ attr n\n")
6608               XCS("end http://example.org/ f n\n")
6609                   XCS("start http://example.org/ g n\n")
6610                       XCS("attribute http://example.org/ attr2 n\n")
6611                           XCS("end http://example.org/ g n\n")
6612                               XCS("end http://example.org/ e n\n");
6613   XML_SetReturnNSTriplet(g_parser, XML_TRUE);
6614   run_ns_tagname_overwrite_test(text, result);
6615 }
6616 END_TEST
6617 
6618 /* Regression test for SF bug #620343. */
6619 static void XMLCALL
6620 start_element_fail(void *userData, const XML_Char *name,
6621                    const XML_Char **atts) {
6622   UNUSED_P(userData);
6623   UNUSED_P(name);
6624   UNUSED_P(atts);
6625 
6626   /* We should never get here. */
6627   fail("should never reach start_element_fail()");
6628 }
6629 
6630 static void XMLCALL
6631 start_ns_clearing_start_element(void *userData, const XML_Char *prefix,
6632                                 const XML_Char *uri) {
6633   UNUSED_P(prefix);
6634   UNUSED_P(uri);
6635   XML_SetStartElementHandler((XML_Parser)userData, NULL);
6636 }
6637 
6638 START_TEST(test_start_ns_clears_start_element) {
6639   /* This needs to use separate start/end tags; using the empty tag
6640      syntax doesn't cause the problematic path through Expat to be
6641      taken.
6642   */
6643   const char *text = "<e xmlns='http://example.org/'></e>";
6644 
6645   XML_SetStartElementHandler(g_parser, start_element_fail);
6646   XML_SetStartNamespaceDeclHandler(g_parser, start_ns_clearing_start_element);
6647   XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
6648   XML_UseParserAsHandlerArg(g_parser);
6649   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6650       == XML_STATUS_ERROR)
6651     xml_failure(g_parser);
6652 }
6653 END_TEST
6654 
6655 /* Regression test for SF bug #616863. */
6656 static int XMLCALL
6657 external_entity_handler(XML_Parser parser, const XML_Char *context,
6658                         const XML_Char *base, const XML_Char *systemId,
6659                         const XML_Char *publicId) {
6660   intptr_t callno = 1 + (intptr_t)XML_GetUserData(parser);
6661   const char *text;
6662   XML_Parser p2;
6663 
6664   UNUSED_P(base);
6665   UNUSED_P(systemId);
6666   UNUSED_P(publicId);
6667   if (callno == 1)
6668     text = ("<!ELEMENT doc (e+)>\n"
6669             "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
6670             "<!ELEMENT e EMPTY>\n");
6671   else
6672     text = ("<?xml version='1.0' encoding='us-ascii'?>"
6673             "<e/>");
6674 
6675   XML_SetUserData(parser, (void *)callno);
6676   p2 = XML_ExternalEntityParserCreate(parser, context, NULL);
6677   if (_XML_Parse_SINGLE_BYTES(p2, text, (int)strlen(text), XML_TRUE)
6678       == XML_STATUS_ERROR) {
6679     xml_failure(p2);
6680     return XML_STATUS_ERROR;
6681   }
6682   XML_ParserFree(p2);
6683   return XML_STATUS_OK;
6684 }
6685 
6686 START_TEST(test_default_ns_from_ext_subset_and_ext_ge) {
6687   const char *text = "<?xml version='1.0'?>\n"
6688                      "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
6689                      "  <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
6690                      "]>\n"
6691                      "<doc xmlns='http://example.org/ns1'>\n"
6692                      "&en;\n"
6693                      "</doc>";
6694 
6695   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6696   XML_SetExternalEntityRefHandler(g_parser, external_entity_handler);
6697   /* We actually need to set this handler to tickle this bug. */
6698   XML_SetStartElementHandler(g_parser, dummy_start_element);
6699   XML_SetUserData(g_parser, NULL);
6700   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6701       == XML_STATUS_ERROR)
6702     xml_failure(g_parser);
6703 }
6704 END_TEST
6705 
6706 /* Regression test #1 for SF bug #673791. */
6707 START_TEST(test_ns_prefix_with_empty_uri_1) {
6708   const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
6709                      "  <e xmlns:prefix=''/>\n"
6710                      "</doc>";
6711 
6712   expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
6713                  "Did not report re-setting namespace"
6714                  " URI with prefix to ''.");
6715 }
6716 END_TEST
6717 
6718 /* Regression test #2 for SF bug #673791. */
6719 START_TEST(test_ns_prefix_with_empty_uri_2) {
6720   const char *text = "<?xml version='1.0'?>\n"
6721                      "<docelem xmlns:pre=''/>";
6722 
6723   expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
6724                  "Did not report setting namespace URI with prefix to ''.");
6725 }
6726 END_TEST
6727 
6728 /* Regression test #3 for SF bug #673791. */
6729 START_TEST(test_ns_prefix_with_empty_uri_3) {
6730   const char *text = "<!DOCTYPE doc [\n"
6731                      "  <!ELEMENT doc EMPTY>\n"
6732                      "  <!ATTLIST doc\n"
6733                      "    xmlns:prefix CDATA ''>\n"
6734                      "]>\n"
6735                      "<doc/>";
6736 
6737   expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
6738                  "Didn't report attr default setting NS w/ prefix to ''.");
6739 }
6740 END_TEST
6741 
6742 /* Regression test #4 for SF bug #673791. */
6743 START_TEST(test_ns_prefix_with_empty_uri_4) {
6744   const char *text = "<!DOCTYPE doc [\n"
6745                      "  <!ELEMENT prefix:doc EMPTY>\n"
6746                      "  <!ATTLIST prefix:doc\n"
6747                      "    xmlns:prefix CDATA 'http://example.org/'>\n"
6748                      "]>\n"
6749                      "<prefix:doc/>";
6750   /* Packaged info expected by the end element handler;
6751      the weird structuring lets us re-use the triplet_end_checker()
6752      function also used for another test. */
6753   const XML_Char *elemstr[] = {XCS("http://example.org/ doc prefix")};
6754   XML_SetReturnNSTriplet(g_parser, XML_TRUE);
6755   XML_SetUserData(g_parser, (void *)elemstr);
6756   XML_SetEndElementHandler(g_parser, triplet_end_checker);
6757   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6758       == XML_STATUS_ERROR)
6759     xml_failure(g_parser);
6760 }
6761 END_TEST
6762 
6763 /* Test with non-xmlns prefix */
6764 START_TEST(test_ns_unbound_prefix) {
6765   const char *text = "<!DOCTYPE doc [\n"
6766                      "  <!ELEMENT prefix:doc EMPTY>\n"
6767                      "  <!ATTLIST prefix:doc\n"
6768                      "    notxmlns:prefix CDATA 'http://example.org/'>\n"
6769                      "]>\n"
6770                      "<prefix:doc/>";
6771 
6772   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6773       != XML_STATUS_ERROR)
6774     fail("Unbound prefix incorrectly passed");
6775   if (XML_GetErrorCode(g_parser) != XML_ERROR_UNBOUND_PREFIX)
6776     xml_failure(g_parser);
6777 }
6778 END_TEST
6779 
6780 START_TEST(test_ns_default_with_empty_uri) {
6781   const char *text = "<doc xmlns='http://example.org/'>\n"
6782                      "  <e xmlns=''/>\n"
6783                      "</doc>";
6784   /* Add some handlers to exercise extra code paths */
6785   XML_SetStartNamespaceDeclHandler(g_parser,
6786                                    dummy_start_namespace_decl_handler);
6787   XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
6788   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6789       == XML_STATUS_ERROR)
6790     xml_failure(g_parser);
6791 }
6792 END_TEST
6793 
6794 /* Regression test for SF bug #692964: two prefixes for one namespace. */
6795 START_TEST(test_ns_duplicate_attrs_diff_prefixes) {
6796   const char *text = "<doc xmlns:a='http://example.org/a'\n"
6797                      "     xmlns:b='http://example.org/a'\n"
6798                      "     a:a='v' b:a='v' />";
6799   expect_failure(text, XML_ERROR_DUPLICATE_ATTRIBUTE,
6800                  "did not report multiple attributes with same URI+name");
6801 }
6802 END_TEST
6803 
6804 START_TEST(test_ns_duplicate_hashes) {
6805   /* The hash of an attribute is calculated as the hash of its URI
6806    * concatenated with a space followed by its name (after the
6807    * colon).  We wish to generate attributes with the same hash
6808    * value modulo the attribute table size so that we can check that
6809    * the attribute hash table works correctly.  The attribute hash
6810    * table size will be the smallest power of two greater than the
6811    * number of attributes, but at least eight.  There is
6812    * unfortunately no programmatic way of getting the hash or the
6813    * table size at user level, but the test code coverage percentage
6814    * will drop if the hashes cease to point to the same row.
6815    *
6816    * The cunning plan is to have few enough attributes to have a
6817    * reliable table size of 8, and have the single letter attribute
6818    * names be 8 characters apart, producing a hash which will be the
6819    * same modulo 8.
6820    */
6821   const char *text = "<doc xmlns:a='http://example.org/a'\n"
6822                      "     a:a='v' a:i='w' />";
6823   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6824       == XML_STATUS_ERROR)
6825     xml_failure(g_parser);
6826 }
6827 END_TEST
6828 
6829 /* Regression test for SF bug #695401: unbound prefix. */
6830 START_TEST(test_ns_unbound_prefix_on_attribute) {
6831   const char *text = "<doc a:attr=''/>";
6832   expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
6833                  "did not report unbound prefix on attribute");
6834 }
6835 END_TEST
6836 
6837 /* Regression test for SF bug #695401: unbound prefix. */
6838 START_TEST(test_ns_unbound_prefix_on_element) {
6839   const char *text = "<a:doc/>";
6840   expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
6841                  "did not report unbound prefix on element");
6842 }
6843 END_TEST
6844 
6845 /* Test that the parsing status is correctly reset by XML_ParserReset().
6846  * We usE test_return_ns_triplet() for our example parse to improve
6847  * coverage of tidying up code executed.
6848  */
6849 START_TEST(test_ns_parser_reset) {
6850   XML_ParsingStatus status;
6851 
6852   XML_GetParsingStatus(g_parser, &status);
6853   if (status.parsing != XML_INITIALIZED)
6854     fail("parsing status doesn't start INITIALIZED");
6855   test_return_ns_triplet();
6856   XML_GetParsingStatus(g_parser, &status);
6857   if (status.parsing != XML_FINISHED)
6858     fail("parsing status doesn't end FINISHED");
6859   XML_ParserReset(g_parser, NULL);
6860   XML_GetParsingStatus(g_parser, &status);
6861   if (status.parsing != XML_INITIALIZED)
6862     fail("parsing status doesn't reset to INITIALIZED");
6863 }
6864 END_TEST
6865 
6866 /* Test that long element names with namespaces are handled correctly */
6867 START_TEST(test_ns_long_element) {
6868   const char *text
6869       = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
6870         " xmlns:foo='http://example.org/' bar:a='12'\n"
6871         " xmlns:bar='http://example.org/'>"
6872         "</foo:thisisalongenoughelementnametotriggerareallocation>";
6873   const XML_Char *elemstr[]
6874       = {XCS("http://example.org/")
6875              XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
6876          XCS("http://example.org/ a bar")};
6877 
6878   XML_SetReturnNSTriplet(g_parser, XML_TRUE);
6879   XML_SetUserData(g_parser, (void *)elemstr);
6880   XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
6881   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6882       == XML_STATUS_ERROR)
6883     xml_failure(g_parser);
6884 }
6885 END_TEST
6886 
6887 /* Test mixed population of prefixed and unprefixed attributes */
6888 START_TEST(test_ns_mixed_prefix_atts) {
6889   const char *text = "<e a='12' bar:b='13'\n"
6890                      " xmlns:bar='http://example.org/'>"
6891                      "</e>";
6892 
6893   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6894       == XML_STATUS_ERROR)
6895     xml_failure(g_parser);
6896 }
6897 END_TEST
6898 
6899 /* Test having a long namespaced element name inside a short one.
6900  * This exercises some internal buffer reallocation that is shared
6901  * across elements with the same namespace URI.
6902  */
6903 START_TEST(test_ns_extend_uri_buffer) {
6904   const char *text = "<foo:e xmlns:foo='http://example.org/'>"
6905                      " <foo:thisisalongenoughnametotriggerallocationaction"
6906                      "   foo:a='12' />"
6907                      "</foo:e>";
6908   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6909       == XML_STATUS_ERROR)
6910     xml_failure(g_parser);
6911 }
6912 END_TEST
6913 
6914 /* Test that xmlns is correctly rejected as an attribute in the xmlns
6915  * namespace, but not in other namespaces
6916  */
6917 START_TEST(test_ns_reserved_attributes) {
6918   const char *text1
6919       = "<foo:e xmlns:foo='http://example.org/' xmlns:xmlns='12' />";
6920   const char *text2
6921       = "<foo:e xmlns:foo='http://example.org/' foo:xmlns='12' />";
6922   expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XMLNS,
6923                  "xmlns not rejected as an attribute");
6924   XML_ParserReset(g_parser, NULL);
6925   if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
6926       == XML_STATUS_ERROR)
6927     xml_failure(g_parser);
6928 }
6929 END_TEST
6930 
6931 /* Test more reserved attributes */
6932 START_TEST(test_ns_reserved_attributes_2) {
6933   const char *text1 = "<foo:e xmlns:foo='http://example.org/'"
6934                       "  xmlns:xml='http://example.org/' />";
6935   const char *text2
6936       = "<foo:e xmlns:foo='http://www.w3.org/XML/1998/namespace' />";
6937   const char *text3 = "<foo:e xmlns:foo='http://www.w3.org/2000/xmlns/' />";
6938 
6939   expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XML,
6940                  "xml not rejected as an attribute");
6941   XML_ParserReset(g_parser, NULL);
6942   expect_failure(text2, XML_ERROR_RESERVED_NAMESPACE_URI,
6943                  "Use of w3.org URL not faulted");
6944   XML_ParserReset(g_parser, NULL);
6945   expect_failure(text3, XML_ERROR_RESERVED_NAMESPACE_URI,
6946                  "Use of w3.org xmlns URL not faulted");
6947 }
6948 END_TEST
6949 
6950 /* Test string pool handling of namespace names of 2048 characters */
6951 /* Exercises a particular string pool growth path */
6952 START_TEST(test_ns_extremely_long_prefix) {
6953   /* C99 compilers are only required to support 4095-character
6954    * strings, so the following needs to be split in two to be safe
6955    * for all compilers.
6956    */
6957   const char *text1
6958       = "<doc "
6959         /* 64 character on each line */
6960         /* ...gives a total length of 2048 */
6961         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6962         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6963         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6964         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6965         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6966         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6967         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6968         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6969         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6970         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6971         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6972         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6973         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6974         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6975         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6976         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6977         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6978         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6979         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6980         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6981         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6982         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6983         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6984         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6985         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6986         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6987         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6988         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6989         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6990         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6991         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6992         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6993         ":a='12'";
6994   const char *text2
6995       = " xmlns:"
6996         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6997         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6998         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
6999         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7000         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7001         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7002         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7003         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7004         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7005         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7006         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7007         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7008         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7009         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7010         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7011         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7012         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7013         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7014         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7015         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7016         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7017         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7018         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7019         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7020         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7021         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7022         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7023         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7024         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7025         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7026         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7027         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7028         "='foo'\n>"
7029         "</doc>";
7030 
7031   if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
7032       == XML_STATUS_ERROR)
7033     xml_failure(g_parser);
7034   if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
7035       == XML_STATUS_ERROR)
7036     xml_failure(g_parser);
7037 }
7038 END_TEST
7039 
7040 /* Test unknown encoding handlers in namespace setup */
7041 START_TEST(test_ns_unknown_encoding_success) {
7042   const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
7043                      "<foo:e xmlns:foo='http://example.org/'>Hi</foo:e>";
7044 
7045   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
7046   run_character_check(text, XCS("Hi"));
7047 }
7048 END_TEST
7049 
7050 /* Test that too many colons are rejected */
7051 START_TEST(test_ns_double_colon) {
7052   const char *text = "<foo:e xmlns:foo='http://example.org/' foo:a:b='bar' />";
7053   const enum XML_Status status
7054       = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
7055 #ifdef XML_NS
7056   if ((status == XML_STATUS_OK)
7057       || (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)) {
7058     fail("Double colon in attribute name not faulted"
7059          " (despite active namespace support)");
7060   }
7061 #else
7062   if (status != XML_STATUS_OK) {
7063     fail("Double colon in attribute name faulted"
7064          " (despite inactive namespace support");
7065   }
7066 #endif
7067 }
7068 END_TEST
7069 
7070 START_TEST(test_ns_double_colon_element) {
7071   const char *text = "<foo:bar:e xmlns:foo='http://example.org/' />";
7072   const enum XML_Status status
7073       = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
7074 #ifdef XML_NS
7075   if ((status == XML_STATUS_OK)
7076       || (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)) {
7077     fail("Double colon in element name not faulted"
7078          " (despite active namespace support)");
7079   }
7080 #else
7081   if (status != XML_STATUS_OK) {
7082     fail("Double colon in element name faulted"
7083          " (despite inactive namespace support");
7084   }
7085 #endif
7086 }
7087 END_TEST
7088 
7089 /* Test that non-name characters after a colon are rejected */
7090 START_TEST(test_ns_bad_attr_leafname) {
7091   const char *text = "<foo:e xmlns:foo='http://example.org/' foo:?ar='baz' />";
7092 
7093   expect_failure(text, XML_ERROR_INVALID_TOKEN,
7094                  "Invalid character in leafname not faulted");
7095 }
7096 END_TEST
7097 
7098 START_TEST(test_ns_bad_element_leafname) {
7099   const char *text = "<foo:?oc xmlns:foo='http://example.org/' />";
7100 
7101   expect_failure(text, XML_ERROR_INVALID_TOKEN,
7102                  "Invalid character in element leafname not faulted");
7103 }
7104 END_TEST
7105 
7106 /* Test high-byte-set UTF-16 characters are valid in a leafname */
7107 START_TEST(test_ns_utf16_leafname) {
7108   const char text[] =
7109       /* <n:e xmlns:n='URI' n:{KHO KHWAI}='a' />
7110        * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
7111        */
7112       "<\0n\0:\0e\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0 \0"
7113       "n\0:\0\x04\x0e=\0'\0a\0'\0 \0/\0>\0";
7114   const XML_Char *expected = XCS("a");
7115   CharData storage;
7116 
7117   CharData_Init(&storage);
7118   XML_SetStartElementHandler(g_parser, accumulate_attribute);
7119   XML_SetUserData(g_parser, &storage);
7120   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
7121       == XML_STATUS_ERROR)
7122     xml_failure(g_parser);
7123   CharData_CheckXMLChars(&storage, expected);
7124 }
7125 END_TEST
7126 
7127 START_TEST(test_ns_utf16_element_leafname) {
7128   const char text[] =
7129       /* <n:{KHO KHWAI} xmlns:n='URI'/>
7130        * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
7131        */
7132       "\0<\0n\0:\x0e\x04\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0/\0>";
7133 #ifdef XML_UNICODE
7134   const XML_Char *expected = XCS("URI \x0e04");
7135 #else
7136   const XML_Char *expected = XCS("URI \xe0\xb8\x84");
7137 #endif
7138   CharData storage;
7139 
7140   CharData_Init(&storage);
7141   XML_SetStartElementHandler(g_parser, start_element_event_handler);
7142   XML_SetUserData(g_parser, &storage);
7143   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
7144       == XML_STATUS_ERROR)
7145     xml_failure(g_parser);
7146   CharData_CheckXMLChars(&storage, expected);
7147 }
7148 END_TEST
7149 
7150 START_TEST(test_ns_utf16_doctype) {
7151   const char text[] =
7152       /* <!DOCTYPE foo:{KHO KHWAI} [ <!ENTITY bar 'baz'> ]>\n
7153        * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
7154        */
7155       "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0f\0o\0o\0:\x0e\x04\0 "
7156       "\0[\0 \0<\0!\0E\0N\0T\0I\0T\0Y\0 \0b\0a\0r\0 \0'\0b\0a\0z\0'\0>\0 "
7157       "\0]\0>\0\n"
7158       /* <foo:{KHO KHWAI} xmlns:foo='URI'>&bar;</foo:{KHO KHWAI}> */
7159       "\0<\0f\0o\0o\0:\x0e\x04\0 "
7160       "\0x\0m\0l\0n\0s\0:\0f\0o\0o\0=\0'\0U\0R\0I\0'\0>"
7161       "\0&\0b\0a\0r\0;"
7162       "\0<\0/\0f\0o\0o\0:\x0e\x04\0>";
7163 #ifdef XML_UNICODE
7164   const XML_Char *expected = XCS("URI \x0e04");
7165 #else
7166   const XML_Char *expected = XCS("URI \xe0\xb8\x84");
7167 #endif
7168   CharData storage;
7169 
7170   CharData_Init(&storage);
7171   XML_SetUserData(g_parser, &storage);
7172   XML_SetStartElementHandler(g_parser, start_element_event_handler);
7173   XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
7174   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
7175       == XML_STATUS_ERROR)
7176     xml_failure(g_parser);
7177   CharData_CheckXMLChars(&storage, expected);
7178 }
7179 END_TEST
7180 
7181 START_TEST(test_ns_invalid_doctype) {
7182   const char *text = "<!DOCTYPE foo:!bad [ <!ENTITY bar 'baz' ]>\n"
7183                      "<foo:!bad>&bar;</foo:!bad>";
7184 
7185   expect_failure(text, XML_ERROR_INVALID_TOKEN,
7186                  "Invalid character in document local name not faulted");
7187 }
7188 END_TEST
7189 
7190 START_TEST(test_ns_double_colon_doctype) {
7191   const char *text = "<!DOCTYPE foo:a:doc [ <!ENTITY bar 'baz' ]>\n"
7192                      "<foo:a:doc>&bar;</foo:a:doc>";
7193 
7194   expect_failure(text, XML_ERROR_SYNTAX,
7195                  "Double colon in document name not faulted");
7196 }
7197 END_TEST
7198 
7199 /* Control variable; the number of times duff_allocator() will successfully
7200  * allocate */
7201 #define ALLOC_ALWAYS_SUCCEED (-1)
7202 #define REALLOC_ALWAYS_SUCCEED (-1)
7203 
7204 static intptr_t allocation_count = ALLOC_ALWAYS_SUCCEED;
7205 static intptr_t reallocation_count = REALLOC_ALWAYS_SUCCEED;
7206 
7207 /* Crocked allocator for allocation failure tests */
7208 static void *
7209 duff_allocator(size_t size) {
7210   if (allocation_count == 0)
7211     return NULL;
7212   if (allocation_count != ALLOC_ALWAYS_SUCCEED)
7213     allocation_count--;
7214   return malloc(size);
7215 }
7216 
7217 /* Crocked reallocator for allocation failure tests */
7218 static void *
7219 duff_reallocator(void *ptr, size_t size) {
7220   if (reallocation_count == 0)
7221     return NULL;
7222   if (reallocation_count != REALLOC_ALWAYS_SUCCEED)
7223     reallocation_count--;
7224   return realloc(ptr, size);
7225 }
7226 
7227 /* Test that a failure to allocate the parser structure fails gracefully */
7228 START_TEST(test_misc_alloc_create_parser) {
7229   XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
7230   unsigned int i;
7231   const unsigned int max_alloc_count = 10;
7232 
7233   /* Something this simple shouldn't need more than 10 allocations */
7234   for (i = 0; i < max_alloc_count; i++) {
7235     allocation_count = i;
7236     g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
7237     if (g_parser != NULL)
7238       break;
7239   }
7240   if (i == 0)
7241     fail("Parser unexpectedly ignored failing allocator");
7242   else if (i == max_alloc_count)
7243     fail("Parser not created with max allocation count");
7244 }
7245 END_TEST
7246 
7247 /* Test memory allocation failures for a parser with an encoding */
7248 START_TEST(test_misc_alloc_create_parser_with_encoding) {
7249   XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
7250   unsigned int i;
7251   const unsigned int max_alloc_count = 10;
7252 
7253   /* Try several levels of allocation */
7254   for (i = 0; i < max_alloc_count; i++) {
7255     allocation_count = i;
7256     g_parser = XML_ParserCreate_MM(XCS("us-ascii"), &memsuite, NULL);
7257     if (g_parser != NULL)
7258       break;
7259   }
7260   if (i == 0)
7261     fail("Parser ignored failing allocator");
7262   else if (i == max_alloc_count)
7263     fail("Parser not created with max allocation count");
7264 }
7265 END_TEST
7266 
7267 /* Test that freeing a NULL parser doesn't cause an explosion.
7268  * (Not actually tested anywhere else)
7269  */
7270 START_TEST(test_misc_null_parser) {
7271   XML_ParserFree(NULL);
7272 }
7273 END_TEST
7274 
7275 /* Test that XML_ErrorString rejects out-of-range codes */
7276 START_TEST(test_misc_error_string) {
7277   if (XML_ErrorString((enum XML_Error) - 1) != NULL)
7278     fail("Negative error code not rejected");
7279   if (XML_ErrorString((enum XML_Error)100) != NULL)
7280     fail("Large error code not rejected");
7281 }
7282 END_TEST
7283 
7284 /* Test the version information is consistent */
7285 
7286 /* Since we are working in XML_LChars (potentially 16-bits), we
7287  * can't use the standard C library functions for character
7288  * manipulation and have to roll our own.
7289  */
7290 static int
7291 parse_version(const XML_LChar *version_text,
7292               XML_Expat_Version *version_struct) {
7293   if (! version_text)
7294     return XML_FALSE;
7295 
7296   while (*version_text != 0x00) {
7297     if (*version_text >= ASCII_0 && *version_text <= ASCII_9)
7298       break;
7299     version_text++;
7300   }
7301   if (*version_text == 0x00)
7302     return XML_FALSE;
7303 
7304   /* version_struct->major = strtoul(version_text, 10, &version_text) */
7305   version_struct->major = 0;
7306   while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
7307     version_struct->major
7308         = 10 * version_struct->major + (*version_text++ - ASCII_0);
7309   }
7310   if (*version_text++ != ASCII_PERIOD)
7311     return XML_FALSE;
7312 
7313   /* Now for the minor version number */
7314   version_struct->minor = 0;
7315   while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
7316     version_struct->minor
7317         = 10 * version_struct->minor + (*version_text++ - ASCII_0);
7318   }
7319   if (*version_text++ != ASCII_PERIOD)
7320     return XML_FALSE;
7321 
7322   /* Finally the micro version number */
7323   version_struct->micro = 0;
7324   while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
7325     version_struct->micro
7326         = 10 * version_struct->micro + (*version_text++ - ASCII_0);
7327   }
7328   if (*version_text != 0x00)
7329     return XML_FALSE;
7330   return XML_TRUE;
7331 }
7332 
7333 static int
7334 versions_equal(const XML_Expat_Version *first,
7335                const XML_Expat_Version *second) {
7336   return (first->major == second->major && first->minor == second->minor
7337           && first->micro == second->micro);
7338 }
7339 
7340 START_TEST(test_misc_version) {
7341   XML_Expat_Version read_version = XML_ExpatVersionInfo();
7342   /* Silence compiler warning with the following assignment */
7343   XML_Expat_Version parsed_version = {0, 0, 0};
7344   const XML_LChar *version_text = XML_ExpatVersion();
7345 
7346   if (version_text == NULL)
7347     fail("Could not obtain version text");
7348   assert(version_text != NULL);
7349   if (! parse_version(version_text, &parsed_version))
7350     fail("Unable to parse version text");
7351   if (! versions_equal(&read_version, &parsed_version))
7352     fail("Version mismatch");
7353 
7354 #if ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T)
7355   if (xcstrcmp(version_text, XCS("expat_2.4.3"))) /* needs bump on releases */
7356     fail("XML_*_VERSION in expat.h out of sync?\n");
7357 #else
7358   /* If we have XML_UNICODE defined but not XML_UNICODE_WCHAR_T
7359    * then XML_LChar is defined as char, for some reason.
7360    */
7361   if (strcmp(version_text, "expat_2.2.5")) /* needs bump on releases */
7362     fail("XML_*_VERSION in expat.h out of sync?\n");
7363 #endif /* ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T) */
7364 }
7365 END_TEST
7366 
7367 /* Test feature information */
7368 START_TEST(test_misc_features) {
7369   const XML_Feature *features = XML_GetFeatureList();
7370 
7371   /* Prevent problems with double-freeing parsers */
7372   g_parser = NULL;
7373   if (features == NULL) {
7374     fail("Failed to get feature information");
7375   } else {
7376     /* Loop through the features checking what we can */
7377     while (features->feature != XML_FEATURE_END) {
7378       switch (features->feature) {
7379       case XML_FEATURE_SIZEOF_XML_CHAR:
7380         if (features->value != sizeof(XML_Char))
7381           fail("Incorrect size of XML_Char");
7382         break;
7383       case XML_FEATURE_SIZEOF_XML_LCHAR:
7384         if (features->value != sizeof(XML_LChar))
7385           fail("Incorrect size of XML_LChar");
7386         break;
7387       default:
7388         break;
7389       }
7390       features++;
7391     }
7392   }
7393 }
7394 END_TEST
7395 
7396 /* Regression test for GitHub Issue #17: memory leak parsing attribute
7397  * values with mixed bound and unbound namespaces.
7398  */
7399 START_TEST(test_misc_attribute_leak) {
7400   const char *text = "<D xmlns:L=\"D\" l:a='' L:a=''/>";
7401   XML_Memory_Handling_Suite memsuite
7402       = {tracking_malloc, tracking_realloc, tracking_free};
7403 
7404   g_parser = XML_ParserCreate_MM(XCS("UTF-8"), &memsuite, XCS("\n"));
7405   expect_failure(text, XML_ERROR_UNBOUND_PREFIX, "Unbound prefixes not found");
7406   XML_ParserFree(g_parser);
7407   /* Prevent the teardown trying to double free */
7408   g_parser = NULL;
7409 
7410   if (! tracking_report())
7411     fail("Memory leak found");
7412 }
7413 END_TEST
7414 
7415 /* Test parser created for UTF-16LE is successful */
7416 START_TEST(test_misc_utf16le) {
7417   const char text[] =
7418       /* <?xml version='1.0'?><q>Hi</q> */
7419       "<\0?\0x\0m\0l\0 \0"
7420       "v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0?\0>\0"
7421       "<\0q\0>\0H\0i\0<\0/\0q\0>\0";
7422   const XML_Char *expected = XCS("Hi");
7423   CharData storage;
7424 
7425   g_parser = XML_ParserCreate(XCS("UTF-16LE"));
7426   if (g_parser == NULL)
7427     fail("Parser not created");
7428 
7429   CharData_Init(&storage);
7430   XML_SetUserData(g_parser, &storage);
7431   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
7432   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
7433       == XML_STATUS_ERROR)
7434     xml_failure(g_parser);
7435   CharData_CheckXMLChars(&storage, expected);
7436 }
7437 END_TEST
7438 
7439 typedef struct {
7440   XML_Parser parser;
7441   int deep;
7442 } DataIssue240;
7443 
7444 static void
7445 start_element_issue_240(void *userData, const XML_Char *name,
7446                         const XML_Char **atts) {
7447   DataIssue240 *mydata = (DataIssue240 *)userData;
7448   UNUSED_P(name);
7449   UNUSED_P(atts);
7450   mydata->deep++;
7451 }
7452 
7453 static void
7454 end_element_issue_240(void *userData, const XML_Char *name) {
7455   DataIssue240 *mydata = (DataIssue240 *)userData;
7456 
7457   UNUSED_P(name);
7458   mydata->deep--;
7459   if (mydata->deep == 0) {
7460     XML_StopParser(mydata->parser, 0);
7461   }
7462 }
7463 
7464 START_TEST(test_misc_stop_during_end_handler_issue_240_1) {
7465   XML_Parser parser;
7466   DataIssue240 *mydata;
7467   enum XML_Status result;
7468   const char *const doc1 = "<doc><e1/><e><foo/></e></doc>";
7469 
7470   parser = XML_ParserCreate(NULL);
7471   XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
7472   mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
7473   mydata->parser = parser;
7474   mydata->deep = 0;
7475   XML_SetUserData(parser, mydata);
7476 
7477   result = XML_Parse(parser, doc1, (int)strlen(doc1), 1);
7478   XML_ParserFree(parser);
7479   free(mydata);
7480   if (result != XML_STATUS_ERROR)
7481     fail("Stopping the parser did not work as expected");
7482 }
7483 END_TEST
7484 
7485 START_TEST(test_misc_stop_during_end_handler_issue_240_2) {
7486   XML_Parser parser;
7487   DataIssue240 *mydata;
7488   enum XML_Status result;
7489   const char *const doc2 = "<doc><elem/></doc>";
7490 
7491   parser = XML_ParserCreate(NULL);
7492   XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
7493   mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
7494   mydata->parser = parser;
7495   mydata->deep = 0;
7496   XML_SetUserData(parser, mydata);
7497 
7498   result = XML_Parse(parser, doc2, (int)strlen(doc2), 1);
7499   XML_ParserFree(parser);
7500   free(mydata);
7501   if (result != XML_STATUS_ERROR)
7502     fail("Stopping the parser did not work as expected");
7503 }
7504 END_TEST
7505 
7506 START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
7507   const char *const inputOne = "<!DOCTYPE d [\n"
7508                                "<!ENTITY % e ']><d/>'>\n"
7509                                "\n"
7510                                "%e;";
7511   const char *const inputTwo = "<!DOCTYPE d [\n"
7512                                "<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '&e1;'>\n"
7513                                "\n"
7514                                "%e2;";
7515   const char *const inputThree = "<!DOCTYPE d [\n"
7516                                  "<!ENTITY % e ']><d'>\n"
7517                                  "\n"
7518                                  "%e;";
7519   const char *const inputIssue317 = "<!DOCTYPE doc [\n"
7520                                     "<!ENTITY % foo ']>\n"
7521                                     "<doc>Hell<oc (#PCDATA)*>'>\n"
7522                                     "%foo;\n"
7523                                     "]>\n"
7524                                     "<doc>Hello, world</dVc>";
7525 
7526   const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317};
7527   size_t inputIndex = 0;
7528 
7529   for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) {
7530     XML_Parser parser;
7531     enum XML_Status parseResult;
7532     int setParamEntityResult;
7533     XML_Size lineNumber;
7534     XML_Size columnNumber;
7535     const char *const input = inputs[inputIndex];
7536 
7537     parser = XML_ParserCreate(NULL);
7538     setParamEntityResult
7539         = XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
7540     if (setParamEntityResult != 1)
7541       fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
7542 
7543     parseResult = XML_Parse(parser, input, (int)strlen(input), 0);
7544     if (parseResult != XML_STATUS_ERROR) {
7545       parseResult = XML_Parse(parser, "", 0, 1);
7546       if (parseResult != XML_STATUS_ERROR) {
7547         fail("Parsing was expected to fail but succeeded.");
7548       }
7549     }
7550 
7551     if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
7552       fail("Error code does not match XML_ERROR_INVALID_TOKEN");
7553 
7554     lineNumber = XML_GetCurrentLineNumber(parser);
7555     if (lineNumber != 4)
7556       fail("XML_GetCurrentLineNumber does not work as expected.");
7557 
7558     columnNumber = XML_GetCurrentColumnNumber(parser);
7559     if (columnNumber != 0)
7560       fail("XML_GetCurrentColumnNumber does not work as expected.");
7561 
7562     XML_ParserFree(parser);
7563   }
7564 }
7565 END_TEST
7566 
7567 static void
7568 alloc_setup(void) {
7569   XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
7570 
7571   /* Ensure the parser creation will go through */
7572   allocation_count = ALLOC_ALWAYS_SUCCEED;
7573   reallocation_count = REALLOC_ALWAYS_SUCCEED;
7574   g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
7575   if (g_parser == NULL)
7576     fail("Parser not created");
7577 }
7578 
7579 static void
7580 alloc_teardown(void) {
7581   basic_teardown();
7582 }
7583 
7584 /* Test the effects of allocation failures on xml declaration processing */
7585 START_TEST(test_alloc_parse_xdecl) {
7586   const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
7587                      "<doc>Hello, world</doc>";
7588   int i;
7589   const int max_alloc_count = 15;
7590 
7591   for (i = 0; i < max_alloc_count; i++) {
7592     allocation_count = i;
7593     XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
7594     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7595         != XML_STATUS_ERROR)
7596       break;
7597     /* Resetting the parser is insufficient, because some memory
7598      * allocations are cached within the parser.  Instead we use
7599      * the teardown and setup routines to ensure that we have the
7600      * right sort of parser back in our hands.
7601      */
7602     alloc_teardown();
7603     alloc_setup();
7604   }
7605   if (i == 0)
7606     fail("Parse succeeded despite failing allocator");
7607   if (i == max_alloc_count)
7608     fail("Parse failed with max allocations");
7609 }
7610 END_TEST
7611 
7612 /* As above, but with an encoding big enough to cause storing the
7613  * version information to expand the string pool being used.
7614  */
7615 static int XMLCALL
7616 long_encoding_handler(void *userData, const XML_Char *encoding,
7617                       XML_Encoding *info) {
7618   int i;
7619 
7620   UNUSED_P(userData);
7621   UNUSED_P(encoding);
7622   for (i = 0; i < 256; i++)
7623     info->map[i] = i;
7624   info->data = NULL;
7625   info->convert = NULL;
7626   info->release = NULL;
7627   return XML_STATUS_OK;
7628 }
7629 
7630 START_TEST(test_alloc_parse_xdecl_2) {
7631   const char *text
7632       = "<?xml version='1.0' encoding='"
7633         /* Each line is 64 characters */
7634         "ThisIsAStupidlyLongEncodingNameIntendedToTriggerPoolGrowth123456"
7635         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7636         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7637         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7638         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7639         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7640         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7641         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7642         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7643         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7644         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7645         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7646         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7647         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7648         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7649         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN"
7650         "'?>"
7651         "<doc>Hello, world</doc>";
7652   int i;
7653   const int max_alloc_count = 20;
7654 
7655   for (i = 0; i < max_alloc_count; i++) {
7656     allocation_count = i;
7657     XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
7658     XML_SetUnknownEncodingHandler(g_parser, long_encoding_handler, NULL);
7659     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7660         != XML_STATUS_ERROR)
7661       break;
7662     /* See comment in test_alloc_parse_xdecl() */
7663     alloc_teardown();
7664     alloc_setup();
7665   }
7666   if (i == 0)
7667     fail("Parse succeeded despite failing allocator");
7668   if (i == max_alloc_count)
7669     fail("Parse failed with max allocations");
7670 }
7671 END_TEST
7672 
7673 /* Test the effects of allocation failures on a straightforward parse */
7674 START_TEST(test_alloc_parse_pi) {
7675   const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
7676                      "<?pi unknown?>\n"
7677                      "<doc>"
7678                      "Hello, world"
7679                      "</doc>";
7680   int i;
7681   const int max_alloc_count = 15;
7682 
7683   for (i = 0; i < max_alloc_count; i++) {
7684     allocation_count = i;
7685     XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
7686     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7687         != XML_STATUS_ERROR)
7688       break;
7689     /* See comment in test_alloc_parse_xdecl() */
7690     alloc_teardown();
7691     alloc_setup();
7692   }
7693   if (i == 0)
7694     fail("Parse succeeded despite failing allocator");
7695   if (i == max_alloc_count)
7696     fail("Parse failed with max allocations");
7697 }
7698 END_TEST
7699 
7700 START_TEST(test_alloc_parse_pi_2) {
7701   const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
7702                      "<doc>"
7703                      "Hello, world"
7704                      "<?pi unknown?>\n"
7705                      "</doc>";
7706   int i;
7707   const int max_alloc_count = 15;
7708 
7709   for (i = 0; i < max_alloc_count; i++) {
7710     allocation_count = i;
7711     XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
7712     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7713         != XML_STATUS_ERROR)
7714       break;
7715     /* See comment in test_alloc_parse_xdecl() */
7716     alloc_teardown();
7717     alloc_setup();
7718   }
7719   if (i == 0)
7720     fail("Parse succeeded despite failing allocator");
7721   if (i == max_alloc_count)
7722     fail("Parse failed with max allocations");
7723 }
7724 END_TEST
7725 
7726 START_TEST(test_alloc_parse_pi_3) {
7727   const char *text
7728       = "<?"
7729         /* 64 characters per line */
7730         "This processing instruction should be long enough to ensure that"
7731         "it triggers the growth of an internal string pool when the      "
7732         "allocator fails at a cruicial moment FGHIJKLMNOPABCDEFGHIJKLMNOP"
7733         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7734         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7735         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7736         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7737         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7738         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7739         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7740         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7741         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7742         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7743         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7744         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7745         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7746         "Q?><doc/>";
7747   int i;
7748   const int max_alloc_count = 20;
7749 
7750   for (i = 0; i < max_alloc_count; i++) {
7751     allocation_count = i;
7752     XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
7753     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7754         != XML_STATUS_ERROR)
7755       break;
7756     /* See comment in test_alloc_parse_xdecl() */
7757     alloc_teardown();
7758     alloc_setup();
7759   }
7760   if (i == 0)
7761     fail("Parse succeeded despite failing allocator");
7762   if (i == max_alloc_count)
7763     fail("Parse failed with max allocations");
7764 }
7765 END_TEST
7766 
7767 START_TEST(test_alloc_parse_comment) {
7768   const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
7769                      "<!-- Test parsing this comment -->"
7770                      "<doc>Hi</doc>";
7771   int i;
7772   const int max_alloc_count = 15;
7773 
7774   for (i = 0; i < max_alloc_count; i++) {
7775     allocation_count = i;
7776     XML_SetCommentHandler(g_parser, dummy_comment_handler);
7777     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7778         != XML_STATUS_ERROR)
7779       break;
7780     /* See comment in test_alloc_parse_xdecl() */
7781     alloc_teardown();
7782     alloc_setup();
7783   }
7784   if (i == 0)
7785     fail("Parse succeeded despite failing allocator");
7786   if (i == max_alloc_count)
7787     fail("Parse failed with max allocations");
7788 }
7789 END_TEST
7790 
7791 START_TEST(test_alloc_parse_comment_2) {
7792   const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
7793                      "<doc>"
7794                      "Hello, world"
7795                      "<!-- Parse this comment too -->"
7796                      "</doc>";
7797   int i;
7798   const int max_alloc_count = 15;
7799 
7800   for (i = 0; i < max_alloc_count; i++) {
7801     allocation_count = i;
7802     XML_SetCommentHandler(g_parser, dummy_comment_handler);
7803     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7804         != XML_STATUS_ERROR)
7805       break;
7806     /* See comment in test_alloc_parse_xdecl() */
7807     alloc_teardown();
7808     alloc_setup();
7809   }
7810   if (i == 0)
7811     fail("Parse succeeded despite failing allocator");
7812   if (i == max_alloc_count)
7813     fail("Parse failed with max allocations");
7814 }
7815 END_TEST
7816 
7817 static int XMLCALL
7818 external_entity_duff_loader(XML_Parser parser, const XML_Char *context,
7819                             const XML_Char *base, const XML_Char *systemId,
7820                             const XML_Char *publicId) {
7821   XML_Parser new_parser;
7822   unsigned int i;
7823   const unsigned int max_alloc_count = 10;
7824 
7825   UNUSED_P(base);
7826   UNUSED_P(systemId);
7827   UNUSED_P(publicId);
7828   /* Try a few different allocation levels */
7829   for (i = 0; i < max_alloc_count; i++) {
7830     allocation_count = i;
7831     new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
7832     if (new_parser != NULL) {
7833       XML_ParserFree(new_parser);
7834       break;
7835     }
7836   }
7837   if (i == 0)
7838     fail("External parser creation ignored failing allocator");
7839   else if (i == max_alloc_count)
7840     fail("Extern parser not created with max allocation count");
7841 
7842   /* Make sure other random allocation doesn't now fail */
7843   allocation_count = ALLOC_ALWAYS_SUCCEED;
7844 
7845   /* Make sure the failure code path is executed too */
7846   return XML_STATUS_ERROR;
7847 }
7848 
7849 /* Test that external parser creation running out of memory is
7850  * correctly reported.  Based on the external entity test cases.
7851  */
7852 START_TEST(test_alloc_create_external_parser) {
7853   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
7854                      "<!DOCTYPE doc SYSTEM 'foo'>\n"
7855                      "<doc>&entity;</doc>";
7856   char foo_text[] = "<!ELEMENT doc (#PCDATA)*>";
7857 
7858   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
7859   XML_SetUserData(g_parser, foo_text);
7860   XML_SetExternalEntityRefHandler(g_parser, external_entity_duff_loader);
7861   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7862       != XML_STATUS_ERROR) {
7863     fail("External parser allocator returned success incorrectly");
7864   }
7865 }
7866 END_TEST
7867 
7868 /* More external parser memory allocation testing */
7869 START_TEST(test_alloc_run_external_parser) {
7870   const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
7871                      "<!DOCTYPE doc SYSTEM 'foo'>\n"
7872                      "<doc>&entity;</doc>";
7873   char foo_text[] = "<!ELEMENT doc (#PCDATA)*>";
7874   unsigned int i;
7875   const unsigned int max_alloc_count = 15;
7876 
7877   for (i = 0; i < max_alloc_count; i++) {
7878     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
7879     XML_SetUserData(g_parser, foo_text);
7880     XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
7881     allocation_count = i;
7882     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7883         != XML_STATUS_ERROR)
7884       break;
7885     /* See comment in test_alloc_parse_xdecl() */
7886     alloc_teardown();
7887     alloc_setup();
7888   }
7889   if (i == 0)
7890     fail("Parsing ignored failing allocator");
7891   else if (i == max_alloc_count)
7892     fail("Parsing failed with allocation count 10");
7893 }
7894 END_TEST
7895 
7896 static int XMLCALL
7897 external_entity_dbl_handler(XML_Parser parser, const XML_Char *context,
7898                             const XML_Char *base, const XML_Char *systemId,
7899                             const XML_Char *publicId) {
7900   intptr_t callno = (intptr_t)XML_GetUserData(parser);
7901   const char *text;
7902   XML_Parser new_parser;
7903   int i;
7904   const int max_alloc_count = 20;
7905 
7906   UNUSED_P(base);
7907   UNUSED_P(systemId);
7908   UNUSED_P(publicId);
7909   if (callno == 0) {
7910     /* First time through, check how many calls to malloc occur */
7911     text = ("<!ELEMENT doc (e+)>\n"
7912             "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
7913             "<!ELEMENT e EMPTY>\n");
7914     allocation_count = 10000;
7915     new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
7916     if (new_parser == NULL) {
7917       fail("Unable to allocate first external parser");
7918       return XML_STATUS_ERROR;
7919     }
7920     /* Stash the number of calls in the user data */
7921     XML_SetUserData(parser, (void *)(intptr_t)(10000 - allocation_count));
7922   } else {
7923     text = ("<?xml version='1.0' encoding='us-ascii'?>"
7924             "<e/>");
7925     /* Try at varying levels to exercise more code paths */
7926     for (i = 0; i < max_alloc_count; i++) {
7927       allocation_count = callno + i;
7928       new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
7929       if (new_parser != NULL)
7930         break;
7931     }
7932     if (i == 0) {
7933       fail("Second external parser unexpectedly created");
7934       XML_ParserFree(new_parser);
7935       return XML_STATUS_ERROR;
7936     } else if (i == max_alloc_count) {
7937       fail("Second external parser not created");
7938       return XML_STATUS_ERROR;
7939     }
7940   }
7941 
7942   allocation_count = ALLOC_ALWAYS_SUCCEED;
7943   if (_XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE)
7944       == XML_STATUS_ERROR) {
7945     xml_failure(new_parser);
7946     return XML_STATUS_ERROR;
7947   }
7948   XML_ParserFree(new_parser);
7949   return XML_STATUS_OK;
7950 }
7951 
7952 /* Test that running out of memory in dtdCopy is correctly reported.
7953  * Based on test_default_ns_from_ext_subset_and_ext_ge()
7954  */
7955 START_TEST(test_alloc_dtd_copy_default_atts) {
7956   const char *text = "<?xml version='1.0'?>\n"
7957                      "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
7958                      "  <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
7959                      "]>\n"
7960                      "<doc xmlns='http://example.org/ns1'>\n"
7961                      "&en;\n"
7962                      "</doc>";
7963 
7964   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
7965   XML_SetExternalEntityRefHandler(g_parser, external_entity_dbl_handler);
7966   XML_SetUserData(g_parser, NULL);
7967   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7968       == XML_STATUS_ERROR)
7969     xml_failure(g_parser);
7970 }
7971 END_TEST
7972 
7973 static int XMLCALL
7974 external_entity_dbl_handler_2(XML_Parser parser, const XML_Char *context,
7975                               const XML_Char *base, const XML_Char *systemId,
7976                               const XML_Char *publicId) {
7977   intptr_t callno = (intptr_t)XML_GetUserData(parser);
7978   const char *text;
7979   XML_Parser new_parser;
7980   enum XML_Status rv;
7981 
7982   UNUSED_P(base);
7983   UNUSED_P(systemId);
7984   UNUSED_P(publicId);
7985   if (callno == 0) {
7986     /* Try different allocation levels for whole exercise */
7987     text = ("<!ELEMENT doc (e+)>\n"
7988             "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
7989             "<!ELEMENT e EMPTY>\n");
7990     XML_SetUserData(parser, (void *)(intptr_t)1);
7991     new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
7992     if (new_parser == NULL)
7993       return XML_STATUS_ERROR;
7994     rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
7995   } else {
7996     /* Just run through once */
7997     text = ("<?xml version='1.0' encoding='us-ascii'?>"
7998             "<e/>");
7999     new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
8000     if (new_parser == NULL)
8001       return XML_STATUS_ERROR;
8002     rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
8003   }
8004   XML_ParserFree(new_parser);
8005   if (rv == XML_STATUS_ERROR)
8006     return XML_STATUS_ERROR;
8007   return XML_STATUS_OK;
8008 }
8009 
8010 /* Test more external entity allocation failure paths */
8011 START_TEST(test_alloc_external_entity) {
8012   const char *text = "<?xml version='1.0'?>\n"
8013                      "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
8014                      "  <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
8015                      "]>\n"
8016                      "<doc xmlns='http://example.org/ns1'>\n"
8017                      "&en;\n"
8018                      "</doc>";
8019   int i;
8020   const int alloc_test_max_repeats = 50;
8021 
8022   for (i = 0; i < alloc_test_max_repeats; i++) {
8023     allocation_count = -1;
8024     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8025     XML_SetExternalEntityRefHandler(g_parser, external_entity_dbl_handler_2);
8026     XML_SetUserData(g_parser, NULL);
8027     allocation_count = i;
8028     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8029         == XML_STATUS_OK)
8030       break;
8031     /* See comment in test_alloc_parse_xdecl() */
8032     alloc_teardown();
8033     alloc_setup();
8034   }
8035   allocation_count = -1;
8036   if (i == 0)
8037     fail("External entity parsed despite duff allocator");
8038   if (i == alloc_test_max_repeats)
8039     fail("External entity not parsed at max allocation count");
8040 }
8041 END_TEST
8042 
8043 /* Test more allocation failure paths */
8044 static int XMLCALL
8045 external_entity_alloc_set_encoding(XML_Parser parser, const XML_Char *context,
8046                                    const XML_Char *base,
8047                                    const XML_Char *systemId,
8048                                    const XML_Char *publicId) {
8049   /* As for external_entity_loader() */
8050   const char *text = "<?xml encoding='iso-8859-3'?>"
8051                      "\xC3\xA9";
8052   XML_Parser ext_parser;
8053   enum XML_Status status;
8054 
8055   UNUSED_P(base);
8056   UNUSED_P(systemId);
8057   UNUSED_P(publicId);
8058   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
8059   if (ext_parser == NULL)
8060     return XML_STATUS_ERROR;
8061   if (! XML_SetEncoding(ext_parser, XCS("utf-8"))) {
8062     XML_ParserFree(ext_parser);
8063     return XML_STATUS_ERROR;
8064   }
8065   status
8066       = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
8067   XML_ParserFree(ext_parser);
8068   if (status == XML_STATUS_ERROR)
8069     return XML_STATUS_ERROR;
8070   return XML_STATUS_OK;
8071 }
8072 
8073 START_TEST(test_alloc_ext_entity_set_encoding) {
8074   const char *text = "<!DOCTYPE doc [\n"
8075                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
8076                      "]>\n"
8077                      "<doc>&en;</doc>";
8078   int i;
8079   const int max_allocation_count = 30;
8080 
8081   for (i = 0; i < max_allocation_count; i++) {
8082     XML_SetExternalEntityRefHandler(g_parser,
8083                                     external_entity_alloc_set_encoding);
8084     allocation_count = i;
8085     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8086         == XML_STATUS_OK)
8087       break;
8088     allocation_count = -1;
8089     /* See comment in test_alloc_parse_xdecl() */
8090     alloc_teardown();
8091     alloc_setup();
8092   }
8093   if (i == 0)
8094     fail("Encoding check succeeded despite failing allocator");
8095   if (i == max_allocation_count)
8096     fail("Encoding failed at max allocation count");
8097 }
8098 END_TEST
8099 
8100 static int XMLCALL
8101 unknown_released_encoding_handler(void *data, const XML_Char *encoding,
8102                                   XML_Encoding *info) {
8103   UNUSED_P(data);
8104   if (! xcstrcmp(encoding, XCS("unsupported-encoding"))) {
8105     int i;
8106 
8107     for (i = 0; i < 256; i++)
8108       info->map[i] = i;
8109     info->data = NULL;
8110     info->convert = NULL;
8111     info->release = dummy_release;
8112     return XML_STATUS_OK;
8113   }
8114   return XML_STATUS_ERROR;
8115 }
8116 
8117 /* Test the effects of allocation failure in internal entities.
8118  * Based on test_unknown_encoding_internal_entity
8119  */
8120 START_TEST(test_alloc_internal_entity) {
8121   const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
8122                      "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
8123                      "<test a='&foo;'/>";
8124   unsigned int i;
8125   const unsigned int max_alloc_count = 20;
8126 
8127   for (i = 0; i < max_alloc_count; i++) {
8128     allocation_count = i;
8129     XML_SetUnknownEncodingHandler(g_parser, unknown_released_encoding_handler,
8130                                   NULL);
8131     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8132         != XML_STATUS_ERROR)
8133       break;
8134     /* See comment in test_alloc_parse_xdecl() */
8135     alloc_teardown();
8136     alloc_setup();
8137   }
8138   if (i == 0)
8139     fail("Internal entity worked despite failing allocations");
8140   else if (i == max_alloc_count)
8141     fail("Internal entity failed at max allocation count");
8142 }
8143 END_TEST
8144 
8145 /* Test the robustness against allocation failure of element handling
8146  * Based on test_dtd_default_handling().
8147  */
8148 START_TEST(test_alloc_dtd_default_handling) {
8149   const char *text = "<!DOCTYPE doc [\n"
8150                      "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
8151                      "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
8152                      "<!ENTITY e1 SYSTEM 'http://example.org/e' NDATA n>\n"
8153                      "<!ELEMENT doc (#PCDATA)>\n"
8154                      "<!ATTLIST doc a CDATA #IMPLIED>\n"
8155                      "<?pi in dtd?>\n"
8156                      "<!--comment in dtd-->\n"
8157                      "]>\n"
8158                      "<doc><![CDATA[text in doc]]></doc>";
8159   const XML_Char *expected = XCS("\n\n\n\n\n\n\n\n\n<doc>text in doc</doc>");
8160   CharData storage;
8161   int i;
8162   const int max_alloc_count = 25;
8163 
8164   for (i = 0; i < max_alloc_count; i++) {
8165     allocation_count = i;
8166     dummy_handler_flags = 0;
8167     XML_SetDefaultHandler(g_parser, accumulate_characters);
8168     XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
8169                               dummy_end_doctype_handler);
8170     XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
8171     XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
8172     XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
8173     XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
8174     XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
8175     XML_SetCommentHandler(g_parser, dummy_comment_handler);
8176     XML_SetCdataSectionHandler(g_parser, dummy_start_cdata_handler,
8177                                dummy_end_cdata_handler);
8178     XML_SetUnparsedEntityDeclHandler(g_parser,
8179                                      dummy_unparsed_entity_decl_handler);
8180     CharData_Init(&storage);
8181     XML_SetUserData(g_parser, &storage);
8182     XML_SetCharacterDataHandler(g_parser, accumulate_characters);
8183     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8184         != XML_STATUS_ERROR)
8185       break;
8186     /* See comment in test_alloc_parse_xdecl() */
8187     alloc_teardown();
8188     alloc_setup();
8189   }
8190   if (i == 0)
8191     fail("Default DTD parsed despite allocation failures");
8192   if (i == max_alloc_count)
8193     fail("Default DTD not parsed with maximum alloc count");
8194   CharData_CheckXMLChars(&storage, expected);
8195   if (dummy_handler_flags
8196       != (DUMMY_START_DOCTYPE_HANDLER_FLAG | DUMMY_END_DOCTYPE_HANDLER_FLAG
8197           | DUMMY_ENTITY_DECL_HANDLER_FLAG | DUMMY_NOTATION_DECL_HANDLER_FLAG
8198           | DUMMY_ELEMENT_DECL_HANDLER_FLAG | DUMMY_ATTLIST_DECL_HANDLER_FLAG
8199           | DUMMY_COMMENT_HANDLER_FLAG | DUMMY_PI_HANDLER_FLAG
8200           | DUMMY_START_CDATA_HANDLER_FLAG | DUMMY_END_CDATA_HANDLER_FLAG
8201           | DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG))
8202     fail("Not all handlers were called");
8203 }
8204 END_TEST
8205 
8206 /* Test robustness of XML_SetEncoding() with a failing allocator */
8207 START_TEST(test_alloc_explicit_encoding) {
8208   int i;
8209   const int max_alloc_count = 5;
8210 
8211   for (i = 0; i < max_alloc_count; i++) {
8212     allocation_count = i;
8213     if (XML_SetEncoding(g_parser, XCS("us-ascii")) == XML_STATUS_OK)
8214       break;
8215   }
8216   if (i == 0)
8217     fail("Encoding set despite failing allocator");
8218   else if (i == max_alloc_count)
8219     fail("Encoding not set at max allocation count");
8220 }
8221 END_TEST
8222 
8223 /* Test robustness of XML_SetBase against a failing allocator */
8224 START_TEST(test_alloc_set_base) {
8225   const XML_Char *new_base = XCS("/local/file/name.xml");
8226   int i;
8227   const int max_alloc_count = 5;
8228 
8229   for (i = 0; i < max_alloc_count; i++) {
8230     allocation_count = i;
8231     if (XML_SetBase(g_parser, new_base) == XML_STATUS_OK)
8232       break;
8233   }
8234   if (i == 0)
8235     fail("Base set despite failing allocator");
8236   else if (i == max_alloc_count)
8237     fail("Base not set with max allocation count");
8238 }
8239 END_TEST
8240 
8241 /* Test buffer extension in the face of a duff reallocator */
8242 START_TEST(test_alloc_realloc_buffer) {
8243   const char *text = get_buffer_test_text;
8244   void *buffer;
8245   int i;
8246   const int max_realloc_count = 10;
8247 
8248   /* Get a smallish buffer */
8249   for (i = 0; i < max_realloc_count; i++) {
8250     reallocation_count = i;
8251     buffer = XML_GetBuffer(g_parser, 1536);
8252     if (buffer == NULL)
8253       fail("1.5K buffer reallocation failed");
8254     assert(buffer != NULL);
8255     memcpy(buffer, text, strlen(text));
8256     if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
8257         == XML_STATUS_OK)
8258       break;
8259     /* See comment in test_alloc_parse_xdecl() */
8260     alloc_teardown();
8261     alloc_setup();
8262   }
8263   reallocation_count = -1;
8264   if (i == 0)
8265     fail("Parse succeeded with no reallocation");
8266   else if (i == max_realloc_count)
8267     fail("Parse failed with max reallocation count");
8268 }
8269 END_TEST
8270 
8271 /* Same test for external entity parsers */
8272 static int XMLCALL
8273 external_entity_reallocator(XML_Parser parser, const XML_Char *context,
8274                             const XML_Char *base, const XML_Char *systemId,
8275                             const XML_Char *publicId) {
8276   const char *text = get_buffer_test_text;
8277   XML_Parser ext_parser;
8278   void *buffer;
8279   enum XML_Status status;
8280 
8281   UNUSED_P(base);
8282   UNUSED_P(systemId);
8283   UNUSED_P(publicId);
8284   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
8285   if (ext_parser == NULL)
8286     fail("Could not create external entity parser");
8287 
8288   reallocation_count = (intptr_t)XML_GetUserData(parser);
8289   buffer = XML_GetBuffer(ext_parser, 1536);
8290   if (buffer == NULL)
8291     fail("Buffer allocation failed");
8292   assert(buffer != NULL);
8293   memcpy(buffer, text, strlen(text));
8294   status = XML_ParseBuffer(ext_parser, (int)strlen(text), XML_FALSE);
8295   reallocation_count = -1;
8296   XML_ParserFree(ext_parser);
8297   return (status == XML_STATUS_OK) ? XML_STATUS_OK : XML_STATUS_ERROR;
8298 }
8299 
8300 START_TEST(test_alloc_ext_entity_realloc_buffer) {
8301   const char *text = "<!DOCTYPE doc [\n"
8302                      "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
8303                      "]>\n"
8304                      "<doc>&en;</doc>";
8305   int i;
8306   const int max_realloc_count = 10;
8307 
8308   for (i = 0; i < max_realloc_count; i++) {
8309     XML_SetExternalEntityRefHandler(g_parser, external_entity_reallocator);
8310     XML_SetUserData(g_parser, (void *)(intptr_t)i);
8311     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8312         == XML_STATUS_OK)
8313       break;
8314     /* See comment in test_alloc_parse_xdecl() */
8315     alloc_teardown();
8316     alloc_setup();
8317   }
8318   if (i == 0)
8319     fail("Succeeded with no reallocations");
8320   if (i == max_realloc_count)
8321     fail("Failed with max reallocations");
8322 }
8323 END_TEST
8324 
8325 /* Test elements with many attributes are handled correctly */
8326 START_TEST(test_alloc_realloc_many_attributes) {
8327   const char *text = "<!DOCTYPE doc [\n"
8328                      "<!ATTLIST doc za CDATA 'default'>\n"
8329                      "<!ATTLIST doc zb CDATA 'def2'>\n"
8330                      "<!ATTLIST doc zc CDATA 'def3'>\n"
8331                      "]>\n"
8332                      "<doc a='1'"
8333                      "     b='2'"
8334                      "     c='3'"
8335                      "     d='4'"
8336                      "     e='5'"
8337                      "     f='6'"
8338                      "     g='7'"
8339                      "     h='8'"
8340                      "     i='9'"
8341                      "     j='10'"
8342                      "     k='11'"
8343                      "     l='12'"
8344                      "     m='13'"
8345                      "     n='14'"
8346                      "     p='15'"
8347                      "     q='16'"
8348                      "     r='17'"
8349                      "     s='18'>"
8350                      "</doc>";
8351   int i;
8352   const int max_realloc_count = 10;
8353 
8354   for (i = 0; i < max_realloc_count; i++) {
8355     reallocation_count = i;
8356     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8357         != XML_STATUS_ERROR)
8358       break;
8359     /* See comment in test_alloc_parse_xdecl() */
8360     alloc_teardown();
8361     alloc_setup();
8362   }
8363   if (i == 0)
8364     fail("Parse succeeded despite no reallocations");
8365   if (i == max_realloc_count)
8366     fail("Parse failed at max reallocations");
8367 }
8368 END_TEST
8369 
8370 /* Test handling of a public entity with failing allocator */
8371 START_TEST(test_alloc_public_entity_value) {
8372   const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
8373                      "<doc></doc>\n";
8374   char dtd_text[]
8375       = "<!ELEMENT doc EMPTY>\n"
8376         "<!ENTITY % e1 PUBLIC 'foo' 'bar.ent'>\n"
8377         "<!ENTITY % "
8378         /* Each line is 64 characters */
8379         "ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
8380         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8381         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8382         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8383         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8384         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8385         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8386         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8387         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8388         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8389         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8390         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8391         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8392         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8393         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8394         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8395         " '%e1;'>\n"
8396         "%e1;\n";
8397   int i;
8398   const int max_alloc_count = 50;
8399 
8400   for (i = 0; i < max_alloc_count; i++) {
8401     allocation_count = i;
8402     dummy_handler_flags = 0;
8403     XML_SetUserData(g_parser, dtd_text);
8404     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8405     XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
8406     /* Provoke a particular code path */
8407     XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
8408     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8409         != XML_STATUS_ERROR)
8410       break;
8411     /* See comment in test_alloc_parse_xdecl() */
8412     alloc_teardown();
8413     alloc_setup();
8414   }
8415   if (i == 0)
8416     fail("Parsing worked despite failing allocation");
8417   if (i == max_alloc_count)
8418     fail("Parsing failed at max allocation count");
8419   if (dummy_handler_flags != DUMMY_ENTITY_DECL_HANDLER_FLAG)
8420     fail("Entity declaration handler not called");
8421 }
8422 END_TEST
8423 
8424 START_TEST(test_alloc_realloc_subst_public_entity_value) {
8425   const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
8426                      "<doc></doc>\n";
8427   char dtd_text[]
8428       = "<!ELEMENT doc EMPTY>\n"
8429         "<!ENTITY % "
8430         /* Each line is 64 characters */
8431         "ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
8432         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8433         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8434         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8435         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8436         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8437         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8438         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8439         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8440         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8441         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8442         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8443         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8444         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8445         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8446         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8447         " PUBLIC 'foo' 'bar.ent'>\n"
8448         "%ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
8449         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8450         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8451         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8452         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8453         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8454         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8455         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8456         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8457         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8458         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8459         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8460         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8461         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8462         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8463         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP;";
8464   int i;
8465   const int max_realloc_count = 10;
8466 
8467   for (i = 0; i < max_realloc_count; i++) {
8468     reallocation_count = i;
8469     XML_SetUserData(g_parser, dtd_text);
8470     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8471     XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
8472     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8473         != XML_STATUS_ERROR)
8474       break;
8475     /* See comment in test_alloc_parse_xdecl() */
8476     alloc_teardown();
8477     alloc_setup();
8478   }
8479   if (i == 0)
8480     fail("Parsing worked despite failing reallocation");
8481   if (i == max_realloc_count)
8482     fail("Parsing failed at max reallocation count");
8483 }
8484 END_TEST
8485 
8486 START_TEST(test_alloc_parse_public_doctype) {
8487   const char *text
8488       = "<?xml version='1.0' encoding='utf-8'?>\n"
8489         "<!DOCTYPE doc PUBLIC '"
8490         /* 64 characters per line */
8491         "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
8492         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8493         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8494         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8495         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8496         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8497         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8498         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8499         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8500         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8501         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8502         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8503         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8504         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8505         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8506         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8507         "' 'test'>\n"
8508         "<doc></doc>";
8509   int i;
8510   const int max_alloc_count = 25;
8511 
8512   for (i = 0; i < max_alloc_count; i++) {
8513     allocation_count = i;
8514     dummy_handler_flags = 0;
8515     XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_decl_handler,
8516                               dummy_end_doctype_decl_handler);
8517     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8518         != XML_STATUS_ERROR)
8519       break;
8520     /* See comment in test_alloc_parse_xdecl() */
8521     alloc_teardown();
8522     alloc_setup();
8523   }
8524   if (i == 0)
8525     fail("Parse succeeded despite failing allocator");
8526   if (i == max_alloc_count)
8527     fail("Parse failed at maximum allocation count");
8528   if (dummy_handler_flags
8529       != (DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG
8530           | DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG))
8531     fail("Doctype handler functions not called");
8532 }
8533 END_TEST
8534 
8535 START_TEST(test_alloc_parse_public_doctype_long_name) {
8536   const char *text
8537       = "<?xml version='1.0' encoding='utf-8'?>\n"
8538         "<!DOCTYPE doc PUBLIC 'http://example.com/foo' '"
8539         /* 64 characters per line */
8540         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8541         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8542         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8543         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8544         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8545         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8546         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8547         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8548         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8549         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8550         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8551         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8552         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8553         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8554         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8555         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8556         "'>\n"
8557         "<doc></doc>";
8558   int i;
8559   const int max_alloc_count = 25;
8560 
8561   for (i = 0; i < max_alloc_count; i++) {
8562     allocation_count = i;
8563     XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_decl_handler,
8564                               dummy_end_doctype_decl_handler);
8565     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8566         != XML_STATUS_ERROR)
8567       break;
8568     /* See comment in test_alloc_parse_xdecl() */
8569     alloc_teardown();
8570     alloc_setup();
8571   }
8572   if (i == 0)
8573     fail("Parse succeeded despite failing allocator");
8574   if (i == max_alloc_count)
8575     fail("Parse failed at maximum allocation count");
8576 }
8577 END_TEST
8578 
8579 static int XMLCALL
8580 external_entity_alloc(XML_Parser parser, const XML_Char *context,
8581                       const XML_Char *base, const XML_Char *systemId,
8582                       const XML_Char *publicId) {
8583   const char *text = (const char *)XML_GetUserData(parser);
8584   XML_Parser ext_parser;
8585   int parse_res;
8586 
8587   UNUSED_P(base);
8588   UNUSED_P(systemId);
8589   UNUSED_P(publicId);
8590   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
8591   if (ext_parser == NULL)
8592     return XML_STATUS_ERROR;
8593   parse_res
8594       = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
8595   XML_ParserFree(ext_parser);
8596   return parse_res;
8597 }
8598 
8599 /* Test foreign DTD handling */
8600 START_TEST(test_alloc_set_foreign_dtd) {
8601   const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
8602                       "<doc>&entity;</doc>";
8603   char text2[] = "<!ELEMENT doc (#PCDATA)*>";
8604   int i;
8605   const int max_alloc_count = 25;
8606 
8607   for (i = 0; i < max_alloc_count; i++) {
8608     allocation_count = i;
8609     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8610     XML_SetUserData(g_parser, &text2);
8611     XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
8612     if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
8613       fail("Could not set foreign DTD");
8614     if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_TRUE)
8615         != XML_STATUS_ERROR)
8616       break;
8617     /* See comment in test_alloc_parse_xdecl() */
8618     alloc_teardown();
8619     alloc_setup();
8620   }
8621   if (i == 0)
8622     fail("Parse succeeded despite failing allocator");
8623   if (i == max_alloc_count)
8624     fail("Parse failed at maximum allocation count");
8625 }
8626 END_TEST
8627 
8628 /* Test based on ibm/valid/P32/ibm32v04.xml */
8629 START_TEST(test_alloc_attribute_enum_value) {
8630   const char *text = "<?xml version='1.0' standalone='no'?>\n"
8631                      "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
8632                      "<animal>This is a \n    <a/>  \n\nyellow tiger</animal>";
8633   char dtd_text[] = "<!ELEMENT animal (#PCDATA|a)*>\n"
8634                     "<!ELEMENT a EMPTY>\n"
8635                     "<!ATTLIST animal xml:space (default|preserve) 'preserve'>";
8636   int i;
8637   const int max_alloc_count = 30;
8638 
8639   for (i = 0; i < max_alloc_count; i++) {
8640     allocation_count = i;
8641     XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
8642     XML_SetUserData(g_parser, dtd_text);
8643     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8644     /* An attribute list handler provokes a different code path */
8645     XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
8646     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8647         != XML_STATUS_ERROR)
8648       break;
8649     /* See comment in test_alloc_parse_xdecl() */
8650     alloc_teardown();
8651     alloc_setup();
8652   }
8653   if (i == 0)
8654     fail("Parse succeeded despite failing allocator");
8655   if (i == max_alloc_count)
8656     fail("Parse failed at maximum allocation count");
8657 }
8658 END_TEST
8659 
8660 /* Test attribute enums sufficient to overflow the string pool */
8661 START_TEST(test_alloc_realloc_attribute_enum_value) {
8662   const char *text = "<?xml version='1.0' standalone='no'?>\n"
8663                      "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
8664                      "<animal>This is a yellow tiger</animal>";
8665   /* We wish to define a collection of attribute enums that will
8666    * cause the string pool storing them to have to expand.  This
8667    * means more than 1024 bytes, including the parentheses and
8668    * separator bars.
8669    */
8670   char dtd_text[]
8671       = "<!ELEMENT animal (#PCDATA)*>\n"
8672         "<!ATTLIST animal thing "
8673         "(default"
8674         /* Each line is 64 characters */
8675         "|ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8676         "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8677         "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8678         "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8679         "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8680         "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8681         "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8682         "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8683         "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8684         "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8685         "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8686         "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8687         "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8688         "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8689         "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8690         "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO)"
8691         " 'default'>";
8692   int i;
8693   const int max_realloc_count = 10;
8694 
8695   for (i = 0; i < max_realloc_count; i++) {
8696     reallocation_count = i;
8697     XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
8698     XML_SetUserData(g_parser, dtd_text);
8699     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8700     /* An attribute list handler provokes a different code path */
8701     XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
8702     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8703         != XML_STATUS_ERROR)
8704       break;
8705     /* See comment in test_alloc_parse_xdecl() */
8706     alloc_teardown();
8707     alloc_setup();
8708   }
8709   if (i == 0)
8710     fail("Parse succeeded despite failing reallocator");
8711   if (i == max_realloc_count)
8712     fail("Parse failed at maximum reallocation count");
8713 }
8714 END_TEST
8715 
8716 /* Test attribute enums in a #IMPLIED attribute forcing pool growth */
8717 START_TEST(test_alloc_realloc_implied_attribute) {
8718   /* Forcing this particular code path is a balancing act.  The
8719    * addition of the closing parenthesis and terminal NUL must be
8720    * what pushes the string of enums over the 1024-byte limit,
8721    * otherwise a different code path will pick up the realloc.
8722    */
8723   const char *text
8724       = "<!DOCTYPE doc [\n"
8725         "<!ELEMENT doc EMPTY>\n"
8726         "<!ATTLIST doc a "
8727         /* Each line is 64 characters */
8728         "(ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8729         "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8730         "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8731         "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8732         "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8733         "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8734         "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8735         "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8736         "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8737         "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8738         "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8739         "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8740         "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8741         "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8742         "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8743         "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN)"
8744         " #IMPLIED>\n"
8745         "]><doc/>";
8746   int i;
8747   const int max_realloc_count = 10;
8748 
8749   for (i = 0; i < max_realloc_count; i++) {
8750     reallocation_count = i;
8751     XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
8752     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8753         != XML_STATUS_ERROR)
8754       break;
8755     /* See comment in test_alloc_parse_xdecl() */
8756     alloc_teardown();
8757     alloc_setup();
8758   }
8759   if (i == 0)
8760     fail("Parse succeeded despite failing reallocator");
8761   if (i == max_realloc_count)
8762     fail("Parse failed at maximum reallocation count");
8763 }
8764 END_TEST
8765 
8766 /* Test attribute enums in a defaulted attribute forcing pool growth */
8767 START_TEST(test_alloc_realloc_default_attribute) {
8768   /* Forcing this particular code path is a balancing act.  The
8769    * addition of the closing parenthesis and terminal NUL must be
8770    * what pushes the string of enums over the 1024-byte limit,
8771    * otherwise a different code path will pick up the realloc.
8772    */
8773   const char *text
8774       = "<!DOCTYPE doc [\n"
8775         "<!ELEMENT doc EMPTY>\n"
8776         "<!ATTLIST doc a "
8777         /* Each line is 64 characters */
8778         "(ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8779         "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8780         "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8781         "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8782         "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8783         "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8784         "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8785         "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8786         "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8787         "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8788         "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8789         "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8790         "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8791         "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8792         "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8793         "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN)"
8794         " 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO'"
8795         ">\n]><doc/>";
8796   int i;
8797   const int max_realloc_count = 10;
8798 
8799   for (i = 0; i < max_realloc_count; i++) {
8800     reallocation_count = i;
8801     XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
8802     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8803         != XML_STATUS_ERROR)
8804       break;
8805     /* See comment in test_alloc_parse_xdecl() */
8806     alloc_teardown();
8807     alloc_setup();
8808   }
8809   if (i == 0)
8810     fail("Parse succeeded despite failing reallocator");
8811   if (i == max_realloc_count)
8812     fail("Parse failed at maximum reallocation count");
8813 }
8814 END_TEST
8815 
8816 /* Test long notation name with dodgy allocator */
8817 START_TEST(test_alloc_notation) {
8818   const char *text
8819       = "<!DOCTYPE doc [\n"
8820         "<!NOTATION "
8821         /* Each line is 64 characters */
8822         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8823         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8824         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8825         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8826         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8827         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8828         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8829         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8830         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8831         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8832         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8833         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8834         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8835         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8836         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8837         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8838         " SYSTEM 'http://example.org/n'>\n"
8839         "<!ENTITY e SYSTEM 'http://example.org/e' NDATA "
8840         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8841         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8842         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8843         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8844         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8845         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8846         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8847         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8848         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8849         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8850         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8851         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8852         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8853         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8854         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8855         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8856         ">\n"
8857         "<!ELEMENT doc EMPTY>\n"
8858         "]>\n<doc/>";
8859   int i;
8860   const int max_alloc_count = 20;
8861 
8862   for (i = 0; i < max_alloc_count; i++) {
8863     allocation_count = i;
8864     dummy_handler_flags = 0;
8865     XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
8866     XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
8867     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8868         != XML_STATUS_ERROR)
8869       break;
8870     /* See comment in test_alloc_parse_xdecl() */
8871     alloc_teardown();
8872     alloc_setup();
8873   }
8874   if (i == 0)
8875     fail("Parse succeeded despite allocation failures");
8876   if (i == max_alloc_count)
8877     fail("Parse failed at maximum allocation count");
8878   if (dummy_handler_flags
8879       != (DUMMY_ENTITY_DECL_HANDLER_FLAG | DUMMY_NOTATION_DECL_HANDLER_FLAG))
8880     fail("Entity declaration handler not called");
8881 }
8882 END_TEST
8883 
8884 /* Test public notation with dodgy allocator */
8885 START_TEST(test_alloc_public_notation) {
8886   const char *text
8887       = "<!DOCTYPE doc [\n"
8888         "<!NOTATION note PUBLIC '"
8889         /* 64 characters per line */
8890         "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
8891         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8892         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8893         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8894         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8895         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8896         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8897         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8898         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8899         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8900         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8901         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8902         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8903         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8904         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8905         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8906         "' 'foo'>\n"
8907         "<!ENTITY e SYSTEM 'http://example.com/e' NDATA note>\n"
8908         "<!ELEMENT doc EMPTY>\n"
8909         "]>\n<doc/>";
8910   int i;
8911   const int max_alloc_count = 20;
8912 
8913   for (i = 0; i < max_alloc_count; i++) {
8914     allocation_count = i;
8915     dummy_handler_flags = 0;
8916     XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
8917     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8918         != XML_STATUS_ERROR)
8919       break;
8920     /* See comment in test_alloc_parse_xdecl() */
8921     alloc_teardown();
8922     alloc_setup();
8923   }
8924   if (i == 0)
8925     fail("Parse succeeded despite allocation failures");
8926   if (i == max_alloc_count)
8927     fail("Parse failed at maximum allocation count");
8928   if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
8929     fail("Notation handler not called");
8930 }
8931 END_TEST
8932 
8933 /* Test public notation with dodgy allocator */
8934 START_TEST(test_alloc_system_notation) {
8935   const char *text
8936       = "<!DOCTYPE doc [\n"
8937         "<!NOTATION note SYSTEM '"
8938         /* 64 characters per line */
8939         "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
8940         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8941         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8942         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8943         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8944         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8945         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8946         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8947         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8948         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8949         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8950         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8951         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8952         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8953         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8954         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8955         "'>\n"
8956         "<!ENTITY e SYSTEM 'http://example.com/e' NDATA note>\n"
8957         "<!ELEMENT doc EMPTY>\n"
8958         "]>\n<doc/>";
8959   int i;
8960   const int max_alloc_count = 20;
8961 
8962   for (i = 0; i < max_alloc_count; i++) {
8963     allocation_count = i;
8964     dummy_handler_flags = 0;
8965     XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
8966     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8967         != XML_STATUS_ERROR)
8968       break;
8969     /* See comment in test_alloc_parse_xdecl() */
8970     alloc_teardown();
8971     alloc_setup();
8972   }
8973   if (i == 0)
8974     fail("Parse succeeded despite allocation failures");
8975   if (i == max_alloc_count)
8976     fail("Parse failed at maximum allocation count");
8977   if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
8978     fail("Notation handler not called");
8979 }
8980 END_TEST
8981 
8982 START_TEST(test_alloc_nested_groups) {
8983   const char *text
8984       = "<!DOCTYPE doc [\n"
8985         "<!ELEMENT doc "
8986         /* Sixteen elements per line */
8987         "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
8988         "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
8989         "))))))))))))))))))))))))))))))))>\n"
8990         "<!ELEMENT e EMPTY>"
8991         "]>\n"
8992         "<doc><e/></doc>";
8993   CharData storage;
8994   int i;
8995   const int max_alloc_count = 20;
8996 
8997   for (i = 0; i < max_alloc_count; i++) {
8998     allocation_count = i;
8999     CharData_Init(&storage);
9000     XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
9001     XML_SetStartElementHandler(g_parser, record_element_start_handler);
9002     XML_SetUserData(g_parser, &storage);
9003     dummy_handler_flags = 0;
9004     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9005         != XML_STATUS_ERROR)
9006       break;
9007     /* See comment in test_alloc_parse_xdecl() */
9008     alloc_teardown();
9009     alloc_setup();
9010   }
9011 
9012   if (i == 0)
9013     fail("Parse succeeded despite failing reallocator");
9014   if (i == max_alloc_count)
9015     fail("Parse failed at maximum reallocation count");
9016   CharData_CheckXMLChars(&storage, XCS("doce"));
9017   if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
9018     fail("Element handler not fired");
9019 }
9020 END_TEST
9021 
9022 START_TEST(test_alloc_realloc_nested_groups) {
9023   const char *text
9024       = "<!DOCTYPE doc [\n"
9025         "<!ELEMENT doc "
9026         /* Sixteen elements per line */
9027         "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
9028         "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
9029         "))))))))))))))))))))))))))))))))>\n"
9030         "<!ELEMENT e EMPTY>"
9031         "]>\n"
9032         "<doc><e/></doc>";
9033   CharData storage;
9034   int i;
9035   const int max_realloc_count = 10;
9036 
9037   for (i = 0; i < max_realloc_count; i++) {
9038     reallocation_count = i;
9039     CharData_Init(&storage);
9040     XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
9041     XML_SetStartElementHandler(g_parser, record_element_start_handler);
9042     XML_SetUserData(g_parser, &storage);
9043     dummy_handler_flags = 0;
9044     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9045         != XML_STATUS_ERROR)
9046       break;
9047     /* See comment in test_alloc_parse_xdecl() */
9048     alloc_teardown();
9049     alloc_setup();
9050   }
9051 
9052   if (i == 0)
9053     fail("Parse succeeded despite failing reallocator");
9054   if (i == max_realloc_count)
9055     fail("Parse failed at maximum reallocation count");
9056   CharData_CheckXMLChars(&storage, XCS("doce"));
9057   if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
9058     fail("Element handler not fired");
9059 }
9060 END_TEST
9061 
9062 START_TEST(test_alloc_large_group) {
9063   const char *text = "<!DOCTYPE doc [\n"
9064                      "<!ELEMENT doc ("
9065                      "a1|a2|a3|a4|a5|a6|a7|a8|"
9066                      "b1|b2|b3|b4|b5|b6|b7|b8|"
9067                      "c1|c2|c3|c4|c5|c6|c7|c8|"
9068                      "d1|d2|d3|d4|d5|d6|d7|d8|"
9069                      "e1"
9070                      ")+>\n"
9071                      "]>\n"
9072                      "<doc>\n"
9073                      "<a1/>\n"
9074                      "</doc>\n";
9075   int i;
9076   const int max_alloc_count = 50;
9077 
9078   for (i = 0; i < max_alloc_count; i++) {
9079     allocation_count = i;
9080     XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
9081     dummy_handler_flags = 0;
9082     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9083         != XML_STATUS_ERROR)
9084       break;
9085     /* See comment in test_alloc_parse_xdecl() */
9086     alloc_teardown();
9087     alloc_setup();
9088   }
9089   if (i == 0)
9090     fail("Parse succeeded despite failing allocator");
9091   if (i == max_alloc_count)
9092     fail("Parse failed at maximum allocation count");
9093   if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
9094     fail("Element handler flag not raised");
9095 }
9096 END_TEST
9097 
9098 START_TEST(test_alloc_realloc_group_choice) {
9099   const char *text = "<!DOCTYPE doc [\n"
9100                      "<!ELEMENT doc ("
9101                      "a1|a2|a3|a4|a5|a6|a7|a8|"
9102                      "b1|b2|b3|b4|b5|b6|b7|b8|"
9103                      "c1|c2|c3|c4|c5|c6|c7|c8|"
9104                      "d1|d2|d3|d4|d5|d6|d7|d8|"
9105                      "e1"
9106                      ")+>\n"
9107                      "]>\n"
9108                      "<doc>\n"
9109                      "<a1/>\n"
9110                      "<b2 attr='foo'>This is a foo</b2>\n"
9111                      "<c3></c3>\n"
9112                      "</doc>\n";
9113   int i;
9114   const int max_realloc_count = 10;
9115 
9116   for (i = 0; i < max_realloc_count; i++) {
9117     reallocation_count = i;
9118     XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
9119     dummy_handler_flags = 0;
9120     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9121         != XML_STATUS_ERROR)
9122       break;
9123     /* See comment in test_alloc_parse_xdecl() */
9124     alloc_teardown();
9125     alloc_setup();
9126   }
9127   if (i == 0)
9128     fail("Parse succeeded despite failing reallocator");
9129   if (i == max_realloc_count)
9130     fail("Parse failed at maximum reallocation count");
9131   if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
9132     fail("Element handler flag not raised");
9133 }
9134 END_TEST
9135 
9136 START_TEST(test_alloc_pi_in_epilog) {
9137   const char *text = "<doc></doc>\n"
9138                      "<?pi in epilog?>";
9139   int i;
9140   const int max_alloc_count = 15;
9141 
9142   for (i = 0; i < max_alloc_count; i++) {
9143     allocation_count = i;
9144     XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
9145     dummy_handler_flags = 0;
9146     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9147         != XML_STATUS_ERROR)
9148       break;
9149     /* See comment in test_alloc_parse_xdecl() */
9150     alloc_teardown();
9151     alloc_setup();
9152   }
9153   if (i == 0)
9154     fail("Parse completed despite failing allocator");
9155   if (i == max_alloc_count)
9156     fail("Parse failed at maximum allocation count");
9157   if (dummy_handler_flags != DUMMY_PI_HANDLER_FLAG)
9158     fail("Processing instruction handler not invoked");
9159 }
9160 END_TEST
9161 
9162 START_TEST(test_alloc_comment_in_epilog) {
9163   const char *text = "<doc></doc>\n"
9164                      "<!-- comment in epilog -->";
9165   int i;
9166   const int max_alloc_count = 15;
9167 
9168   for (i = 0; i < max_alloc_count; i++) {
9169     allocation_count = i;
9170     XML_SetCommentHandler(g_parser, dummy_comment_handler);
9171     dummy_handler_flags = 0;
9172     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9173         != XML_STATUS_ERROR)
9174       break;
9175     /* See comment in test_alloc_parse_xdecl() */
9176     alloc_teardown();
9177     alloc_setup();
9178   }
9179   if (i == 0)
9180     fail("Parse completed despite failing allocator");
9181   if (i == max_alloc_count)
9182     fail("Parse failed at maximum allocation count");
9183   if (dummy_handler_flags != DUMMY_COMMENT_HANDLER_FLAG)
9184     fail("Processing instruction handler not invoked");
9185 }
9186 END_TEST
9187 
9188 START_TEST(test_alloc_realloc_long_attribute_value) {
9189   const char *text
9190       = "<!DOCTYPE doc [<!ENTITY foo '"
9191         /* Each line is 64 characters */
9192         "This entity will be substituted as an attribute value, and is   "
9193         "calculated to be exactly long enough that the terminating NUL   "
9194         "that the library adds internally will trigger the string pool to"
9195         "grow. GHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9196         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9197         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9198         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9199         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9200         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9201         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9202         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9203         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9204         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9205         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9206         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9207         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9208         "'>]>\n"
9209         "<doc a='&foo;'></doc>";
9210   int i;
9211   const int max_realloc_count = 10;
9212 
9213   for (i = 0; i < max_realloc_count; i++) {
9214     reallocation_count = i;
9215     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9216         != XML_STATUS_ERROR)
9217       break;
9218     /* See comment in test_alloc_parse_xdecl() */
9219     alloc_teardown();
9220     alloc_setup();
9221   }
9222   if (i == 0)
9223     fail("Parse succeeded despite failing reallocator");
9224   if (i == max_realloc_count)
9225     fail("Parse failed at maximum reallocation count");
9226 }
9227 END_TEST
9228 
9229 START_TEST(test_alloc_attribute_whitespace) {
9230   const char *text = "<doc a=' '></doc>";
9231   int i;
9232   const int max_alloc_count = 15;
9233 
9234   for (i = 0; i < max_alloc_count; i++) {
9235     allocation_count = i;
9236     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9237         != XML_STATUS_ERROR)
9238       break;
9239     /* See comment in test_alloc_parse_xdecl() */
9240     alloc_teardown();
9241     alloc_setup();
9242   }
9243   if (i == 0)
9244     fail("Parse succeeded despite failing allocator");
9245   if (i == max_alloc_count)
9246     fail("Parse failed at maximum allocation count");
9247 }
9248 END_TEST
9249 
9250 START_TEST(test_alloc_attribute_predefined_entity) {
9251   const char *text = "<doc a='&amp;'></doc>";
9252   int i;
9253   const int max_alloc_count = 15;
9254 
9255   for (i = 0; i < max_alloc_count; i++) {
9256     allocation_count = i;
9257     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9258         != XML_STATUS_ERROR)
9259       break;
9260     /* See comment in test_alloc_parse_xdecl() */
9261     alloc_teardown();
9262     alloc_setup();
9263   }
9264   if (i == 0)
9265     fail("Parse succeeded despite failing allocator");
9266   if (i == max_alloc_count)
9267     fail("Parse failed at maximum allocation count");
9268 }
9269 END_TEST
9270 
9271 /* Test that a character reference at the end of a suitably long
9272  * default value for an attribute can trigger pool growth, and recovers
9273  * if the allocator fails on it.
9274  */
9275 START_TEST(test_alloc_long_attr_default_with_char_ref) {
9276   const char *text
9277       = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '"
9278         /* 64 characters per line */
9279         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9280         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9281         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9282         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9283         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9284         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9285         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9286         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9287         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9288         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9289         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9290         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9291         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9292         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9293         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9294         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHI"
9295         "&#x31;'>]>\n"
9296         "<doc/>";
9297   int i;
9298   const int max_alloc_count = 20;
9299 
9300   for (i = 0; i < max_alloc_count; i++) {
9301     allocation_count = i;
9302     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9303         != XML_STATUS_ERROR)
9304       break;
9305     /* See comment in test_alloc_parse_xdecl() */
9306     alloc_teardown();
9307     alloc_setup();
9308   }
9309   if (i == 0)
9310     fail("Parse succeeded despite failing allocator");
9311   if (i == max_alloc_count)
9312     fail("Parse failed at maximum allocation count");
9313 }
9314 END_TEST
9315 
9316 /* Test that a long character reference substitution triggers a pool
9317  * expansion correctly for an attribute value.
9318  */
9319 START_TEST(test_alloc_long_attr_value) {
9320   const char *text
9321       = "<!DOCTYPE test [<!ENTITY foo '\n"
9322         /* 64 characters per line */
9323         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9324         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9325         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9326         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9327         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9328         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9329         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9330         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9331         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9332         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9333         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9334         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9335         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9336         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9337         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9338         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9339         "'>]>\n"
9340         "<test a='&foo;'/>";
9341   int i;
9342   const int max_alloc_count = 25;
9343 
9344   for (i = 0; i < max_alloc_count; i++) {
9345     allocation_count = i;
9346     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9347         != XML_STATUS_ERROR)
9348       break;
9349     /* See comment in test_alloc_parse_xdecl() */
9350     alloc_teardown();
9351     alloc_setup();
9352   }
9353   if (i == 0)
9354     fail("Parse succeeded despite failing allocator");
9355   if (i == max_alloc_count)
9356     fail("Parse failed at maximum allocation count");
9357 }
9358 END_TEST
9359 
9360 /* Test that an error in a nested parameter entity substitution is
9361  * handled correctly.  It seems unlikely that the code path being
9362  * exercised can be reached purely by carefully crafted XML, but an
9363  * allocation error in the right place will definitely do it.
9364  */
9365 START_TEST(test_alloc_nested_entities) {
9366   const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
9367                      "<doc />";
9368   ExtFaults test_data
9369       = {"<!ENTITY % pe1 '"
9370          /* 64 characters per line */
9371          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9372          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9373          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9374          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9375          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9376          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9377          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9378          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9379          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9380          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9381          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9382          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9383          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9384          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9385          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9386          "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9387          "'>\n"
9388          "<!ENTITY % pe2 '%pe1;'>\n"
9389          "%pe2;",
9390          "Memory Fail not faulted", NULL, XML_ERROR_NO_MEMORY};
9391 
9392   /* Causes an allocation error in a nested storeEntityValue() */
9393   allocation_count = 12;
9394   XML_SetUserData(g_parser, &test_data);
9395   XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9396   XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
9397   expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
9398                  "Entity allocation failure not noted");
9399 }
9400 END_TEST
9401 
9402 START_TEST(test_alloc_realloc_param_entity_newline) {
9403   const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
9404                      "<doc/>";
9405   char dtd_text[]
9406       = "<!ENTITY % pe '<!ATTLIST doc att CDATA \""
9407         /* 64 characters per line */
9408         "This default value is carefully crafted so that the carriage    "
9409         "return right at the end of the entity string causes an internal "
9410         "string pool to have to grow.  This allows us to test the alloc  "
9411         "failure path from that point. OPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9412         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9413         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9414         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9415         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9416         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9417         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9418         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9419         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9420         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9421         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9422         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9423         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDE"
9424         "\">\n'>"
9425         "%pe;\n";
9426   int i;
9427   const int max_realloc_count = 5;
9428 
9429   for (i = 0; i < max_realloc_count; i++) {
9430     reallocation_count = i;
9431     XML_SetUserData(g_parser, dtd_text);
9432     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9433     XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
9434     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9435         != XML_STATUS_ERROR)
9436       break;
9437     /* See comment in test_alloc_parse_xdecl() */
9438     alloc_teardown();
9439     alloc_setup();
9440   }
9441   if (i == 0)
9442     fail("Parse succeeded despite failing reallocator");
9443   if (i == max_realloc_count)
9444     fail("Parse failed at maximum reallocation count");
9445 }
9446 END_TEST
9447 
9448 START_TEST(test_alloc_realloc_ce_extends_pe) {
9449   const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
9450                      "<doc/>";
9451   char dtd_text[]
9452       = "<!ENTITY % pe '<!ATTLIST doc att CDATA \""
9453         /* 64 characters per line */
9454         "This default value is carefully crafted so that the character   "
9455         "entity at the end causes an internal string pool to have to     "
9456         "grow.  This allows us to test the allocation failure path from  "
9457         "that point onwards. EFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9458         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9459         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9460         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9461         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9462         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9463         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9464         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9465         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9466         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9467         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9468         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9469         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFG&#x51;"
9470         "\">\n'>"
9471         "%pe;\n";
9472   int i;
9473   const int max_realloc_count = 5;
9474 
9475   for (i = 0; i < max_realloc_count; i++) {
9476     reallocation_count = i;
9477     XML_SetUserData(g_parser, dtd_text);
9478     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9479     XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
9480     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9481         != XML_STATUS_ERROR)
9482       break;
9483     /* See comment in test_alloc_parse_xdecl() */
9484     alloc_teardown();
9485     alloc_setup();
9486   }
9487   if (i == 0)
9488     fail("Parse succeeded despite failing reallocator");
9489   if (i == max_realloc_count)
9490     fail("Parse failed at maximum reallocation count");
9491 }
9492 END_TEST
9493 
9494 START_TEST(test_alloc_realloc_attributes) {
9495   const char *text = "<!DOCTYPE doc [\n"
9496                      "  <!ATTLIST doc\n"
9497                      "    a1  (a|b|c)   'a'\n"
9498                      "    a2  (foo|bar) #IMPLIED\n"
9499                      "    a3  NMTOKEN   #IMPLIED\n"
9500                      "    a4  NMTOKENS  #IMPLIED\n"
9501                      "    a5  ID        #IMPLIED\n"
9502                      "    a6  IDREF     #IMPLIED\n"
9503                      "    a7  IDREFS    #IMPLIED\n"
9504                      "    a8  ENTITY    #IMPLIED\n"
9505                      "    a9  ENTITIES  #IMPLIED\n"
9506                      "    a10 CDATA     #IMPLIED\n"
9507                      "  >]>\n"
9508                      "<doc>wombat</doc>\n";
9509   int i;
9510   const int max_realloc_count = 5;
9511 
9512   for (i = 0; i < max_realloc_count; i++) {
9513     reallocation_count = i;
9514     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9515         != XML_STATUS_ERROR)
9516       break;
9517     /* See comment in test_alloc_parse_xdecl() */
9518     alloc_teardown();
9519     alloc_setup();
9520   }
9521 
9522   if (i == 0)
9523     fail("Parse succeeded despite failing reallocator");
9524   if (i == max_realloc_count)
9525     fail("Parse failed at maximum reallocation count");
9526 }
9527 END_TEST
9528 
9529 START_TEST(test_alloc_long_doc_name) {
9530   const char *text =
9531       /* 64 characters per line */
9532       "<LongRootElementNameThatWillCauseTheNextAllocationToExpandTheStr"
9533       "ingPoolForTheDTDQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9534       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9535       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9536       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9537       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9538       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9539       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9540       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9541       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9542       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9543       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9544       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9545       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9546       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9547       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9548       " a='1'/>";
9549   int i;
9550   const int max_alloc_count = 20;
9551 
9552   for (i = 0; i < max_alloc_count; i++) {
9553     allocation_count = i;
9554     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9555         != XML_STATUS_ERROR)
9556       break;
9557     /* See comment in test_alloc_parse_xdecl() */
9558     alloc_teardown();
9559     alloc_setup();
9560   }
9561   if (i == 0)
9562     fail("Parsing worked despite failing reallocations");
9563   else if (i == max_alloc_count)
9564     fail("Parsing failed even at max reallocation count");
9565 }
9566 END_TEST
9567 
9568 START_TEST(test_alloc_long_base) {
9569   const char *text = "<!DOCTYPE doc [\n"
9570                      "  <!ENTITY e SYSTEM 'foo'>\n"
9571                      "]>\n"
9572                      "<doc>&e;</doc>";
9573   char entity_text[] = "Hello world";
9574   const XML_Char *base =
9575       /* 64 characters per line */
9576       /* clang-format off */
9577         XCS("LongBaseURI/that/will/overflow/an/internal/buffer/and/cause/it/t")
9578         XCS("o/have/to/grow/PQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9579         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9580         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9581         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9582         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9583         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9584         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9585         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9586         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9587         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9588         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9589         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9590         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9591         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9592         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/");
9593   /* clang-format on */
9594   int i;
9595   const int max_alloc_count = 25;
9596 
9597   for (i = 0; i < max_alloc_count; i++) {
9598     allocation_count = i;
9599     XML_SetUserData(g_parser, entity_text);
9600     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9601     XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
9602     if (XML_SetBase(g_parser, base) == XML_STATUS_ERROR) {
9603       XML_ParserReset(g_parser, NULL);
9604       continue;
9605     }
9606     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9607         != XML_STATUS_ERROR)
9608       break;
9609     /* See comment in test_alloc_parse_xdecl() */
9610     alloc_teardown();
9611     alloc_setup();
9612   }
9613   if (i == 0)
9614     fail("Parsing worked despite failing allocations");
9615   else if (i == max_alloc_count)
9616     fail("Parsing failed even at max allocation count");
9617 }
9618 END_TEST
9619 
9620 START_TEST(test_alloc_long_public_id) {
9621   const char *text
9622       = "<!DOCTYPE doc [\n"
9623         "  <!ENTITY e PUBLIC '"
9624         /* 64 characters per line */
9625         "LongPublicIDThatShouldResultInAnInternalStringPoolGrowingAtASpec"
9626         "ificMomentKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9627         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9628         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9629         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9630         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9631         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9632         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9633         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9634         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9635         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9636         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9637         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9638         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9639         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9640         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9641         "' 'bar'>\n"
9642         "]>\n"
9643         "<doc>&e;</doc>";
9644   char entity_text[] = "Hello world";
9645   int i;
9646   const int max_alloc_count = 40;
9647 
9648   for (i = 0; i < max_alloc_count; i++) {
9649     allocation_count = i;
9650     XML_SetUserData(g_parser, entity_text);
9651     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9652     XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
9653     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9654         != XML_STATUS_ERROR)
9655       break;
9656     /* See comment in test_alloc_parse_xdecl() */
9657     alloc_teardown();
9658     alloc_setup();
9659   }
9660   if (i == 0)
9661     fail("Parsing worked despite failing allocations");
9662   else if (i == max_alloc_count)
9663     fail("Parsing failed even at max allocation count");
9664 }
9665 END_TEST
9666 
9667 START_TEST(test_alloc_long_entity_value) {
9668   const char *text
9669       = "<!DOCTYPE doc [\n"
9670         "  <!ENTITY e1 '"
9671         /* 64 characters per line */
9672         "Long entity value that should provoke a string pool to grow whil"
9673         "e setting up to parse the external entity below. xyz0123456789AB"
9674         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9675         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9676         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9677         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9678         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9679         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9680         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9681         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9682         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9683         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9684         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9685         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9686         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9687         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9688         "'>\n"
9689         "  <!ENTITY e2 SYSTEM 'bar'>\n"
9690         "]>\n"
9691         "<doc>&e2;</doc>";
9692   char entity_text[] = "Hello world";
9693   int i;
9694   const int max_alloc_count = 40;
9695 
9696   for (i = 0; i < max_alloc_count; i++) {
9697     allocation_count = i;
9698     XML_SetUserData(g_parser, entity_text);
9699     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9700     XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
9701     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9702         != XML_STATUS_ERROR)
9703       break;
9704     /* See comment in test_alloc_parse_xdecl() */
9705     alloc_teardown();
9706     alloc_setup();
9707   }
9708   if (i == 0)
9709     fail("Parsing worked despite failing allocations");
9710   else if (i == max_alloc_count)
9711     fail("Parsing failed even at max allocation count");
9712 }
9713 END_TEST
9714 
9715 START_TEST(test_alloc_long_notation) {
9716   const char *text
9717       = "<!DOCTYPE doc [\n"
9718         "  <!NOTATION note SYSTEM '"
9719         /* 64 characters per line */
9720         "ALongNotationNameThatShouldProvokeStringPoolGrowthWhileCallingAn"
9721         "ExternalEntityParserUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9722         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9723         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9724         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9725         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9726         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9727         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9728         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9729         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9730         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9731         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9732         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9733         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9734         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9735         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9736         "'>\n"
9737         "  <!ENTITY e1 SYSTEM 'foo' NDATA "
9738         /* 64 characters per line */
9739         "ALongNotationNameThatShouldProvokeStringPoolGrowthWhileCallingAn"
9740         "ExternalEntityParserUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9741         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9742         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9743         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9744         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9745         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9746         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9747         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9748         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9749         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9750         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9751         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9752         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9753         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9754         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9755         ">\n"
9756         "  <!ENTITY e2 SYSTEM 'bar'>\n"
9757         "]>\n"
9758         "<doc>&e2;</doc>";
9759   ExtOption options[]
9760       = {{XCS("foo"), "Entity Foo"}, {XCS("bar"), "Entity Bar"}, {NULL, NULL}};
9761   int i;
9762   const int max_alloc_count = 40;
9763 
9764   for (i = 0; i < max_alloc_count; i++) {
9765     allocation_count = i;
9766     XML_SetUserData(g_parser, options);
9767     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9768     XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
9769     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9770         != XML_STATUS_ERROR)
9771       break;
9772 
9773     /* See comment in test_alloc_parse_xdecl() */
9774     alloc_teardown();
9775     alloc_setup();
9776   }
9777   if (i == 0)
9778     fail("Parsing worked despite failing allocations");
9779   else if (i == max_alloc_count)
9780     fail("Parsing failed even at max allocation count");
9781 }
9782 END_TEST
9783 
9784 static void
9785 nsalloc_setup(void) {
9786   XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
9787   XML_Char ns_sep[2] = {' ', '\0'};
9788 
9789   /* Ensure the parser creation will go through */
9790   allocation_count = ALLOC_ALWAYS_SUCCEED;
9791   reallocation_count = REALLOC_ALWAYS_SUCCEED;
9792   g_parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep);
9793   if (g_parser == NULL)
9794     fail("Parser not created");
9795 }
9796 
9797 static void
9798 nsalloc_teardown(void) {
9799   basic_teardown();
9800 }
9801 
9802 /* Test the effects of allocation failure in simple namespace parsing.
9803  * Based on test_ns_default_with_empty_uri()
9804  */
9805 START_TEST(test_nsalloc_xmlns) {
9806   const char *text = "<doc xmlns='http://example.org/'>\n"
9807                      "  <e xmlns=''/>\n"
9808                      "</doc>";
9809   unsigned int i;
9810   const unsigned int max_alloc_count = 30;
9811 
9812   for (i = 0; i < max_alloc_count; i++) {
9813     allocation_count = i;
9814     /* Exercise more code paths with a default handler */
9815     XML_SetDefaultHandler(g_parser, dummy_default_handler);
9816     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9817         != XML_STATUS_ERROR)
9818       break;
9819     /* Resetting the parser is insufficient, because some memory
9820      * allocations are cached within the parser.  Instead we use
9821      * the teardown and setup routines to ensure that we have the
9822      * right sort of parser back in our hands.
9823      */
9824     nsalloc_teardown();
9825     nsalloc_setup();
9826   }
9827   if (i == 0)
9828     fail("Parsing worked despite failing allocations");
9829   else if (i == max_alloc_count)
9830     fail("Parsing failed even at maximum allocation count");
9831 }
9832 END_TEST
9833 
9834 /* Test XML_ParseBuffer interface with namespace and a dicky allocator */
9835 START_TEST(test_nsalloc_parse_buffer) {
9836   const char *text = "<doc>Hello</doc>";
9837   void *buffer;
9838 
9839   /* Try a parse before the start of the world */
9840   /* (Exercises new code path) */
9841   if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_ERROR)
9842     fail("Pre-init XML_ParseBuffer not faulted");
9843   if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_BUFFER)
9844     fail("Pre-init XML_ParseBuffer faulted for wrong reason");
9845 
9846   buffer = XML_GetBuffer(g_parser, 1 /* any small number greater than 0 */);
9847   if (buffer == NULL)
9848     fail("Could not acquire parse buffer");
9849 
9850   allocation_count = 0;
9851   if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_ERROR)
9852     fail("Pre-init XML_ParseBuffer not faulted");
9853   if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_MEMORY)
9854     fail("Pre-init XML_ParseBuffer faulted for wrong reason");
9855 
9856   /* Now with actual memory allocation */
9857   allocation_count = ALLOC_ALWAYS_SUCCEED;
9858   if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_OK)
9859     xml_failure(g_parser);
9860 
9861   /* Check that resuming an unsuspended parser is faulted */
9862   if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
9863     fail("Resuming unsuspended parser not faulted");
9864   if (XML_GetErrorCode(g_parser) != XML_ERROR_NOT_SUSPENDED)
9865     xml_failure(g_parser);
9866 
9867   /* Get the parser into suspended state */
9868   XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
9869   resumable = XML_TRUE;
9870   buffer = XML_GetBuffer(g_parser, (int)strlen(text));
9871   if (buffer == NULL)
9872     fail("Could not acquire parse buffer");
9873   assert(buffer != NULL);
9874   memcpy(buffer, text, strlen(text));
9875   if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
9876       != XML_STATUS_SUSPENDED)
9877     xml_failure(g_parser);
9878   if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
9879     xml_failure(g_parser);
9880   if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
9881       != XML_STATUS_ERROR)
9882     fail("Suspended XML_ParseBuffer not faulted");
9883   if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
9884     xml_failure(g_parser);
9885   if (XML_GetBuffer(g_parser, (int)strlen(text)) != NULL)
9886     fail("Suspended XML_GetBuffer not faulted");
9887 
9888   /* Get it going again and complete the world */
9889   XML_SetCharacterDataHandler(g_parser, NULL);
9890   if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
9891     xml_failure(g_parser);
9892   if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
9893       != XML_STATUS_ERROR)
9894     fail("Post-finishing XML_ParseBuffer not faulted");
9895   if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
9896     xml_failure(g_parser);
9897   if (XML_GetBuffer(g_parser, (int)strlen(text)) != NULL)
9898     fail("Post-finishing XML_GetBuffer not faulted");
9899 }
9900 END_TEST
9901 
9902 /* Check handling of long prefix names (pool growth) */
9903 START_TEST(test_nsalloc_long_prefix) {
9904   const char *text
9905       = "<"
9906         /* 64 characters per line */
9907         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9908         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9909         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9910         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9911         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9912         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9913         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9914         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9915         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9916         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9917         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9918         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9919         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9920         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9921         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9922         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9923         ":foo xmlns:"
9924         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9925         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9926         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9927         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9928         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9929         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9930         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9931         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9932         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9933         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9934         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9935         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9936         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9937         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9938         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9939         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9940         "='http://example.org/'>"
9941         "</"
9942         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9943         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9944         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9945         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9946         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9947         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9948         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9949         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9950         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9951         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9952         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9953         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9954         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9955         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9956         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9957         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9958         ":foo>";
9959   int i;
9960   const int max_alloc_count = 40;
9961 
9962   for (i = 0; i < max_alloc_count; i++) {
9963     allocation_count = i;
9964     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9965         != XML_STATUS_ERROR)
9966       break;
9967     /* See comment in test_nsalloc_xmlns() */
9968     nsalloc_teardown();
9969     nsalloc_setup();
9970   }
9971   if (i == 0)
9972     fail("Parsing worked despite failing allocations");
9973   else if (i == max_alloc_count)
9974     fail("Parsing failed even at max allocation count");
9975 }
9976 END_TEST
9977 
9978 /* Check handling of long uri names (pool growth) */
9979 START_TEST(test_nsalloc_long_uri) {
9980   const char *text
9981       = "<foo:e xmlns:foo='http://example.org/"
9982         /* 64 characters per line */
9983         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9984         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9985         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9986         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9987         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9988         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9989         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9990         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9991         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9992         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9993         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9994         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9995         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9996         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9997         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9998         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9999         "' bar:a='12'\n"
10000         "xmlns:bar='http://example.org/"
10001         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10002         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10003         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10004         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10005         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10006         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10007         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10008         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10009         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10010         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10011         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10012         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10013         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10014         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10015         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10016         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
10017         "'>"
10018         "</foo:e>";
10019   int i;
10020   const int max_alloc_count = 40;
10021 
10022   for (i = 0; i < max_alloc_count; i++) {
10023     allocation_count = i;
10024     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10025         != XML_STATUS_ERROR)
10026       break;
10027     /* See comment in test_nsalloc_xmlns() */
10028     nsalloc_teardown();
10029     nsalloc_setup();
10030   }
10031   if (i == 0)
10032     fail("Parsing worked despite failing allocations");
10033   else if (i == max_alloc_count)
10034     fail("Parsing failed even at max allocation count");
10035 }
10036 END_TEST
10037 
10038 /* Test handling of long attribute names with prefixes */
10039 START_TEST(test_nsalloc_long_attr) {
10040   const char *text
10041       = "<foo:e xmlns:foo='http://example.org/' bar:"
10042         /* 64 characters per line */
10043         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10044         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10045         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10046         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10047         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10048         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10049         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10050         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10051         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10052         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10053         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10054         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10055         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10056         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10057         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10058         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10059         "='12'\n"
10060         "xmlns:bar='http://example.org/'>"
10061         "</foo:e>";
10062   int i;
10063   const int max_alloc_count = 40;
10064 
10065   for (i = 0; i < max_alloc_count; i++) {
10066     allocation_count = i;
10067     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10068         != XML_STATUS_ERROR)
10069       break;
10070     /* See comment in test_nsalloc_xmlns() */
10071     nsalloc_teardown();
10072     nsalloc_setup();
10073   }
10074   if (i == 0)
10075     fail("Parsing worked despite failing allocations");
10076   else if (i == max_alloc_count)
10077     fail("Parsing failed even at max allocation count");
10078 }
10079 END_TEST
10080 
10081 /* Test handling of an attribute name with a long namespace prefix */
10082 START_TEST(test_nsalloc_long_attr_prefix) {
10083   const char *text
10084       = "<foo:e xmlns:foo='http://example.org/' "
10085         /* 64 characters per line */
10086         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10087         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10088         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10089         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10090         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10091         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10092         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10093         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10094         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10095         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10096         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10097         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10098         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10099         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10100         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10101         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10102         ":a='12'\n"
10103         "xmlns:"
10104         /* 64 characters per line */
10105         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10106         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10107         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10108         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10109         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10110         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10111         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10112         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10113         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10114         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10115         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10116         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10117         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10118         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10119         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10120         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10121         "='http://example.org/'>"
10122         "</foo:e>";
10123   const XML_Char *elemstr[] = {
10124       /* clang-format off */
10125         XCS("http://example.org/ e foo"),
10126         XCS("http://example.org/ a ")
10127         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10128         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10129         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10130         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10131         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10132         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10133         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10134         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10135         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10136         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10137         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10138         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10139         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10140         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10141         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10142         XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10143       /* clang-format on */
10144   };
10145   int i;
10146   const int max_alloc_count = 40;
10147 
10148   for (i = 0; i < max_alloc_count; i++) {
10149     allocation_count = i;
10150     XML_SetReturnNSTriplet(g_parser, XML_TRUE);
10151     XML_SetUserData(g_parser, (void *)elemstr);
10152     XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
10153     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10154         != XML_STATUS_ERROR)
10155       break;
10156     /* See comment in test_nsalloc_xmlns() */
10157     nsalloc_teardown();
10158     nsalloc_setup();
10159   }
10160   if (i == 0)
10161     fail("Parsing worked despite failing allocations");
10162   else if (i == max_alloc_count)
10163     fail("Parsing failed even at max allocation count");
10164 }
10165 END_TEST
10166 
10167 /* Test attribute handling in the face of a dodgy reallocator */
10168 START_TEST(test_nsalloc_realloc_attributes) {
10169   const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
10170                      "       xmlns:bar='http://example.org/'>"
10171                      "</foo:e>";
10172   int i;
10173   const int max_realloc_count = 10;
10174 
10175   for (i = 0; i < max_realloc_count; i++) {
10176     reallocation_count = i;
10177     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10178         != XML_STATUS_ERROR)
10179       break;
10180     /* See comment in test_nsalloc_xmlns() */
10181     nsalloc_teardown();
10182     nsalloc_setup();
10183   }
10184   if (i == 0)
10185     fail("Parsing worked despite failing reallocations");
10186   else if (i == max_realloc_count)
10187     fail("Parsing failed at max reallocation count");
10188 }
10189 END_TEST
10190 
10191 /* Test long element names with namespaces under a failing allocator */
10192 START_TEST(test_nsalloc_long_element) {
10193   const char *text
10194       = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
10195         " xmlns:foo='http://example.org/' bar:a='12'\n"
10196         " xmlns:bar='http://example.org/'>"
10197         "</foo:thisisalongenoughelementnametotriggerareallocation>";
10198   const XML_Char *elemstr[]
10199       = {XCS("http://example.org/")
10200              XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
10201          XCS("http://example.org/ a bar")};
10202   int i;
10203   const int max_alloc_count = 30;
10204 
10205   for (i = 0; i < max_alloc_count; i++) {
10206     allocation_count = i;
10207     XML_SetReturnNSTriplet(g_parser, XML_TRUE);
10208     XML_SetUserData(g_parser, (void *)elemstr);
10209     XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
10210     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10211         != XML_STATUS_ERROR)
10212       break;
10213     /* See comment in test_nsalloc_xmlns() */
10214     nsalloc_teardown();
10215     nsalloc_setup();
10216   }
10217   if (i == 0)
10218     fail("Parsing worked despite failing reallocations");
10219   else if (i == max_alloc_count)
10220     fail("Parsing failed at max reallocation count");
10221 }
10222 END_TEST
10223 
10224 /* Test the effects of reallocation failure when reassigning a
10225  * binding.
10226  *
10227  * XML_ParserReset does not free the BINDING structures used by a
10228  * parser, but instead adds them to an internal free list to be reused
10229  * as necessary.  Likewise the URI buffers allocated for the binding
10230  * aren't freed, but kept attached to their existing binding.  If the
10231  * new binding has a longer URI, it will need reallocation.  This test
10232  * provokes that reallocation, and tests the control path if it fails.
10233  */
10234 START_TEST(test_nsalloc_realloc_binding_uri) {
10235   const char *first = "<doc xmlns='http://example.org/'>\n"
10236                       "  <e xmlns='' />\n"
10237                       "</doc>";
10238   const char *second
10239       = "<doc xmlns='http://example.org/long/enough/URI/to/reallocate/'>\n"
10240         "  <e xmlns='' />\n"
10241         "</doc>";
10242   unsigned i;
10243   const unsigned max_realloc_count = 10;
10244 
10245   /* First, do a full parse that will leave bindings around */
10246   if (_XML_Parse_SINGLE_BYTES(g_parser, first, (int)strlen(first), XML_TRUE)
10247       == XML_STATUS_ERROR)
10248     xml_failure(g_parser);
10249 
10250   /* Now repeat with a longer URI and a duff reallocator */
10251   for (i = 0; i < max_realloc_count; i++) {
10252     XML_ParserReset(g_parser, NULL);
10253     reallocation_count = i;
10254     if (_XML_Parse_SINGLE_BYTES(g_parser, second, (int)strlen(second), XML_TRUE)
10255         != XML_STATUS_ERROR)
10256       break;
10257   }
10258   if (i == 0)
10259     fail("Parsing worked despite failing reallocation");
10260   else if (i == max_realloc_count)
10261     fail("Parsing failed at max reallocation count");
10262 }
10263 END_TEST
10264 
10265 /* Check handling of long prefix names (pool growth) */
10266 START_TEST(test_nsalloc_realloc_long_prefix) {
10267   const char *text
10268       = "<"
10269         /* 64 characters per line */
10270         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10271         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10272         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10273         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10274         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10275         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10276         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10277         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10278         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10279         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10280         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10281         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10282         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10283         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10284         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10285         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10286         ":foo xmlns:"
10287         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10288         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10289         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10290         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10291         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10292         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10293         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10294         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10295         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10296         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10297         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10298         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10299         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10300         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10301         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10302         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10303         "='http://example.org/'>"
10304         "</"
10305         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10306         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10307         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10308         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10309         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10310         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10311         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10312         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10313         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10314         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10315         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10316         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10317         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10318         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10319         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10320         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10321         ":foo>";
10322   int i;
10323   const int max_realloc_count = 12;
10324 
10325   for (i = 0; i < max_realloc_count; i++) {
10326     reallocation_count = i;
10327     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10328         != XML_STATUS_ERROR)
10329       break;
10330     /* See comment in test_nsalloc_xmlns() */
10331     nsalloc_teardown();
10332     nsalloc_setup();
10333   }
10334   if (i == 0)
10335     fail("Parsing worked despite failing reallocations");
10336   else if (i == max_realloc_count)
10337     fail("Parsing failed even at max reallocation count");
10338 }
10339 END_TEST
10340 
10341 /* Check handling of even long prefix names (different code path) */
10342 START_TEST(test_nsalloc_realloc_longer_prefix) {
10343   const char *text
10344       = "<"
10345         /* 64 characters per line */
10346         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10347         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10348         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10349         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10350         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10351         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10352         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10353         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10354         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10355         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10356         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10357         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10358         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10359         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10360         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10361         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10362         "Q:foo xmlns:"
10363         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10364         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10365         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10366         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10367         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10368         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10369         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10370         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10371         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10372         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10373         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10374         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10375         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10376         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10377         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10378         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10379         "Q='http://example.org/'>"
10380         "</"
10381         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10382         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10383         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10384         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10385         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10386         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10387         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10388         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10389         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10390         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10391         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10392         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10393         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10394         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10395         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10396         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10397         "Q:foo>";
10398   int i;
10399   const int max_realloc_count = 12;
10400 
10401   for (i = 0; i < max_realloc_count; i++) {
10402     reallocation_count = i;
10403     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10404         != XML_STATUS_ERROR)
10405       break;
10406     /* See comment in test_nsalloc_xmlns() */
10407     nsalloc_teardown();
10408     nsalloc_setup();
10409   }
10410   if (i == 0)
10411     fail("Parsing worked despite failing reallocations");
10412   else if (i == max_realloc_count)
10413     fail("Parsing failed even at max reallocation count");
10414 }
10415 END_TEST
10416 
10417 START_TEST(test_nsalloc_long_namespace) {
10418   const char *text1
10419       = "<"
10420         /* 64 characters per line */
10421         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10422         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10423         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10424         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10425         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10426         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10427         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10428         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10429         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10430         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10431         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10432         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10433         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10434         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10435         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10436         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10437         ":e xmlns:"
10438         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10439         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10440         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10441         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10442         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10443         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10444         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10445         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10446         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10447         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10448         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10449         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10450         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10451         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10452         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10453         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10454         "='http://example.org/'>\n";
10455   const char *text2
10456       = "<"
10457         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10458         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10459         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10460         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10461         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10462         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10463         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10464         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10465         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10466         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10467         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10468         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10469         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10470         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10471         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10472         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10473         ":f "
10474         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10475         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10476         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10477         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10478         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10479         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10480         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10481         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10482         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10483         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10484         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10485         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10486         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10487         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10488         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10489         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10490         ":attr='foo'/>\n"
10491         "</"
10492         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10493         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10494         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10495         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10496         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10497         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10498         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10499         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10500         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10501         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10502         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10503         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10504         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10505         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10506         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10507         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10508         ":e>";
10509   int i;
10510   const int max_alloc_count = 40;
10511 
10512   for (i = 0; i < max_alloc_count; i++) {
10513     allocation_count = i;
10514     if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
10515             != XML_STATUS_ERROR
10516         && _XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2),
10517                                    XML_TRUE)
10518                != XML_STATUS_ERROR)
10519       break;
10520     /* See comment in test_nsalloc_xmlns() */
10521     nsalloc_teardown();
10522     nsalloc_setup();
10523   }
10524   if (i == 0)
10525     fail("Parsing worked despite failing allocations");
10526   else if (i == max_alloc_count)
10527     fail("Parsing failed even at max allocation count");
10528 }
10529 END_TEST
10530 
10531 /* Using a slightly shorter namespace name provokes allocations in
10532  * slightly different places in the code.
10533  */
10534 START_TEST(test_nsalloc_less_long_namespace) {
10535   const char *text
10536       = "<"
10537         /* 64 characters per line */
10538         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10539         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10540         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10541         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10542         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10543         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10544         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10545         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
10546         ":e xmlns:"
10547         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10548         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10549         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10550         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10551         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10552         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10553         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10554         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
10555         "='http://example.org/'>\n"
10556         "<"
10557         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10558         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10559         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10560         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10561         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10562         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10563         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10564         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
10565         ":f "
10566         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10567         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10568         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10569         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10570         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10571         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10572         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10573         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
10574         ":att='foo'/>\n"
10575         "</"
10576         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10577         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10578         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10579         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10580         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10581         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10582         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10583         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
10584         ":e>";
10585   int i;
10586   const int max_alloc_count = 40;
10587 
10588   for (i = 0; i < max_alloc_count; i++) {
10589     allocation_count = i;
10590     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10591         != XML_STATUS_ERROR)
10592       break;
10593     /* See comment in test_nsalloc_xmlns() */
10594     nsalloc_teardown();
10595     nsalloc_setup();
10596   }
10597   if (i == 0)
10598     fail("Parsing worked despite failing allocations");
10599   else if (i == max_alloc_count)
10600     fail("Parsing failed even at max allocation count");
10601 }
10602 END_TEST
10603 
10604 START_TEST(test_nsalloc_long_context) {
10605   const char *text
10606       = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10607         "  <!ATTLIST doc baz ID #REQUIRED>\n"
10608         "  <!ENTITY en SYSTEM 'bar'>\n"
10609         "]>\n"
10610         "<doc xmlns='http://example.org/"
10611         /* 64 characters per line */
10612         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10613         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10614         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10615         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10616         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10617         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10618         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10619         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10620         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10621         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10622         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10623         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10624         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10625         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10626         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10627         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKL"
10628         "' baz='2'>\n"
10629         "&en;"
10630         "</doc>";
10631   ExtOption options[] = {
10632       {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
10633   int i;
10634   const int max_alloc_count = 70;
10635 
10636   for (i = 0; i < max_alloc_count; i++) {
10637     allocation_count = i;
10638     XML_SetUserData(g_parser, options);
10639     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
10640     XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
10641     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10642         != XML_STATUS_ERROR)
10643       break;
10644 
10645     /* See comment in test_nsalloc_xmlns() */
10646     nsalloc_teardown();
10647     nsalloc_setup();
10648   }
10649   if (i == 0)
10650     fail("Parsing worked despite failing allocations");
10651   else if (i == max_alloc_count)
10652     fail("Parsing failed even at max allocation count");
10653 }
10654 END_TEST
10655 
10656 /* This function is void; it will throw a fail() on error, so if it
10657  * returns normally it must have succeeded.
10658  */
10659 static void
10660 context_realloc_test(const char *text) {
10661   ExtOption options[] = {
10662       {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
10663   int i;
10664   const int max_realloc_count = 6;
10665 
10666   for (i = 0; i < max_realloc_count; i++) {
10667     reallocation_count = i;
10668     XML_SetUserData(g_parser, options);
10669     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
10670     XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
10671     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10672         != XML_STATUS_ERROR)
10673       break;
10674     /* See comment in test_nsalloc_xmlns() */
10675     nsalloc_teardown();
10676     nsalloc_setup();
10677   }
10678   if (i == 0)
10679     fail("Parsing worked despite failing reallocations");
10680   else if (i == max_realloc_count)
10681     fail("Parsing failed even at max reallocation count");
10682 }
10683 
10684 START_TEST(test_nsalloc_realloc_long_context) {
10685   const char *text
10686       = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10687         "  <!ENTITY en SYSTEM 'bar'>\n"
10688         "]>\n"
10689         "<doc xmlns='http://example.org/"
10690         /* 64 characters per line */
10691         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10692         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10693         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10694         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10695         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10696         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10697         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10698         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10699         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10700         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10701         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10702         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10703         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10704         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10705         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10706         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKL"
10707         "'>\n"
10708         "&en;"
10709         "</doc>";
10710 
10711   context_realloc_test(text);
10712 }
10713 END_TEST
10714 
10715 START_TEST(test_nsalloc_realloc_long_context_2) {
10716   const char *text
10717       = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10718         "  <!ENTITY en SYSTEM 'bar'>\n"
10719         "]>\n"
10720         "<doc xmlns='http://example.org/"
10721         /* 64 characters per line */
10722         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10723         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10724         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10725         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10726         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10727         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10728         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10729         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10730         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10731         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10732         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10733         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10734         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10735         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10736         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10737         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJK"
10738         "'>\n"
10739         "&en;"
10740         "</doc>";
10741 
10742   context_realloc_test(text);
10743 }
10744 END_TEST
10745 
10746 START_TEST(test_nsalloc_realloc_long_context_3) {
10747   const char *text
10748       = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10749         "  <!ENTITY en SYSTEM 'bar'>\n"
10750         "]>\n"
10751         "<doc xmlns='http://example.org/"
10752         /* 64 characters per line */
10753         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10754         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10755         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10756         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10757         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10758         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10759         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10760         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10761         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10762         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10763         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10764         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10765         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10766         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10767         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10768         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGH"
10769         "'>\n"
10770         "&en;"
10771         "</doc>";
10772 
10773   context_realloc_test(text);
10774 }
10775 END_TEST
10776 
10777 START_TEST(test_nsalloc_realloc_long_context_4) {
10778   const char *text
10779       = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10780         "  <!ENTITY en SYSTEM 'bar'>\n"
10781         "]>\n"
10782         "<doc xmlns='http://example.org/"
10783         /* 64 characters per line */
10784         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10785         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10786         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10787         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10788         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10789         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10790         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10791         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10792         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10793         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10794         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10795         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10796         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10797         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10798         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10799         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO"
10800         "'>\n"
10801         "&en;"
10802         "</doc>";
10803 
10804   context_realloc_test(text);
10805 }
10806 END_TEST
10807 
10808 START_TEST(test_nsalloc_realloc_long_context_5) {
10809   const char *text
10810       = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10811         "  <!ENTITY en SYSTEM 'bar'>\n"
10812         "]>\n"
10813         "<doc xmlns='http://example.org/"
10814         /* 64 characters per line */
10815         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10816         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10817         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10818         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10819         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10820         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10821         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10822         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10823         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10824         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10825         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10826         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10827         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10828         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10829         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10830         "ABC"
10831         "'>\n"
10832         "&en;"
10833         "</doc>";
10834 
10835   context_realloc_test(text);
10836 }
10837 END_TEST
10838 
10839 START_TEST(test_nsalloc_realloc_long_context_6) {
10840   const char *text
10841       = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10842         "  <!ENTITY en SYSTEM 'bar'>\n"
10843         "]>\n"
10844         "<doc xmlns='http://example.org/"
10845         /* 64 characters per line */
10846         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10847         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10848         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10849         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10850         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10851         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10852         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10853         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10854         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10855         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10856         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10857         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10858         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10859         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10860         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
10861         "'>\n"
10862         "&en;"
10863         "</doc>";
10864 
10865   context_realloc_test(text);
10866 }
10867 END_TEST
10868 
10869 START_TEST(test_nsalloc_realloc_long_context_7) {
10870   const char *text
10871       = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10872         "  <!ENTITY en SYSTEM 'bar'>\n"
10873         "]>\n"
10874         "<doc xmlns='http://example.org/"
10875         /* 64 characters per line */
10876         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10877         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10878         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10879         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10880         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10881         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10882         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10883         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10884         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10885         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10886         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10887         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10888         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10889         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10890         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10891         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLM"
10892         "'>\n"
10893         "&en;"
10894         "</doc>";
10895 
10896   context_realloc_test(text);
10897 }
10898 END_TEST
10899 
10900 START_TEST(test_nsalloc_realloc_long_ge_name) {
10901   const char *text
10902       = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10903         "  <!ENTITY "
10904         /* 64 characters per line */
10905         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10906         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10907         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10908         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10909         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10910         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10911         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10912         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10913         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10914         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10915         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10916         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10917         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10918         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10919         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10920         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10921         " SYSTEM 'bar'>\n"
10922         "]>\n"
10923         "<doc xmlns='http://example.org/baz'>\n"
10924         "&"
10925         /* 64 characters per line */
10926         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10927         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10928         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10929         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10930         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10931         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10932         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10933         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10934         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10935         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10936         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10937         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10938         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10939         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10940         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10941         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10942         ";"
10943         "</doc>";
10944   ExtOption options[] = {
10945       {XCS("foo"), "<!ELEMENT el EMPTY>"}, {XCS("bar"), "<el/>"}, {NULL, NULL}};
10946   int i;
10947   const int max_realloc_count = 10;
10948 
10949   for (i = 0; i < max_realloc_count; i++) {
10950     reallocation_count = i;
10951     XML_SetUserData(g_parser, options);
10952     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
10953     XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
10954     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10955         != XML_STATUS_ERROR)
10956       break;
10957     /* See comment in test_nsalloc_xmlns() */
10958     nsalloc_teardown();
10959     nsalloc_setup();
10960   }
10961   if (i == 0)
10962     fail("Parsing worked despite failing reallocations");
10963   else if (i == max_realloc_count)
10964     fail("Parsing failed even at max reallocation count");
10965 }
10966 END_TEST
10967 
10968 /* Test that when a namespace is passed through the context mechanism
10969  * to an external entity parser, the parsers handle reallocation
10970  * failures correctly.  The prefix is exactly the right length to
10971  * provoke particular uncommon code paths.
10972  */
10973 START_TEST(test_nsalloc_realloc_long_context_in_dtd) {
10974   const char *text1
10975       = "<!DOCTYPE "
10976         /* 64 characters per line */
10977         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10978         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10979         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10980         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10981         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10982         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10983         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10984         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10985         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10986         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10987         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10988         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10989         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10990         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10991         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10992         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10993         ":doc [\n"
10994         "  <!ENTITY First SYSTEM 'foo/First'>\n"
10995         "]>\n"
10996         "<"
10997         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10998         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10999         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11000         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11001         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11002         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11003         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11004         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11005         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11006         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11007         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11008         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11009         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11010         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11011         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11012         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11013         ":doc xmlns:"
11014         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11015         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11016         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11017         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11018         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11019         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11020         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11021         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11022         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11023         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11024         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11025         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11026         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11027         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11028         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11029         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11030         "='foo/Second'>&First;";
11031   const char *text2
11032       = "</"
11033         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11034         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11035         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11036         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11037         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11038         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11039         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11040         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11041         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11042         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11043         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11044         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11045         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11046         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11047         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11048         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11049         ":doc>";
11050   ExtOption options[] = {{XCS("foo/First"), "Hello world"}, {NULL, NULL}};
11051   int i;
11052   const int max_realloc_count = 20;
11053 
11054   for (i = 0; i < max_realloc_count; i++) {
11055     reallocation_count = i;
11056     XML_SetUserData(g_parser, options);
11057     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
11058     XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
11059     if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
11060             != XML_STATUS_ERROR
11061         && _XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2),
11062                                    XML_TRUE)
11063                != XML_STATUS_ERROR)
11064       break;
11065     /* See comment in test_nsalloc_xmlns() */
11066     nsalloc_teardown();
11067     nsalloc_setup();
11068   }
11069   if (i == 0)
11070     fail("Parsing worked despite failing reallocations");
11071   else if (i == max_realloc_count)
11072     fail("Parsing failed even at max reallocation count");
11073 }
11074 END_TEST
11075 
11076 START_TEST(test_nsalloc_long_default_in_ext) {
11077   const char *text
11078       = "<!DOCTYPE doc [\n"
11079         "  <!ATTLIST e a1 CDATA '"
11080         /* 64 characters per line */
11081         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11082         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11083         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11084         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11085         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11086         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11087         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11088         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11089         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11090         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11091         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11092         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11093         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11094         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11095         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11096         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11097         "'>\n"
11098         "  <!ENTITY x SYSTEM 'foo'>\n"
11099         "]>\n"
11100         "<doc>&x;</doc>";
11101   ExtOption options[] = {{XCS("foo"), "<e/>"}, {NULL, NULL}};
11102   int i;
11103   const int max_alloc_count = 50;
11104 
11105   for (i = 0; i < max_alloc_count; i++) {
11106     allocation_count = i;
11107     XML_SetUserData(g_parser, options);
11108     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
11109     XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
11110     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
11111         != XML_STATUS_ERROR)
11112       break;
11113 
11114     /* See comment in test_nsalloc_xmlns() */
11115     nsalloc_teardown();
11116     nsalloc_setup();
11117   }
11118   if (i == 0)
11119     fail("Parsing worked despite failing allocations");
11120   else if (i == max_alloc_count)
11121     fail("Parsing failed even at max allocation count");
11122 }
11123 END_TEST
11124 
11125 START_TEST(test_nsalloc_long_systemid_in_ext) {
11126   const char *text
11127       = "<!DOCTYPE doc SYSTEM 'foo' [\n"
11128         "  <!ENTITY en SYSTEM '"
11129         /* 64 characters per line */
11130         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11131         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11132         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11133         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11134         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11135         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11136         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11137         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11138         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11139         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11140         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11141         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11142         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11143         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11144         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11145         "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11146         "'>\n"
11147         "]>\n"
11148         "<doc>&en;</doc>";
11149   ExtOption options[] = {
11150       {XCS("foo"), "<!ELEMENT e EMPTY>"},
11151       {/* clang-format off */
11152             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11153             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11154             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11155             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11156             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11157             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11158             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11159             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11160             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11161             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11162             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11163             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11164             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11165             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11166             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11167             XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"),
11168        /* clang-format on */
11169        "<e/>"},
11170       {NULL, NULL}};
11171   int i;
11172   const int max_alloc_count = 55;
11173 
11174   for (i = 0; i < max_alloc_count; i++) {
11175     allocation_count = i;
11176     XML_SetUserData(g_parser, options);
11177     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
11178     XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
11179     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
11180         != XML_STATUS_ERROR)
11181       break;
11182 
11183     /* See comment in test_nsalloc_xmlns() */
11184     nsalloc_teardown();
11185     nsalloc_setup();
11186   }
11187   if (i == 0)
11188     fail("Parsing worked despite failing allocations");
11189   else if (i == max_alloc_count)
11190     fail("Parsing failed even at max allocation count");
11191 }
11192 END_TEST
11193 
11194 /* Test the effects of allocation failure on parsing an element in a
11195  * namespace.  Based on test_nsalloc_long_context.
11196  */
11197 START_TEST(test_nsalloc_prefixed_element) {
11198   const char *text = "<!DOCTYPE pfx:element SYSTEM 'foo' [\n"
11199                      "  <!ATTLIST pfx:element baz ID #REQUIRED>\n"
11200                      "  <!ENTITY en SYSTEM 'bar'>\n"
11201                      "]>\n"
11202                      "<pfx:element xmlns:pfx='http://example.org/' baz='2'>\n"
11203                      "&en;"
11204                      "</pfx:element>";
11205   ExtOption options[] = {
11206       {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
11207   int i;
11208   const int max_alloc_count = 70;
11209 
11210   for (i = 0; i < max_alloc_count; i++) {
11211     allocation_count = i;
11212     XML_SetUserData(g_parser, options);
11213     XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
11214     XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
11215     if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
11216         != XML_STATUS_ERROR)
11217       break;
11218 
11219     /* See comment in test_nsalloc_xmlns() */
11220     nsalloc_teardown();
11221     nsalloc_setup();
11222   }
11223   if (i == 0)
11224     fail("Success despite failing allocator");
11225   else if (i == max_alloc_count)
11226     fail("Failed even at full allocation count");
11227 }
11228 END_TEST
11229 
11230 #if defined(XML_DTD)
11231 typedef enum XML_Status (*XmlParseFunction)(XML_Parser, const char *, int, int);
11232 
11233 struct AccountingTestCase {
11234   const char *primaryText;
11235   const char *firstExternalText;  /* often NULL */
11236   const char *secondExternalText; /* often NULL */
11237   const unsigned long long expectedCountBytesIndirectExtra;
11238   XML_Bool singleBytesWanted;
11239 };
11240 
11241 static int
11242 accounting_external_entity_ref_handler(XML_Parser parser,
11243                                        const XML_Char *context,
11244                                        const XML_Char *base,
11245                                        const XML_Char *systemId,
11246                                        const XML_Char *publicId) {
11247   UNUSED_P(context);
11248   UNUSED_P(base);
11249   UNUSED_P(publicId);
11250 
11251   const struct AccountingTestCase *const testCase
11252       = (const struct AccountingTestCase *)XML_GetUserData(parser);
11253 
11254   const char *externalText = NULL;
11255   if (xcstrcmp(systemId, XCS("first.ent")) == 0) {
11256     externalText = testCase->firstExternalText;
11257   } else if (xcstrcmp(systemId, XCS("second.ent")) == 0) {
11258     externalText = testCase->secondExternalText;
11259   } else {
11260     assert(! "systemId is neither \"first.ent\" nor \"second.ent\"");
11261   }
11262   assert(externalText);
11263 
11264   XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
11265   assert(entParser);
11266 
11267   const XmlParseFunction xmlParseFunction
11268       = testCase->singleBytesWanted ? _XML_Parse_SINGLE_BYTES : XML_Parse;
11269 
11270   const enum XML_Status status = xmlParseFunction(
11271       entParser, externalText, (int)strlen(externalText), XML_TRUE);
11272 
11273   XML_ParserFree(entParser);
11274   return status;
11275 }
11276 
11277 START_TEST(test_accounting_precision) {
11278   const XML_Bool filled_later = XML_TRUE; /* value is arbitrary */
11279   struct AccountingTestCase cases[] = {
11280       {"<e/>", NULL, NULL, 0, 0},
11281       {"<e></e>", NULL, NULL, 0, 0},
11282 
11283       /* Attributes */
11284       {"<e k1=\"v2\" k2=\"v2\"/>", NULL, NULL, 0, filled_later},
11285       {"<e k1=\"v2\" k2=\"v2\"></e>", NULL, NULL, 0, 0},
11286       {"<p:e xmlns:p=\"https://domain.invalid/\" />", NULL, NULL, 0,
11287        filled_later},
11288       {"<e k=\"&amp;&apos;&gt;&lt;&quot;\" />", NULL, NULL,
11289        sizeof(XML_Char) * 5 /* number of predefined entites */, filled_later},
11290       {"<e1 xmlns='https://example.org/'>\n"
11291        "  <e2 xmlns=''/>\n"
11292        "</e1>",
11293        NULL, NULL, 0, filled_later},
11294 
11295       /* Text */
11296       {"<e>text</e>", NULL, NULL, 0, filled_later},
11297       {"<e1><e2>text1<e3/>text2</e2></e1>", NULL, NULL, 0, filled_later},
11298       {"<e>&amp;&apos;&gt;&lt;&quot;</e>", NULL, NULL,
11299        sizeof(XML_Char) * 5 /* number of predefined entites */, filled_later},
11300       {"<e>&#65;&#41;</e>", NULL, NULL, 0, filled_later},
11301 
11302       /* Prolog */
11303       {"<?xml version=\"1.0\"?><root/>", NULL, NULL, 0, filled_later},
11304 
11305       /* Whitespace */
11306       {"  <e1>  <e2>  </e2>  </e1>  ", NULL, NULL, 0, filled_later},
11307       {"<e1  ><e2  /></e1  >", NULL, NULL, 0, filled_later},
11308       {"<e1><e2 k = \"v\"/><e3 k = 'v'/></e1>", NULL, NULL, 0, filled_later},
11309 
11310       /* Comments */
11311       {"<!-- Comment --><e><!-- Comment --></e>", NULL, NULL, 0, filled_later},
11312 
11313       /* Processing instructions */
11314       {"<?xml-stylesheet type=\"text/xsl\" href=\"https://domain.invalid/\" media=\"all\"?><e/>",
11315        NULL, NULL, 0, filled_later},
11316       {"<?pi0?><?pi1 ?><?pi2  ?><!DOCTYPE r SYSTEM 'first.ent'><r/>",
11317        "<?pi3?><!ENTITY % e1 SYSTEM 'second.ent'><?pi4?>%e1;<?pi5?>", "<?pi6?>",
11318        0, filled_later},
11319 
11320       /* CDATA */
11321       {"<e><![CDATA[one two three]]></e>", NULL, NULL, 0, filled_later},
11322       /* The following is the essence of this OSS-Fuzz finding:
11323          https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=34302
11324          https://oss-fuzz.com/testcase-detail/4860575394955264
11325       */
11326       {"<!DOCTYPE r [\n"
11327        "<!ENTITY e \"111<![CDATA[2 <= 2]]>333\">\n"
11328        "]>\n"
11329        "<r>&e;</r>\n",
11330        NULL, NULL, sizeof(XML_Char) * strlen("111<![CDATA[2 <= 2]]>333"),
11331        filled_later},
11332 
11333       /* Conditional sections */
11334       {"<!DOCTYPE r [\n"
11335        "<!ENTITY % draft 'INCLUDE'>\n"
11336        "<!ENTITY % final 'IGNORE'>\n"
11337        "<!ENTITY % import SYSTEM \"first.ent\">\n"
11338        "%import;\n"
11339        "]>\n"
11340        "<r/>\n",
11341        "<![%draft;[<!--1-->]]>\n"
11342        "<![%final;[<!--22-->]]>",
11343        NULL, sizeof(XML_Char) * (strlen("INCLUDE") + strlen("IGNORE")),
11344        filled_later},
11345 
11346       /* General entities */
11347       {"<!DOCTYPE root [\n"
11348        "<!ENTITY nine \"123456789\">\n"
11349        "]>\n"
11350        "<root>&nine;</root>",
11351        NULL, NULL, sizeof(XML_Char) * strlen("123456789"), filled_later},
11352       {"<!DOCTYPE root [\n"
11353        "<!ENTITY nine \"123456789\">\n"
11354        "]>\n"
11355        "<root k1=\"&nine;\"/>",
11356        NULL, NULL, sizeof(XML_Char) * strlen("123456789"), filled_later},
11357       {"<!DOCTYPE root [\n"
11358        "<!ENTITY nine \"123456789\">\n"
11359        "<!ENTITY nine2 \"&nine;&nine;\">\n"
11360        "]>\n"
11361        "<root>&nine2;&nine2;&nine2;</root>",
11362        NULL, NULL,
11363        sizeof(XML_Char) * 3 /* calls to &nine2; */ * 2 /* calls to &nine; */
11364            * (strlen("&nine;") + strlen("123456789")),
11365        filled_later},
11366       {"<!DOCTYPE r [\n"
11367        "  <!ENTITY five SYSTEM 'first.ent'>\n"
11368        "]>\n"
11369        "<r>&five;</r>",
11370        "12345", NULL, 0, filled_later},
11371 
11372       /* Parameter entities */
11373       {"<!DOCTYPE r [\n"
11374        "<!ENTITY % comment \"<!---->\">\n"
11375        "%comment;\n"
11376        "]>\n"
11377        "<r/>",
11378        NULL, NULL, sizeof(XML_Char) * strlen("<!---->"), filled_later},
11379       {"<!DOCTYPE r [\n"
11380        "<!ENTITY % ninedef \"&#60;!ENTITY nine &#34;123456789&#34;&#62;\">\n"
11381        "%ninedef;\n"
11382        "]>\n"
11383        "<r>&nine;</r>",
11384        NULL, NULL,
11385        sizeof(XML_Char)
11386            * (strlen("<!ENTITY nine \"123456789\">") + strlen("123456789")),
11387        filled_later},
11388       {"<!DOCTYPE r [\n"
11389        "<!ENTITY % comment \"<!--1-->\">\n"
11390        "<!ENTITY % comment2 \"&#37;comment;<!--22-->&#37;comment;\">\n"
11391        "%comment2;\n"
11392        "]>\n"
11393        "<r/>\n",
11394        NULL, NULL,
11395        sizeof(XML_Char)
11396            * (strlen("%comment;<!--22-->%comment;") + 2 * strlen("<!--1-->")),
11397        filled_later},
11398       {"<!DOCTYPE r [\n"
11399        "  <!ENTITY % five \"12345\">\n"
11400        "  <!ENTITY % five2def \"&#60;!ENTITY five2 &#34;[&#37;five;][&#37;five;]]]]&#34;&#62;\">\n"
11401        "  %five2def;\n"
11402        "]>\n"
11403        "<r>&five2;</r>",
11404        NULL, NULL, /* from "%five2def;": */
11405        sizeof(XML_Char)
11406            * (strlen("<!ENTITY five2 \"[%five;][%five;]]]]\">")
11407               + 2 /* calls to "%five;" */ * strlen("12345")
11408               + /* from "&five2;": */ strlen("[12345][12345]]]]")),
11409        filled_later},
11410       {"<!DOCTYPE r SYSTEM \"first.ent\">\n"
11411        "<r/>",
11412        "<!ENTITY % comment '<!--1-->'>\n"
11413        "<!ENTITY % comment2 '<!--22-->%comment;<!--22-->%comment;<!--22-->'>\n"
11414        "%comment2;",
11415        NULL,
11416        sizeof(XML_Char)
11417            * (strlen("<!--22-->%comment;<!--22-->%comment;<!--22-->")
11418               + 2 /* calls to "%comment;" */ * strlen("<!---->")),
11419        filled_later},
11420       {"<!DOCTYPE r SYSTEM 'first.ent'>\n"
11421        "<r/>",
11422        "<!ENTITY % e1 PUBLIC 'foo' 'second.ent'>\n"
11423        "<!ENTITY % e2 '<!--22-->%e1;<!--22-->'>\n"
11424        "%e2;\n",
11425        "<!--1-->", sizeof(XML_Char) * strlen("<!--22--><!--1--><!--22-->"),
11426        filled_later},
11427       {
11428           "<!DOCTYPE r SYSTEM 'first.ent'>\n"
11429           "<r/>",
11430           "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
11431           "<!ENTITY % e2 '%e1;'>",
11432           "<?xml version='1.0' encoding='utf-8'?>\n"
11433           "hello\n"
11434           "xml" /* without trailing newline! */,
11435           0,
11436           filled_later,
11437       },
11438       {
11439           "<!DOCTYPE r SYSTEM 'first.ent'>\n"
11440           "<r/>",
11441           "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
11442           "<!ENTITY % e2 '%e1;'>",
11443           "<?xml version='1.0' encoding='utf-8'?>\n"
11444           "hello\n"
11445           "xml\n" /* with trailing newline! */,
11446           0,
11447           filled_later,
11448       },
11449       {"<!DOCTYPE doc SYSTEM 'first.ent'>\n"
11450        "<doc></doc>\n",
11451        "<!ELEMENT doc EMPTY>\n"
11452        "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
11453        "<!ENTITY % e2 '%e1;'>\n"
11454        "%e1;\n",
11455        "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>" /* UTF-8 BOM */,
11456        strlen("\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>"), filled_later},
11457       {"<!DOCTYPE r [\n"
11458        "  <!ENTITY five SYSTEM 'first.ent'>\n"
11459        "]>\n"
11460        "<r>&five;</r>",
11461        "\xEF\xBB\xBF" /* UTF-8 BOM */, NULL, 0, filled_later},
11462   };
11463 
11464   const size_t countCases = sizeof(cases) / sizeof(cases[0]);
11465   size_t u = 0;
11466   for (; u < countCases; u++) {
11467     size_t v = 0;
11468     for (; v < 2; v++) {
11469       const XML_Bool singleBytesWanted = (v == 0) ? XML_FALSE : XML_TRUE;
11470       const unsigned long long expectedCountBytesDirect
11471           = strlen(cases[u].primaryText);
11472       const unsigned long long expectedCountBytesIndirect
11473           = (cases[u].firstExternalText ? strlen(cases[u].firstExternalText)
11474                                         : 0)
11475             + (cases[u].secondExternalText ? strlen(cases[u].secondExternalText)
11476                                            : 0)
11477             + cases[u].expectedCountBytesIndirectExtra;
11478 
11479       XML_Parser parser = XML_ParserCreate(NULL);
11480       XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
11481       if (cases[u].firstExternalText) {
11482         XML_SetExternalEntityRefHandler(parser,
11483                                         accounting_external_entity_ref_handler);
11484         XML_SetUserData(parser, (void *)&cases[u]);
11485         cases[u].singleBytesWanted = singleBytesWanted;
11486       }
11487 
11488       const XmlParseFunction xmlParseFunction
11489           = singleBytesWanted ? _XML_Parse_SINGLE_BYTES : XML_Parse;
11490 
11491       enum XML_Status status
11492           = xmlParseFunction(parser, cases[u].primaryText,
11493                              (int)strlen(cases[u].primaryText), XML_TRUE);
11494       if (status != XML_STATUS_OK) {
11495         _xml_failure(parser, __FILE__, __LINE__);
11496       }
11497 
11498       const unsigned long long actualCountBytesDirect
11499           = testingAccountingGetCountBytesDirect(parser);
11500       const unsigned long long actualCountBytesIndirect
11501           = testingAccountingGetCountBytesIndirect(parser);
11502 
11503       XML_ParserFree(parser);
11504 
11505       if (actualCountBytesDirect != expectedCountBytesDirect) {
11506         fprintf(
11507             stderr,
11508             "Document " EXPAT_FMT_SIZE_T("") " of " EXPAT_FMT_SIZE_T("") ", %s: Expected " EXPAT_FMT_ULL(
11509                 "") " count direct bytes, got " EXPAT_FMT_ULL("") " instead.\n",
11510             u + 1, countCases, singleBytesWanted ? "single bytes" : "chunks",
11511             expectedCountBytesDirect, actualCountBytesDirect);
11512         fail("Count of direct bytes is off");
11513       }
11514 
11515       if (actualCountBytesIndirect != expectedCountBytesIndirect) {
11516         fprintf(
11517             stderr,
11518             "Document " EXPAT_FMT_SIZE_T("") " of " EXPAT_FMT_SIZE_T("") ", %s: Expected " EXPAT_FMT_ULL(
11519                 "") " count indirect bytes, got " EXPAT_FMT_ULL("") " instead.\n",
11520             u + 1, countCases, singleBytesWanted ? "single bytes" : "chunks",
11521             expectedCountBytesIndirect, actualCountBytesIndirect);
11522         fail("Count of indirect bytes is off");
11523       }
11524     }
11525   }
11526 }
11527 END_TEST
11528 
11529 START_TEST(test_billion_laughs_attack_protection_api) {
11530   XML_Parser parserWithoutParent = XML_ParserCreate(NULL);
11531   XML_Parser parserWithParent
11532       = XML_ExternalEntityParserCreate(parserWithoutParent, NULL, NULL);
11533   if (parserWithoutParent == NULL)
11534     fail("parserWithoutParent is NULL");
11535   if (parserWithParent == NULL)
11536     fail("parserWithParent is NULL");
11537 
11538   // XML_SetBillionLaughsAttackProtectionMaximumAmplification, error cases
11539   if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(NULL, 123.0f)
11540       == XML_TRUE)
11541     fail("Call with NULL parser is NOT supposed to succeed");
11542   if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(parserWithParent,
11543                                                                123.0f)
11544       == XML_TRUE)
11545     fail("Call with non-root parser is NOT supposed to succeed");
11546   if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
11547           parserWithoutParent, NAN)
11548       == XML_TRUE)
11549     fail("Call with NaN limit is NOT supposed to succeed");
11550   if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
11551           parserWithoutParent, -1.0f)
11552       == XML_TRUE)
11553     fail("Call with negative limit is NOT supposed to succeed");
11554   if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
11555           parserWithoutParent, 0.9f)
11556       == XML_TRUE)
11557     fail("Call with positive limit <1.0 is NOT supposed to succeed");
11558 
11559   // XML_SetBillionLaughsAttackProtectionMaximumAmplification, success cases
11560   if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
11561           parserWithoutParent, 1.0f)
11562       == XML_FALSE)
11563     fail("Call with positive limit >=1.0 is supposed to succeed");
11564   if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
11565           parserWithoutParent, 123456.789f)
11566       == XML_FALSE)
11567     fail("Call with positive limit >=1.0 is supposed to succeed");
11568   if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
11569           parserWithoutParent, INFINITY)
11570       == XML_FALSE)
11571     fail("Call with positive limit >=1.0 is supposed to succeed");
11572 
11573   // XML_SetBillionLaughsAttackProtectionActivationThreshold, error cases
11574   if (XML_SetBillionLaughsAttackProtectionActivationThreshold(NULL, 123)
11575       == XML_TRUE)
11576     fail("Call with NULL parser is NOT supposed to succeed");
11577   if (XML_SetBillionLaughsAttackProtectionActivationThreshold(parserWithParent,
11578                                                               123)
11579       == XML_TRUE)
11580     fail("Call with non-root parser is NOT supposed to succeed");
11581 
11582   // XML_SetBillionLaughsAttackProtectionActivationThreshold, success cases
11583   if (XML_SetBillionLaughsAttackProtectionActivationThreshold(
11584           parserWithoutParent, 123)
11585       == XML_FALSE)
11586     fail("Call with non-NULL parentless parser is supposed to succeed");
11587 
11588   XML_ParserFree(parserWithParent);
11589   XML_ParserFree(parserWithoutParent);
11590 }
11591 END_TEST
11592 
11593 START_TEST(test_helper_unsigned_char_to_printable) {
11594   // Smoke test
11595   unsigned char uc = 0;
11596   for (; uc < (unsigned char)-1; uc++) {
11597     const char *const printable = unsignedCharToPrintable(uc);
11598     if (printable == NULL)
11599       fail("unsignedCharToPrintable returned NULL");
11600     if (strlen(printable) < (size_t)1)
11601       fail("unsignedCharToPrintable returned empty string");
11602   }
11603 
11604   // Two concrete samples
11605   if (strcmp(unsignedCharToPrintable('A'), "A") != 0)
11606     fail("unsignedCharToPrintable result mistaken");
11607   if (strcmp(unsignedCharToPrintable('\\'), "\\\\") != 0)
11608     fail("unsignedCharToPrintable result mistaken");
11609 }
11610 END_TEST
11611 #endif // defined(XML_DTD)
11612 
11613 static Suite *
11614 make_suite(void) {
11615   Suite *s = suite_create("basic");
11616   TCase *tc_basic = tcase_create("basic tests");
11617   TCase *tc_namespace = tcase_create("XML namespaces");
11618   TCase *tc_misc = tcase_create("miscellaneous tests");
11619   TCase *tc_alloc = tcase_create("allocation tests");
11620   TCase *tc_nsalloc = tcase_create("namespace allocation tests");
11621 #if defined(XML_DTD)
11622   TCase *tc_accounting = tcase_create("accounting tests");
11623 #endif
11624 
11625   suite_add_tcase(s, tc_basic);
11626   tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
11627   tcase_add_test(tc_basic, test_nul_byte);
11628   tcase_add_test(tc_basic, test_u0000_char);
11629   tcase_add_test(tc_basic, test_siphash_self);
11630   tcase_add_test(tc_basic, test_siphash_spec);
11631   tcase_add_test(tc_basic, test_bom_utf8);
11632   tcase_add_test(tc_basic, test_bom_utf16_be);
11633   tcase_add_test(tc_basic, test_bom_utf16_le);
11634   tcase_add_test(tc_basic, test_nobom_utf16_le);
11635   tcase_add_test(tc_basic, test_illegal_utf8);
11636   tcase_add_test(tc_basic, test_utf8_auto_align);
11637   tcase_add_test(tc_basic, test_utf16);
11638   tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
11639   tcase_add_test(tc_basic, test_not_utf16);
11640   tcase_add_test(tc_basic, test_bad_encoding);
11641   tcase_add_test(tc_basic, test_latin1_umlauts);
11642   tcase_add_test(tc_basic, test_long_utf8_character);
11643   tcase_add_test(tc_basic, test_long_latin1_attribute);
11644   tcase_add_test(tc_basic, test_long_ascii_attribute);
11645   /* Regression test for SF bug #491986. */
11646   tcase_add_test(tc_basic, test_danish_latin1);
11647   /* Regression test for SF bug #514281. */
11648   tcase_add_test(tc_basic, test_french_charref_hexidecimal);
11649   tcase_add_test(tc_basic, test_french_charref_decimal);
11650   tcase_add_test(tc_basic, test_french_latin1);
11651   tcase_add_test(tc_basic, test_french_utf8);
11652   tcase_add_test(tc_basic, test_utf8_false_rejection);
11653   tcase_add_test(tc_basic, test_line_number_after_parse);
11654   tcase_add_test(tc_basic, test_column_number_after_parse);
11655   tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers);
11656   tcase_add_test(tc_basic, test_line_number_after_error);
11657   tcase_add_test(tc_basic, test_column_number_after_error);
11658   tcase_add_test(tc_basic, test_really_long_lines);
11659   tcase_add_test(tc_basic, test_really_long_encoded_lines);
11660   tcase_add_test(tc_basic, test_end_element_events);
11661   tcase_add_test(tc_basic, test_attr_whitespace_normalization);
11662   tcase_add_test(tc_basic, test_xmldecl_misplaced);
11663   tcase_add_test(tc_basic, test_xmldecl_invalid);
11664   tcase_add_test(tc_basic, test_xmldecl_missing_attr);
11665   tcase_add_test(tc_basic, test_xmldecl_missing_value);
11666   tcase_add_test(tc_basic, test_unknown_encoding_internal_entity);
11667   tcase_add_test(tc_basic, test_unrecognised_encoding_internal_entity);
11668   tcase_add_test(tc_basic, test_wfc_undeclared_entity_unread_external_subset);
11669   tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
11670   tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
11671   tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
11672   tcase_add_test(tc_basic, test_not_standalone_handler_reject);
11673   tcase_add_test(tc_basic, test_not_standalone_handler_accept);
11674   tcase_add_test(tc_basic,
11675                  test_wfc_undeclared_entity_with_external_subset_standalone);
11676   tcase_add_test(tc_basic, test_entity_with_external_subset_unless_standalone);
11677   tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs);
11678   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_encoding);
11679   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_no_handler);
11680   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_bom);
11681   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_bad_encoding);
11682   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_bad_encoding_2);
11683   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_invalid_parse);
11684   tcase_add_test__ifdef_xml_dtd(tc_basic,
11685                                 test_ext_entity_invalid_suspended_parse);
11686   tcase_add_test(tc_basic, test_dtd_default_handling);
11687   tcase_add_test(tc_basic, test_dtd_attr_handling);
11688   tcase_add_test(tc_basic, test_empty_ns_without_namespaces);
11689   tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces);
11690   tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls);
11691   tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls);
11692   tcase_add_test(tc_basic, test_repeated_stop_parser_between_char_data_calls);
11693   tcase_add_test(tc_basic, test_good_cdata_ascii);
11694   tcase_add_test(tc_basic, test_good_cdata_utf16);
11695   tcase_add_test(tc_basic, test_good_cdata_utf16_le);
11696   tcase_add_test(tc_basic, test_long_cdata_utf16);
11697   tcase_add_test(tc_basic, test_multichar_cdata_utf16);
11698   tcase_add_test(tc_basic, test_utf16_bad_surrogate_pair);
11699   tcase_add_test(tc_basic, test_bad_cdata);
11700   tcase_add_test(tc_basic, test_bad_cdata_utf16);
11701   tcase_add_test(tc_basic, test_stop_parser_between_cdata_calls);
11702   tcase_add_test(tc_basic, test_suspend_parser_between_cdata_calls);
11703   tcase_add_test(tc_basic, test_memory_allocation);
11704   tcase_add_test(tc_basic, test_default_current);
11705   tcase_add_test(tc_basic, test_dtd_elements);
11706   tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd);
11707   tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_not_standalone);
11708   tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_foreign_dtd);
11709   tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_with_doctype);
11710   tcase_add_test__ifdef_xml_dtd(tc_basic,
11711                                 test_foreign_dtd_without_external_subset);
11712   tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_foreign_dtd);
11713   tcase_add_test(tc_basic, test_set_base);
11714   tcase_add_test(tc_basic, test_attributes);
11715   tcase_add_test(tc_basic, test_reset_in_entity);
11716   tcase_add_test(tc_basic, test_resume_invalid_parse);
11717   tcase_add_test(tc_basic, test_resume_resuspended);
11718   tcase_add_test(tc_basic, test_cdata_default);
11719   tcase_add_test(tc_basic, test_subordinate_reset);
11720   tcase_add_test(tc_basic, test_subordinate_suspend);
11721   tcase_add_test(tc_basic, test_subordinate_xdecl_suspend);
11722   tcase_add_test(tc_basic, test_subordinate_xdecl_abort);
11723   tcase_add_test(tc_basic, test_explicit_encoding);
11724   tcase_add_test(tc_basic, test_trailing_cr);
11725   tcase_add_test(tc_basic, test_ext_entity_trailing_cr);
11726   tcase_add_test(tc_basic, test_trailing_rsqb);
11727   tcase_add_test(tc_basic, test_ext_entity_trailing_rsqb);
11728   tcase_add_test(tc_basic, test_ext_entity_good_cdata);
11729   tcase_add_test__ifdef_xml_dtd(tc_basic, test_user_parameters);
11730   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_ref_parameter);
11731   tcase_add_test(tc_basic, test_empty_parse);
11732   tcase_add_test(tc_basic, test_get_buffer_1);
11733   tcase_add_test(tc_basic, test_get_buffer_2);
11734   tcase_add_test(tc_basic, test_byte_info_at_end);
11735   tcase_add_test(tc_basic, test_byte_info_at_error);
11736   tcase_add_test(tc_basic, test_byte_info_at_cdata);
11737   tcase_add_test(tc_basic, test_predefined_entities);
11738   tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_tag_in_dtd);
11739   tcase_add_test(tc_basic, test_not_predefined_entities);
11740   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section);
11741   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section_utf16);
11742   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section_utf16_be);
11743   tcase_add_test__ifdef_xml_dtd(tc_basic, test_bad_ignore_section);
11744   tcase_add_test__ifdef_xml_dtd(tc_basic, test_external_entity_values);
11745   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_not_standalone);
11746   tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_value_abort);
11747   tcase_add_test(tc_basic, test_bad_public_doctype);
11748   tcase_add_test(tc_basic, test_attribute_enum_value);
11749   tcase_add_test(tc_basic, test_predefined_entity_redefinition);
11750   tcase_add_test__ifdef_xml_dtd(tc_basic, test_dtd_stop_processing);
11751   tcase_add_test(tc_basic, test_public_notation_no_sysid);
11752   tcase_add_test(tc_basic, test_nested_groups);
11753   tcase_add_test(tc_basic, test_group_choice);
11754   tcase_add_test(tc_basic, test_standalone_parameter_entity);
11755   tcase_add_test__ifdef_xml_dtd(tc_basic, test_skipped_parameter_entity);
11756   tcase_add_test__ifdef_xml_dtd(tc_basic,
11757                                 test_recursive_external_parameter_entity);
11758   tcase_add_test(tc_basic, test_undefined_ext_entity_in_external_dtd);
11759   tcase_add_test(tc_basic, test_suspend_xdecl);
11760   tcase_add_test(tc_basic, test_abort_epilog);
11761   tcase_add_test(tc_basic, test_abort_epilog_2);
11762   tcase_add_test(tc_basic, test_suspend_epilog);
11763   tcase_add_test(tc_basic, test_suspend_in_sole_empty_tag);
11764   tcase_add_test(tc_basic, test_unfinished_epilog);
11765   tcase_add_test(tc_basic, test_partial_char_in_epilog);
11766   tcase_add_test(tc_basic, test_hash_collision);
11767   tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_internal_entity);
11768   tcase_add_test__ifdef_xml_dtd(tc_basic, test_resume_entity_with_syntax_error);
11769   tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_parameter_entity);
11770   tcase_add_test(tc_basic, test_restart_on_error);
11771   tcase_add_test(tc_basic, test_reject_lt_in_attribute_value);
11772   tcase_add_test(tc_basic, test_reject_unfinished_param_in_att_value);
11773   tcase_add_test(tc_basic, test_trailing_cr_in_att_value);
11774   tcase_add_test(tc_basic, test_standalone_internal_entity);
11775   tcase_add_test(tc_basic, test_skipped_external_entity);
11776   tcase_add_test(tc_basic, test_skipped_null_loaded_ext_entity);
11777   tcase_add_test(tc_basic, test_skipped_unloaded_ext_entity);
11778   tcase_add_test__ifdef_xml_dtd(tc_basic, test_param_entity_with_trailing_cr);
11779   tcase_add_test(tc_basic, test_invalid_character_entity);
11780   tcase_add_test(tc_basic, test_invalid_character_entity_2);
11781   tcase_add_test(tc_basic, test_invalid_character_entity_3);
11782   tcase_add_test(tc_basic, test_invalid_character_entity_4);
11783   tcase_add_test(tc_basic, test_pi_handled_in_default);
11784   tcase_add_test(tc_basic, test_comment_handled_in_default);
11785   tcase_add_test(tc_basic, test_pi_yml);
11786   tcase_add_test(tc_basic, test_pi_xnl);
11787   tcase_add_test(tc_basic, test_pi_xmm);
11788   tcase_add_test(tc_basic, test_utf16_pi);
11789   tcase_add_test(tc_basic, test_utf16_be_pi);
11790   tcase_add_test(tc_basic, test_utf16_be_comment);
11791   tcase_add_test(tc_basic, test_utf16_le_comment);
11792   tcase_add_test(tc_basic, test_missing_encoding_conversion_fn);
11793   tcase_add_test(tc_basic, test_failing_encoding_conversion_fn);
11794   tcase_add_test(tc_basic, test_unknown_encoding_success);
11795   tcase_add_test(tc_basic, test_unknown_encoding_bad_name);
11796   tcase_add_test(tc_basic, test_unknown_encoding_bad_name_2);
11797   tcase_add_test(tc_basic, test_unknown_encoding_long_name_1);
11798   tcase_add_test(tc_basic, test_unknown_encoding_long_name_2);
11799   tcase_add_test(tc_basic, test_invalid_unknown_encoding);
11800   tcase_add_test(tc_basic, test_unknown_ascii_encoding_ok);
11801   tcase_add_test(tc_basic, test_unknown_ascii_encoding_fail);
11802   tcase_add_test(tc_basic, test_unknown_encoding_invalid_length);
11803   tcase_add_test(tc_basic, test_unknown_encoding_invalid_topbit);
11804   tcase_add_test(tc_basic, test_unknown_encoding_invalid_surrogate);
11805   tcase_add_test(tc_basic, test_unknown_encoding_invalid_high);
11806   tcase_add_test(tc_basic, test_unknown_encoding_invalid_attr_value);
11807   tcase_add_test(tc_basic, test_ext_entity_latin1_utf16le_bom);
11808   tcase_add_test(tc_basic, test_ext_entity_latin1_utf16be_bom);
11809   tcase_add_test(tc_basic, test_ext_entity_latin1_utf16le_bom2);
11810   tcase_add_test(tc_basic, test_ext_entity_latin1_utf16be_bom2);
11811   tcase_add_test(tc_basic, test_ext_entity_utf16_be);
11812   tcase_add_test(tc_basic, test_ext_entity_utf16_le);
11813   tcase_add_test(tc_basic, test_ext_entity_utf16_unknown);
11814   tcase_add_test(tc_basic, test_ext_entity_utf8_non_bom);
11815   tcase_add_test(tc_basic, test_utf8_in_cdata_section);
11816   tcase_add_test(tc_basic, test_utf8_in_cdata_section_2);
11817   tcase_add_test(tc_basic, test_trailing_spaces_in_elements);
11818   tcase_add_test(tc_basic, test_utf16_attribute);
11819   tcase_add_test(tc_basic, test_utf16_second_attr);
11820   tcase_add_test(tc_basic, test_attr_after_solidus);
11821   tcase_add_test__ifdef_xml_dtd(tc_basic, test_utf16_pe);
11822   tcase_add_test(tc_basic, test_bad_attr_desc_keyword);
11823   tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16);
11824   tcase_add_test(tc_basic, test_bad_doctype);
11825   tcase_add_test(tc_basic, test_bad_doctype_utf16);
11826   tcase_add_test(tc_basic, test_bad_doctype_plus);
11827   tcase_add_test(tc_basic, test_bad_doctype_star);
11828   tcase_add_test(tc_basic, test_bad_doctype_query);
11829   tcase_add_test__ifdef_xml_dtd(tc_basic, test_unknown_encoding_bad_ignore);
11830   tcase_add_test(tc_basic, test_entity_in_utf16_be_attr);
11831   tcase_add_test(tc_basic, test_entity_in_utf16_le_attr);
11832   tcase_add_test__ifdef_xml_dtd(tc_basic, test_entity_public_utf16_be);
11833   tcase_add_test__ifdef_xml_dtd(tc_basic, test_entity_public_utf16_le);
11834   tcase_add_test(tc_basic, test_short_doctype);
11835   tcase_add_test(tc_basic, test_short_doctype_2);
11836   tcase_add_test(tc_basic, test_short_doctype_3);
11837   tcase_add_test(tc_basic, test_long_doctype);
11838   tcase_add_test(tc_basic, test_bad_entity);
11839   tcase_add_test(tc_basic, test_bad_entity_2);
11840   tcase_add_test(tc_basic, test_bad_entity_3);
11841   tcase_add_test(tc_basic, test_bad_entity_4);
11842   tcase_add_test(tc_basic, test_bad_notation);
11843   tcase_add_test(tc_basic, test_default_doctype_handler);
11844   tcase_add_test(tc_basic, test_empty_element_abort);
11845 
11846   suite_add_tcase(s, tc_namespace);
11847   tcase_add_checked_fixture(tc_namespace, namespace_setup, namespace_teardown);
11848   tcase_add_test(tc_namespace, test_return_ns_triplet);
11849   tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
11850   tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
11851   tcase_add_test(tc_namespace, test_start_ns_clears_start_element);
11852   tcase_add_test__ifdef_xml_dtd(tc_namespace,
11853                                 test_default_ns_from_ext_subset_and_ext_ge);
11854   tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1);
11855   tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2);
11856   tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3);
11857   tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4);
11858   tcase_add_test(tc_namespace, test_ns_unbound_prefix);
11859   tcase_add_test(tc_namespace, test_ns_default_with_empty_uri);
11860   tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes);
11861   tcase_add_test(tc_namespace, test_ns_duplicate_hashes);
11862   tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute);
11863   tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element);
11864   tcase_add_test(tc_namespace, test_ns_parser_reset);
11865   tcase_add_test(tc_namespace, test_ns_long_element);
11866   tcase_add_test(tc_namespace, test_ns_mixed_prefix_atts);
11867   tcase_add_test(tc_namespace, test_ns_extend_uri_buffer);
11868   tcase_add_test(tc_namespace, test_ns_reserved_attributes);
11869   tcase_add_test(tc_namespace, test_ns_reserved_attributes_2);
11870   tcase_add_test(tc_namespace, test_ns_extremely_long_prefix);
11871   tcase_add_test(tc_namespace, test_ns_unknown_encoding_success);
11872   tcase_add_test(tc_namespace, test_ns_double_colon);
11873   tcase_add_test(tc_namespace, test_ns_double_colon_element);
11874   tcase_add_test(tc_namespace, test_ns_bad_attr_leafname);
11875   tcase_add_test(tc_namespace, test_ns_bad_element_leafname);
11876   tcase_add_test(tc_namespace, test_ns_utf16_leafname);
11877   tcase_add_test(tc_namespace, test_ns_utf16_element_leafname);
11878   tcase_add_test(tc_namespace, test_ns_utf16_doctype);
11879   tcase_add_test(tc_namespace, test_ns_invalid_doctype);
11880   tcase_add_test(tc_namespace, test_ns_double_colon_doctype);
11881 
11882   suite_add_tcase(s, tc_misc);
11883   tcase_add_checked_fixture(tc_misc, NULL, basic_teardown);
11884   tcase_add_test(tc_misc, test_misc_alloc_create_parser);
11885   tcase_add_test(tc_misc, test_misc_alloc_create_parser_with_encoding);
11886   tcase_add_test(tc_misc, test_misc_null_parser);
11887   tcase_add_test(tc_misc, test_misc_error_string);
11888   tcase_add_test(tc_misc, test_misc_version);
11889   tcase_add_test(tc_misc, test_misc_features);
11890   tcase_add_test(tc_misc, test_misc_attribute_leak);
11891   tcase_add_test(tc_misc, test_misc_utf16le);
11892   tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_1);
11893   tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_2);
11894   tcase_add_test__ifdef_xml_dtd(
11895       tc_misc, test_misc_deny_internal_entity_closing_doctype_issue_317);
11896 
11897   suite_add_tcase(s, tc_alloc);
11898   tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown);
11899   tcase_add_test(tc_alloc, test_alloc_parse_xdecl);
11900   tcase_add_test(tc_alloc, test_alloc_parse_xdecl_2);
11901   tcase_add_test(tc_alloc, test_alloc_parse_pi);
11902   tcase_add_test(tc_alloc, test_alloc_parse_pi_2);
11903   tcase_add_test(tc_alloc, test_alloc_parse_pi_3);
11904   tcase_add_test(tc_alloc, test_alloc_parse_comment);
11905   tcase_add_test(tc_alloc, test_alloc_parse_comment_2);
11906   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_create_external_parser);
11907   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_run_external_parser);
11908   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_dtd_copy_default_atts);
11909   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_external_entity);
11910   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_ext_entity_set_encoding);
11911   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_internal_entity);
11912   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_dtd_default_handling);
11913   tcase_add_test(tc_alloc, test_alloc_explicit_encoding);
11914   tcase_add_test(tc_alloc, test_alloc_set_base);
11915   tcase_add_test(tc_alloc, test_alloc_realloc_buffer);
11916   tcase_add_test(tc_alloc, test_alloc_ext_entity_realloc_buffer);
11917   tcase_add_test(tc_alloc, test_alloc_realloc_many_attributes);
11918   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_public_entity_value);
11919   tcase_add_test__ifdef_xml_dtd(tc_alloc,
11920                                 test_alloc_realloc_subst_public_entity_value);
11921   tcase_add_test(tc_alloc, test_alloc_parse_public_doctype);
11922   tcase_add_test(tc_alloc, test_alloc_parse_public_doctype_long_name);
11923   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_set_foreign_dtd);
11924   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_attribute_enum_value);
11925   tcase_add_test__ifdef_xml_dtd(tc_alloc,
11926                                 test_alloc_realloc_attribute_enum_value);
11927   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_implied_attribute);
11928   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_default_attribute);
11929   tcase_add_test(tc_alloc, test_alloc_notation);
11930   tcase_add_test(tc_alloc, test_alloc_public_notation);
11931   tcase_add_test(tc_alloc, test_alloc_system_notation);
11932   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_nested_groups);
11933   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_nested_groups);
11934   tcase_add_test(tc_alloc, test_alloc_large_group);
11935   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_group_choice);
11936   tcase_add_test(tc_alloc, test_alloc_pi_in_epilog);
11937   tcase_add_test(tc_alloc, test_alloc_comment_in_epilog);
11938   tcase_add_test__ifdef_xml_dtd(tc_alloc,
11939                                 test_alloc_realloc_long_attribute_value);
11940   tcase_add_test(tc_alloc, test_alloc_attribute_whitespace);
11941   tcase_add_test(tc_alloc, test_alloc_attribute_predefined_entity);
11942   tcase_add_test(tc_alloc, test_alloc_long_attr_default_with_char_ref);
11943   tcase_add_test(tc_alloc, test_alloc_long_attr_value);
11944   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_nested_entities);
11945   tcase_add_test__ifdef_xml_dtd(tc_alloc,
11946                                 test_alloc_realloc_param_entity_newline);
11947   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_ce_extends_pe);
11948   tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_attributes);
11949   tcase_add_test(tc_alloc, test_alloc_long_doc_name);
11950   tcase_add_test(tc_alloc, test_alloc_long_base);
11951   tcase_add_test(tc_alloc, test_alloc_long_public_id);
11952   tcase_add_test(tc_alloc, test_alloc_long_entity_value);
11953   tcase_add_test(tc_alloc, test_alloc_long_notation);
11954 
11955   suite_add_tcase(s, tc_nsalloc);
11956   tcase_add_checked_fixture(tc_nsalloc, nsalloc_setup, nsalloc_teardown);
11957   tcase_add_test(tc_nsalloc, test_nsalloc_xmlns);
11958   tcase_add_test(tc_nsalloc, test_nsalloc_parse_buffer);
11959   tcase_add_test(tc_nsalloc, test_nsalloc_long_prefix);
11960   tcase_add_test(tc_nsalloc, test_nsalloc_long_uri);
11961   tcase_add_test(tc_nsalloc, test_nsalloc_long_attr);
11962   tcase_add_test(tc_nsalloc, test_nsalloc_long_attr_prefix);
11963   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes);
11964   tcase_add_test(tc_nsalloc, test_nsalloc_long_element);
11965   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_binding_uri);
11966   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_prefix);
11967   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_longer_prefix);
11968   tcase_add_test(tc_nsalloc, test_nsalloc_long_namespace);
11969   tcase_add_test(tc_nsalloc, test_nsalloc_less_long_namespace);
11970   tcase_add_test(tc_nsalloc, test_nsalloc_long_context);
11971   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context);
11972   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_2);
11973   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_3);
11974   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_4);
11975   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_5);
11976   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_6);
11977   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_7);
11978   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_ge_name);
11979   tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_in_dtd);
11980   tcase_add_test(tc_nsalloc, test_nsalloc_long_default_in_ext);
11981   tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
11982   tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
11983 
11984 #if defined(XML_DTD)
11985   suite_add_tcase(s, tc_accounting);
11986   tcase_add_test(tc_accounting, test_accounting_precision);
11987   tcase_add_test(tc_accounting, test_billion_laughs_attack_protection_api);
11988   tcase_add_test(tc_accounting, test_helper_unsigned_char_to_printable);
11989 #endif
11990 
11991   return s;
11992 }
11993 
11994 int
11995 main(int argc, char *argv[]) {
11996   int i, nf;
11997   int verbosity = CK_NORMAL;
11998   Suite *s = make_suite();
11999   SRunner *sr = srunner_create(s);
12000 
12001   /* run the tests for internal helper functions */
12002   testhelper_is_whitespace_normalized();
12003 
12004   for (i = 1; i < argc; ++i) {
12005     char *opt = argv[i];
12006     if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0)
12007       verbosity = CK_VERBOSE;
12008     else if (strcmp(opt, "-q") == 0 || strcmp(opt, "--quiet") == 0)
12009       verbosity = CK_SILENT;
12010     else {
12011       fprintf(stderr, "runtests: unknown option '%s'\n", opt);
12012       return 2;
12013     }
12014   }
12015   if (verbosity != CK_SILENT)
12016     printf("Expat version: %" XML_FMT_STR "\n", XML_ExpatVersion());
12017   srunner_run_all(sr, verbosity);
12018   nf = srunner_ntests_failed(sr);
12019   srunner_free(sr);
12020 
12021   return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
12022 }
12023